1

我目前正在尝试将外部@AspectJ 方面集成到 Spring+JSF 项目中。也就是说,我的方面是在单独的项目中实现的,应该在运行时加载到主应用程序上下文中。如果我在我的应用程序上下文中声明外部方面,然后将其首先加载到我的 main.js 中,这将正常工作。

ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("app-context.xml");

但是,我希望能够动态加载未知数量的方面,以便我可以将某些方面打包到插件中,这些插件根据我的 maven pom 中的依赖项设置进行部署。

这是我的应用程序上下文:

   <?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 依赖项加载。显式定义 bean (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 冲突。

在其他地方发现,这种错误表明,我正在代理一个非法的代理,尽管我不明白这应该是什么意思。

一个相关问题的答案是,我需要在所有 bean 初始化之后执行自动代理,但这没有帮助(如我的应用程序上下文中所见)

我一直在寻找一种在主应用程序中自动检测我的方面的方法,而不必在主 app-context.xml 中静态定义它们我不需要通过 AnnotationAwareAspectJAutoProxyCreator 来执行此操作。只要我不必在一个 app-context.xml 文件中“注册”所有方面,我就很高兴。

我的替代方法是让所有插件实现一个通用接口“Pluggable”,并访问一个 PluginManager,通过它他们可以启动(),加载他们自己的应用程序上下文,以便我可以将 bean 定义放在他们的子上下文 .xml作为各自项目中的资源。我有点让它工作(至少加载了几个应用程序上下文,所以我可以将 bean 信息保存在相应的包中),但我仍然更喜欢更动态的方法。

感谢您提供任何指示,甚至可能回答我为什么会出现该异常!


编辑:

由于似乎没有人知道通过名称自动装配之间的冲突的解决方案,AnnotationAwareAspectJAutoProxyCreator我们现在在他们的项目上下文中注册我们的方面,并将所有项目上下文导入使用该方面的 Web 应用程序:

核心项目

方面:

@Aspect
public class SomeAspect { ... }

核心上下文.xml:

<bean id="someAspect" class="path.to.core.SomeAspect />         
<aop:aspectj-autoproxy proxy-target-class="true" />

网络项目

<import resource="classpath:core-context.xml"/> 

然后方面也将在 web 项目中触发。这对我们来说已经足够了。

我猜另一种动态方法是扫描类路径以查找@Aspect设置 bean 中的注释并通过 BeanFactory 注册方面。

不过,如果有人知道更多关于两者之间的冲突Autowire: by-nameAnnotationAwareAspectJAutoProxyCreator请分享。

4

0 回答 0