天天看點

Spring中Aspectj和Schema-based AOP混用引起的錯誤

         前幾天要在項目中增加一個新功能用來監控某些子產品的運作情況,自然就想到了使用Spring的AOP來實作。之前已經有類似的AOP代碼,使用的是Schema-based形式配置的,也就是在Spring的ApplicationContext.xml中加入了:

其中sampleService和sampleAdvice都是通過:

自動引入的。

送出代碼到測試伺服器上進行測試,結果啟動時就遇到了第一個問題:

 ERROR [org.springframework.web.servlet.DispatcherServlet] [Thread-2] Context initialization failed

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'service1' defined in file [/opt/myapp/bin/WEB-INF/classes/com/nokia/myapp/Service1.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.nokia.myapp.Service1]: Constructor threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'service2': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.nokia.myapp.Service1 com.nokia.myapp.Service2.locationService; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'service1': Requested bean is currently in creation: Is there an unresolvable circular reference?

        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:965) ~[spring-beans-3.0.5.RELEASE.jar:3.0.5.RELEASE]

        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:911) ~[spring-beans-3.0.5.RELEASE.jar:3.0.5.RELEASE]

        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:485) ~[spring-beans-3.0.5.RELEASE.jar:3.0.5.RELEASE]

        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456) ~[spring-beans-3.0.5.RELEASE.jar:3.0.5.RELEASE]

……

        根據提示檢視代碼,發現在Service2中通過@Autowired引入了Service1,而在Service1中也通過@Autowired引入了Service2。于是去掉了Service2在Service1中引用,而後在需要用的時候通過ApplicationContext.getBean(String beanName)擷取Service2。

        修正了上面的錯誤,再次測試,程式可以正常啟動,但是有些程式運作出現了奇怪的問題:每次ApplicationConext.getBeansOfType(Class class)擷取sampleService時,總是會擷取到其他的Bean,導緻程式運作異常(不過本地Eclipse中運作測試沒有問題)。使用Eclipse的Remote Debug功能連到開發伺服器上調試,發現其他類getClass()擷取的都是class com.nokia.myapp.Service2$$EnhancerByCGLIB$$ccadc5e,而SampleService卻是$Proxy119。百思不得其解。

        最後請教了對Spring架構很熟悉的同僚,終于發現了問題的原因:

Spring AOP uses either JDK dynamic proxies or CGLIB to create the proxy for a given target object. (JDK dynamic proxies are preferred whenever you have a choice).

If the target object to be proxied implements at least one interface then a JDK dynamic proxy will be used. All of the interfaces implemented by the target type will be proxied. If the target object does not implement any interfaces then a CGLIB proxy will be created.

Spring又在實作了接口的SampleService的代理類外面包了JDK的代理實作,是以就造成了這個問題。

繼續閱讀