Динамически регистрируйте внешние аспекты @AspectJ в основном весеннем проекте
В настоящее время я пытаюсь интегрировать внешние аспекты @AspectJ в проект Spring+JSF. То есть мои аспекты реализованы в отдельных проектах и должны быть загружены в основной контекст приложения во время выполнения. Это работает нормально, если я объявляю внешний аспект в контексте моего приложения, который затем загружается первым делом в основной.
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("app-context.xml");
Однако я хочу иметь возможность динамически загружать неизвестное количество Аспектов, чтобы я мог упаковать некоторые аспекты в плагины, которые развертываются в зависимости от настроек зависимостей в моем maven pom.
вот мой app-context:
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"
default-autowire="byName">
<context:annotation-config />
<context:component-scan base-package="..." />
<import resource="app-ds-jpa.xml"/>
<!-- a explicit -->
<bean id="stopWatchProviderAspect" class="....util.StopWatchProviderAspect" />
<!-- b dynamic -->
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" />
<!-- Enable the @AspectJ support -->
<aop:aspectj-autoproxy proxy-target-class="true" />
</beans>
StopWatchProvider загружается через зависимость maven. Явное определение компонента (a) будет работать нормально. Динамический подход, однако, терпит неудачу со следующим исключением:
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'defaultData': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private ....manager.CustomerManager ....util.DefaultData.customerManager; nested exception is java.lang.IllegalArgumentException: Can not set ....manager.CustomerManager field ....util.DefaultData.customerManager to $Proxy26
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:285)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1074)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:517)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:291)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:288)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:190)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:580)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:895)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:425)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
at ....App.main(App.java:190)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private ....manager.CustomerManager ....util.DefaultData.customerManager; nested exception is java.lang.IllegalArgumentException: Can not set ....manager.CustomerManager field ...e.util.DefaultData.customerManager to $Proxy26
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:502)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:84)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:282)
... 13 more
Caused by: java.lang.IllegalArgumentException: Can not set ....manager.CustomerManager field ....util.DefaultData.customerManager to $Proxy26
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:146)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:150)
at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:63)
at java.lang.reflect.Field.set(Field.java:657)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:498)
Не знаю, возможно ли это вообще. Однако я обнаружил в старом посте в комментариях, что AnnotationAwareAspectJAutoProxyCreator конфликтует с моим Autowireing byName.
Обнаружил, что где-то еще, что предполагает такая ошибка, я использую прокси-сервер, который является незаконным, хотя я не понимаю, что это должно означать.
Один из ответов на связанный с этим вопрос заключается в том, что мне нужно выполнить autoproxy после инициализации всех компонентов, но это не помогло (как видно из контекста моего приложения).
Я постоянно искал способ автоматического определения моих Аспектов в основном приложении без необходимости статически определять их в основном app-context.xml. Мне не нужно делать это через AnnotationAwareAspectJAutoProxyCreator. Пока мне не нужно "регистрировать" все аспекты в одном файле app-context.xml, я счастлив.
Мой альтернативный вариант - сделать так, чтобы все плагины реализовывали общий интерфейс "Pluggable" с доступом к PluginManager, через который они могли бы начать () редактировать, загружая собственный контекст приложения, чтобы я мог поместить определение компонента в их дочерний контекст.xml в качестве ресурса в рамках своих соответствующих проектов. Я как бы заставил это работать (по крайней мере, загрузку нескольких контекстов приложения, чтобы я мог хранить информацию о компоненте в соответствующем пакете), но я все же предпочел бы более динамичный подход.
Спасибо за любые ссылки или, возможно, даже ответы на вопрос, почему я получаю это исключение!
РЕДАКТИРОВАТЬ:
Поскольку никто, кажется, не знает решения для конфликта между autowire по имени и AnnotationAwareAspectJAutoProxyCreator
теперь мы регистрируем наши аспекты в контексте их проекта и импортируем все контексты проекта в веб-приложение, использующее этот аспект:
Основной проект:
аспект:
@Aspect
public class SomeAspect { ... }
ядро-context.xml:
<bean id="someAspect" class="path.to.core.SomeAspect />
<aop:aspectj-autoproxy proxy-target-class="true" />
Веб-проект:
<import resource="classpath:core-context.xml"/>
Тогда аспект будет срабатывать и в веб-проекте. Нам этого пока достаточно.
Я думаю, что другой динамический подход будет сканировать путь к классам для @Aspect
аннотации внутри бина установки и регистрируют аспекты через BeanFactory.
Тем не менее, если кто-то знает больше о конфликте между Autowire: by-name
а также AnnotationAwareAspectJAutoProxyCreator
Пожалуйста, поделитесь этим.