前几天要在项目中增加一个新功能用来监控某些模块的运行情况,自然就想到了使用Spring的AOP来实现。之前已经有类似的AOP代码,使用的是Schema-based形式配置的,也就是在Spring的ApplicationContext.xml中加入了:
<bean id="handlerBeanNameAutoProxyCreator"
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>sampleService</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>sampleAdvice</value>
</list>
</property>
</bean>
其中sampleService和sampleAdvice都是通过:
<context:component-scan base-package="com.nokia.myapp"/>
自动引入的。
这次要加的功能需要监控很多类,如果按照这个配置,就需要在beanNames的list中增加很多bean,并且还要修改原来的sampleAdvice代码判断是否是属于sampleService,无疑增加了程序的复杂度,这不是我想要的。这时就考虑使用AspectJ的Annotation,编程迅速,不会破坏现在的代码结构,也易于以后的维护。按照Spring Reference Document中@AspectJ Support章节的例子,很快写好了代码:
package com.nokia.myapp.aop.monitor;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Aspect
public class NewAspectjAOP{
private Logger logger = LoggerFactory.getLogger("profile");
@Around("execution(* com.nokia.myapp.client..*.*(..))")
public Object serviceProfile(ProceedingJoinPoint pjp) throws Throwable {
//Do something before method execution
Object ret = null;
Throwable th = null;
try {
ret = pjp.proceed();
} catch(Throwable thr){
th = thr;
}
//Do something after method execution
if(th != null){
throw th;
}
return ret;
}
}
提交代码到测试服务器上进行测试,结果启动时就遇到了第一个问题:
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框架很熟悉的同事,终于发现了问题的原因:
由于@AspectJ声明的AOP和在Spring的配置文件中配置的AOP都监测了同一个类SampleService。于是在运行过程中,SampleService实现了CGLIB的三个接口,而根据Spring Reference Document中Proxying mechanisms:
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的代理实现,所以就造成了这个问题。
找到了问题,修复就很容易了,只需要指定ProxyFactoryBean的proxyTargetClass属性:
<bean id="handlerBeanNameAutoProxyCreator"
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator" p:proxyTargetClass="true">
分享到:
相关推荐
Spring demo to demonstrate aop using aspectj with xml based configuration.
aspectj.jar-aspectjweaver.jar-aopalliance.jar
aspectj-for-spring-developersaspectj-for-spring-developersaspectj-for-spring-developersaspectj-for-spring-developers
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
spring-aop-4.0.4.RELEASE.jar com.springsource.net.sf.cglib-2.2.0.jar com.springsource.org.aopalliance-1.0.0.jar com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar spring-aspects-4.1.2.RELEASE.jar ...
NULL 博文链接:https://wangxinchun.iteye.com/blog/2074483
aspectj-1.9.6-src.jar
包括:com.springsource.net.sf.cglib-2.2.0.jar、com.springsource.org.aopalliance-1.0.0.jar、com.springsource.org.aspectj.weaver-1.6.4.RELEASE.jar、commons-logging-1.1.1.jar、spring-aop-5.2.6.RELEASE....
aspectj-1.8.14-src.jar
When to use Spring AOP and AspectJ AOP? Expert author Ramnivas Laddad shows how to combine technologies such as Spring, Hibernate, Swing, and JDBC with AspectJ. The book fully covers the latest ...
aspectj的jar spring使用aop需要的jar 使用aop
Spring4.3.7的AOP依赖包-AspectJ
主要对Spring AOP的相关概念和简单的静态代理、动态代理以及常见的几种AOP配置方式做总结学习。主要包括:1. AOP的常见概念 2. 静态代理 3. jdk动态代理 4. Aspectj and Aspectjweaver 5. **aop-config** 6. CGLIB ...
aspectj.weaver最新的185版本
You'll master key features including annotation-based syntax, load-time weaver, annotation-based crosscutting, and Spring-AspectJ integration. Building on familiar technologies such as JDBC, ...
要用spring-aop-4.2.6.RELEASE.jar包必须依赖到的几个包
包含学习Spring AOP以及学习Spring Aspect J需要新增的jar包,需要的朋友可以下载哦!
Spring AOP的AspectJ支持jar包; 包括: com.springsource.net.sf.cglib-2.2.0.jar com.srpingsource.org.aopalliance-1.0.0.jar com.srpingsource.org.aspectj.weaver-1.68.RELEASE.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar