本文是根据《深入分析Java Web技术内幕》一书第十三章探讨
Spring Aop是什么
简单来说就是面向切面编程。Spring AOP的实现对于接口来说就是使用的JDK的动态代理来实现的,而对于类的代理使用CGLIB来实现。
JDK动态代理
JDK的动态代理,就是在程序运行的过程中,根据被代理的接口来动态生成代理类的class文件,并加载运行的过程。代理的目的是调用目标方法时可以转而执行InvocationHandler的invoke方法,实际上spring aop也是在这里做文章。这也是典型的代理模式
下面简单代码说明这个问题
- 实现自己的InvocationHandler
/** * * @author yvan * */
public class AopProxy implements InvocationHandler {
private Object realObject;
public AopProxy(Object realObject) {
super();
this.realObject = realObject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("do something before execute invoke method...");
Object invokeResult= method.invoke(realObject, args);
System.out.println("do something after execute invoke method...");
return invokeResult;
}
}
- 制定接口以及其实现类
/** * * @author yvan * */
public interface SubObject {
public String execute(String... param);
}
/** * * @author yvan * */
public class RealObject implements SubObject {
@Override
public String execute(String... param) {
for (int i = 0; i < param.length; i++) {
System.out.println(param[i]);
}
return "execute method";
}
}
- 测试动态代理
/** * * @author yvan * */
public class AppMain {
public static void main(String[] args) {
SubObject realObject = new RealObject();
AopProxy aopProxy = new AopProxy(realObject);
// 通过jdk提供的proxy生成代理
SubObject subObject = (SubObject) Proxy.newProxyInstance(aopProxy.getClass().getClassLoader(),
realObject.getClass().getInterfaces(), aopProxy);
System.out.println(subObject.getClass().getName());
System.out.println(subObject instanceof Proxy);
String result = subObject.execute("参数一","参数二");
System.out.println(result);
}
}
- 打印结果
com.sun.proxy.$Proxy0
true
do something before execute invoke method...
参数一
参数二
do something after execute invoke method...
execute method
着重说明一下:看到com.sun.proxy.$Proxy0是jdk动态生成的代理类,subObject instanceof Proxy打印为ture说明这个代理类继承了Proxy。
这里遇到一个疑问:为什么jdk动态代理必须基于接口
原因如下:
1、生成的代理类继承了Proxy,由于java是单继承,所以只能实现接口,通过接口实现
2、从代理模式的设计来说,充分利用了java的多态特性,也符合基于接口编码的规范
当然,jdk在生成代理的参数中也说明了,需要传入对应接口
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
CGLIB代理
CGLIB底层:使用字节码处理框架ASM,来转换字节码并生成新的类。
CGLIB(CODE GENERLIZE LIBRARY)代理是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的所有方法,所以该类或方法不能声明称final的。
如果目标对象没有实现接口,则默认会采用CGLIB代理;
如果目标对象实现了接口,可以强制使用CGLIB实现代理。
添加CGLIB库,并在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>