Spring @Автоматизированный сбой в случае инструментального класса Cobertura
Вопрос
Инструмент Cobertura разбивает автопогрузчики пружин в конкретном случае. Кто-нибудь знает, как это решить?
Сценарий
- Я запускаю MVN 3.0.4 с версией 2.5.1 cobertura-maven-plugin.
- Тест mvn без проблем
- mvn compile, package etc также работает без проблем.
- mvn cobertura: cobertura также работал без каких-либо проблем вплоть до добавления двух новых функций, которые ввели ряд новых классов, в том числе два новых класса com.mycompany.executor. (Пример: MyHappyExecutor и MySadExecutor были добавлены в дополнение к существующему MyExecutor)
- Исключение MyExecutor из процесса сборки cobertura, похоже, устраняет autowiring
- Проверка вывода autwiring spring подтверждает, что правильные beans становятся автообновленными.
Точка отказа
При попытке автоуверсии инструментальной версии myExecutor в myService происходит автоматическое завершение Autowiring. Это отлично работало перед добавлением MyHappyExecutor и MySadExecutor. MyHappyExecutor и MySadExecutor автоматизированы и используются исключительно в MyExecutor.
Я добавил приведенный ниже вывод исключения. Пожалуйста, не редактируйте имена классов и пакетов.
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myService': Injection of autowired dependencies failed;
nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.mycompany.executor.MyExecutor com.mycompany.service.impl.MyServiceImpl.myExecutor;
nested exception is java.lang.IllegalArgumentException: Can not set com.mycompany.executor.MyExecutor field com.mycompany.service.impl.MyServiceImpl.myExecutor to $Proxy20
Заключение
Что-то в процессе сборки Cobertura запутывает автоспуск Springs.
Обновление 1
Принуждение прокси-сервера класса CGLIB изменяет тип ошибки на ошибку "java.lang.NoClassDefFoundError". Это влияет на стандартную цель теста, а также на цель Cobertura.
<aop:config proxy-target-class="true"/>
Обновление 2
Вот результат процесса запуска пружин для 3 классов, о которых идет речь.
2012-11-01 16:21:51 INFO [main] Overriding bean definition for bean 'myExecutor': replacing [Generic bean: class [com.mycompany.executor.MyExecutor]; scope=; abstract=false; lazyInit=false; autowireMode=1; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [configuration.xml]] with [Generic bean: class [com.mycompany.executor.MyExecutor]; scope=; abstract=false; lazyInit=false; autowireMode=1; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [configuration.xml]] - (DefaultListableBeanFactory.java:623)
2012-11-01 16:21:51 INFO [main] Overriding bean definition for bean 'happyExecutor': replacing [Generic bean: class [com.mycompany.executor.HappyExecutor]; scope=; abstract=false; lazyInit=false; autowireMode=1; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [configuration.xml]] with [Generic bean: class [com.mycompany.executor.HappyExecutor]; scope=; abstract=false; lazyInit=false; autowireMode=1; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [configuration.xml]] - (DefaultListableBeanFactory.java:623)
2012-11-01 16:21:51 INFO [main] Overriding bean definition for bean 'sadExecutor': replacing [Generic bean: class [com.mycompany.executor.SadExecutor]; scope=; abstract=false; lazyInit=false; autowireMode=1; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [configuration.xml]] with [Generic bean: class [com.mycompany.executor.SadExecutor]; scope=; abstract=false; lazyInit=false; autowireMode=1; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [configuration.xml]] - (DefaultListableBeanFactory.java:623)
Ответы
Ответ 1
Еще один вариант заключается в том, чтобы исполнители реализовали интерфейс (скажем, Executor) и ввели использование интерфейса в MyService.
Spring будет знать, как создать прокси-сервер, чтобы он реализовал интерфейс.
В большинстве случаев я предпочитаю этот подход к proxyTargetClass.
Ответ 2
Для ваших тестов вам нужно установить proxyTargetClass=true
@EnableTransactionManagement(mode=AdviceMode.ASPECTJ, proxyTargetClass=true)
Если это работает для ваших тестов, но когда вы запускаете приложение, оно терпит неудачу, тогда вам нужны отдельные конфигурации для тестов и для вашего приложения. Тестовые конфигурации конфигурации proxyTargetClass=true
, а App config устанавливает proxyTargetClass=false
Для вашей ошибки NoClassDefFoundError
нам нужно увидеть stacktrace. Вероятно, вы не включили spring -aop library
Ответ 3
У нас была аналогичная проблема, касающаяся классов Aspect и private-private.
Наше исправление было довольно простым, так как мы могли просто сделать наш пакетно-закрытый класс общедоступным.
После этого и более проблем с cobertura мы перешли в JaCoCo и очень довольны результатом. По умолчанию сборка maven с cobertura настраивается следующим образом:
- Запустите тесты
- Измерить код через cobertura
- Повторите тесты и измерьте охват
Поскольку JaCoCo использует агент вместо инструментария байт-кода для измерения охвата кода, тесты выполняются только один раз, что делает способ сборки быстрее.
Смотрите эту ссылку, если вам нужна дополнительная информация о настройке JaCoCo.