Spring 与 Aspectj 集成
首先,让我们从 AOP(Aspect Oriented Progarmming) 开始, AOP 是 OOP 的强有力的补充,那么关键的问题是:发现横切性的问题( Cross cutting concern ),把横切性的问题进行模块化,即抽象出类,我们把这个类叫做 Aspect( 切面 ) ,然后定义 Advice( 通知 ) 也就是在切点上执行的动作和 Pointcut( 切点 ) 即匹配的表达式,找到对应的 Pointcut ,织入通知,这也就是 AOP 的思想。那么什么是 AspectJ 的,它是一个 (AOP) 的强大工具。 Spirng 提供了对 Aspectj 的集成,好了让我们看看怎么做 AOP 的开发吧。
I . 先建立一个 Java 工程 , 拷贝相关的 jar 包,
★ SPEING-HOME/dist/spring.jar
★ SPEING-HOME/lib/jakarta-common/common-logging.jar
★ SPEING-HOME/lib/log4j/log4j-1.2.14.jar
★ SPEING-HOME/lib/aspectj/*.jar
II . 建立业务逻辑类,
UserManager
package com.aop;
public interface UserManager {
public void addUser(String name, String passwor);
public void delUser( int id);
}
UserManagerImpl
package com.aop;
public class UserManagerImpl implements UserManager {
public void addUser(String name, String password) {
System. out .println( "=========addUser==========" );
}
public void delUser( int id) {
System. out .println( "=========delUser============" );
}
}
SecurityHandler
package com.aop;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class SecurityHandler {
@Pointcut ( "execution(* add*(..))" )
private void allMethods()
@Before ( "allMethods()" )
private void checkSecurity()
System. out .println( "========checkSecurity==========" );
}
}
Client
package com.aop;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Client
public static void main(String[] args) {
BeanFactory factory = new ClassPathXmlApplicationContext( "applicationContext-common.xml" );
UserManager userManager = (UserManager)factory.getBean( "userManager" );
userManager.addUser( "name" , "password" );
}
}
ApplicationContext-common.xml
< aop:aspectj-autoproxy />
< bean id = "userManager" class = "com.aop.UserManagerImpl" />
< bean id = "securityHanler" class = "com.aop.SecurityHandler" />
好了,动手测试下吧,(注意启用 AspectJ 对 Annotation 的支持,并且将 Aspect 类和目标对象配置到 IOC 容器中)。
下面是静态配置到 .xml 文件中
SecurityHandler2
package com.aop;
public class SecurityHandler2 {
private void checkSecurity() {
System.out.println("========checkSecurity==========");
}
}
ApplicationContext-common.xml
< bean id = "userManager" class = "com.aop.UserManagerImpl" />
< bean id = "securityHandler" class = "com.aop.SecurityHandler2" />
< aop:config >
< aop:aspect id = "securityaop" ref = "securityHandler" >
< aop:pointcut id = "allMethod" expression = "execution(* com.aop.UserManager.add*(..))" />
< aop:before method = "checkSecurity" pointcut-ref = "allMethod" />
</ aop:aspect >
</ aop:config >
其他的不变。
(注意如果没有匹配的 poitcut, 那么将不生成 dynamic 代理,即使有相应的配置。)
可能大家感到不满?为什么呢,在动态代理中我们可以拿到 JoinPoint 的参数,那么在 AspectJ 中有这个功能吗?答案是肯定的,我们只要在相应的 Advice 中添加 JoinPoint 参数,从中就可以拿到你需要的参数和信息了。
private void checkSecurity(JoinPoint joinPoint)
Object[] args = joinPoint.getArgs();
for ( int i = 0; i < args. length ; i++) {
System. out .println(args[i]);
}
System. out .println(joinPoint.getSignature().getName());
System. out .println( "========checkSecurity==========" );
}Spring AOP 默认情况下用 JDK 的动态代理,那么这个类必须实现接口。如果这个类没有实现接口那么要引入 CGLIB 库才可以。
总结:
1. 如果目标对象实现了接口,默认情况下会采用 JDK 的动态代理。
2. 如果目标对象实现了接口,也可以使用 CGLIB 实现 AOP .
3. 如果目标对象没有实现接口,那么必须采用 CGLIB 库。 Spring 会在 JDK 动态代理和 CGLIB 之间转换。
如何强制使用 CGLIB 实现 AOP
☆ 引入 %SPRING-HOME%/lib/cglib/*,jar
☆ 在 spring 配置文件中加入 <aop:aspectj-autoproxy proxy-target-class=”true “/>
JDK 动态代理和 CGLIB 字节码生成的区别?
☆ JDK 动态代理只能针对实现了接口的类生成代理,而不针对类
☆ CGLIB 是针对类实现代理,主要是针对指定的类生成一个子类,覆盖其中的方法,因为是继承,所以该类和方法最好不要声明成 final
但是,在实践中我们一般还是用 JDK 的动态代理 .
















