1. 动态代理
动态代理类需要实现InvocationHandler接口并重写其中的invoke()方法
实例如下:
实例其功能是在调用执行目标对象的方法之前调用执行checkSecurity方法
publicclass SecurityHandler implements InvocationHandler { private Object targetObject; public Object newProxy(Object targetObject) { this.targetObject = targetObject; return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { checkSecurity(); Object returnValue = null; try { returnValue = method.invoke(this.targetObject, args); } catch (Exception e) { e.printStackTrace(); thrownew RuntimeException(e); } return returnValue; } privatevoidcheckSecurity() { System.out.println("SecurityHandler.checkSecurity()"); } } |
SecurityHandler handler = new SecurityHandler(); IUserManager userManager = (IUserManager)handler.newProxy(new UserManagerImpl()); userManager.addUser("zhaoTeacher", "123"); |
2. Spring中Annotation方式进行AOP
需要在代理类中以注解的方式进行标记
实例如下:
import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; //定义Aspect @Aspect publicclass SecurityHandler { /** *定义Pointcut,Pointcut的名称就是allAddMethod, *此方法不能有返回值和参数, *该方法只是一个标识 */ @Pointcut("execution(* add*(..)) || execution(* del*(..))") privatevoid allAddMethod() {} /** *下面注解意思是在所有add方法之前执行checkSecurity()。 */ @Before("allAddMethod()") privatevoid checkSecurity() { System.out.println("SecurityHandler.checkSecurity()"); } } |
配置方法如下:
<aop:aspectj-autoproxy/><!-- 启用Annotation方式切入 --> <bean id="userManager" class="com.xasxt.spring.UserManagerImpl"/> <bean id="security" class="com.xasxt.spring.SecurityHandler"/> |
3. 配置方式切入(@AspectJ支持)
配置实例如下:
具体实现效果同上面的注解方式以及动态代理方式。
<bean id="userManager" class="com.xasxt.spring.UserManagerImpl"/> <bean id="securityHandler" class="com.xasxt.spring.SecurityHandler"/> <aop:config> <aop:aspect id="security" ref="securityHandler"> <aop:pointcut id="allAddMethod" expression="execution(* com.xasxt.spring.UserManagerImpl.add*(..))"/> <aop:before method="checkSecurity" pointcut-ref="allAddMethod"/> </aop:aspect> </aop:config> |
4. Spring对AOP的支持
I、 Spring中Advice如何接收方法的参数:
l Aspect默认情况下不用实现接口,但对于目标对象(UserManagerImpl.java),在默认情况下必须实现接口;如果没有实现接口必须引入CGLIB库
l 我们可以通过在Advice中添加一个JoinPoint参数,这个值会由spring自动传入,从JoinPoint中可以取得参数值、方法名等等。
II、 如何选择代理:
l 如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP l 如果目标对象实现了接口,也可以强制使用CGLIB实现AOP l 如果目标对象没有实现接口,则必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换 |
III、 如何强制使用CGLIB实现AOP:
Ø 添加CGLIB库,SPRING_HOME/cglib/*.jar
Ø 在spring配置文件中加入下面配置:
<aop:aspectj-autoproxy proxy-target-class="true"/>
IV、 JDK动态代理和CGLIB字节码生成的区别
l JDK动态代理只能对实现了接口的类生成代理,而不能针对未实现接口的类 l CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法;因为是继承,所以该类或方法最好不要声明成final |