Spring AOP之AspectJ
1. Spring AOP实现方式 — 动态代理
Spring AOP 可以有两种风格的 aop配置,
a) 方式1:
<aop:config proxy-target-class=”true”>
<!– other beans defined here… –>
</aop:config>
使用这种方式配置,xml中使用<aop:before>等手工配置比较繁琐
b) 方式2:使用AspectJ的方式配置
<aop:aspectj-autoproxy proxy-target-class=”true”/>,支持 @AspectJ 注解风格的配置
Spring AOP部分使用JDK动态代理或者CGLIB来为目标对象创建代理。(建议优先使用JDK的动态代理)
如果被代理的目标对象实现了至少一个接口,则会使用JDK动态代理。所有该目标类型实现的接口都将被代理。
若该目标对象没有实现任何接口,则创建一个CGLIB代理。
如果你希望强制使用CGLIB代理,(例如:希望代理目标对象的所有方法,而不只是实现自接口的方法) 那也可以。
但是需要考虑以下问题:
- 无法通知(advise)Final方法,因为他们不能被覆写。
- 你需要将CGLIB 2二进制发行包放在classpath下面,与之相较JDK本身就提供了动态代理。
- 当需要CGLIB而在classpath下又没有找到CGLIB类库的话,Spring会自动提醒。
- 代理对象的构造器会被调用两次。这是很自然的结果因为在CGLIB代理模式下每一个代理对象都会 产生一个子类。
- 每一个代理实例会生成两个对象:实际代理对象和它的一个实现了通知的子类实例 而是用JDK代理时不会出现这样的行为。
通常情况下,调用代理类型的构造器两次并不是问题, 因为除了会发生指派外没有任何真正的逻辑被实现。
强制使用CGLIB代理需要将<aop:config>的proxy-target-class 属性设为true:
<aop:config proxy-target-class="true"> <!-- other beans defined here... --> </aop:config>
当使用@AspectJ自动代理时要强制使用CGLIB,请将<aop:aspectj-autoproxy> 的proxy-target-class属性设置为true:
<aop:aspectj-autoproxy proxy-target-class=”true”/>
以上两种方式都是使用动态代理的方式配置AOP的,这种方式的缺点:
JDK使用动态代理时,被代理的对象必须至少实现了一个接口
使用CGLIB创建动态代理时,因为CGLIB会在内存中自动创建一个被代理类的子类,实际上是一种继承机制,因此无法在使用final修饰的bean上应用横切关注点(final的bean无法被继承)。
与此相似,在private, static和final方法上应用横切关注点也是无法做到的。
2. 使用 AspectJ框架的 compiler/weaver 来代替Spring AOP或者作为它的补充, 使用加载时织入(Loading Time Wave)方法,完美实现AOP。
2.1 依赖
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-instrument</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${spring.version}</version> </dependency> <!-- AspectJ (required spring-aop dependency) --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.5</version> </dependency>
2.2 需要在 JVM的启动参数中配置
-javaagent:C:\Users\your_username\.m2\repository\org\springframework\spring-instrument\4.0.9.RELEASE\spring-instrument-4.0.9.RELEASE.jar
以便在加载时织入AOP代码
2.3 AspectJ AOP配置
在classpath的META-INF/aop.xml,
其中 waver中的 <include within=”foo.*”/>配置哪些类需要被织入AOP代码,
aspects 中配置切面类,需要被@Aspect注解修饰,然后根据需要在方法中配置@Before,@After,@Around等增强处理器
<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd"> <aspectj> <weaver> <!-- only weave classes in our application-specific packages --> <include within="foo.*"/> </weaver> <aspects> <!-- weave in just this aspect --> <aspect name="foo.ProfilingAspect"/> </aspects> </aspectj>
2.4 Spring配置文件:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd "> <context:component-scan base-package="foo" /> <context:annotation-config /> <!-- Scans the classpath for annotated components that will be auto-registered as Spring beans --> <context:load-time-weaver/> </beans>
参考: http://www.shouce.ren/api/spring2.5/ch06s08.html
赞 赏 微信赞赏
支付宝赞赏