JDK动态代理
spring aop 默认使用的是JDK动态代理。如果一个类实现了一个接口,则spring则会用这种方式进行代理。
首先是实现InvocationHandler接口, 重写invoke方法, 这个方法就是代理的方法。其次是Proxy类,通过这个类的newProxyInstance方法, 返回一个代理对象。生成的代理对象实现原来那个类的所有接口, 并对接口的方法进行代理 , 通过代理对象调用这些方法,底层通过反射实现, 调用我们实现的invoke方法。
优点
原生, 不需要任何依赖。
通过反射机制生成的代理类的速度比CGLib操作字节码生成的代理类的速度更快。
缺点
被代理的类必须继承一个或多个接口,否则无法代理。
无法为没有在接口中定义的方法实现代理。
代理方法时, 需要通过反射机制进行回调, 此时执行效率比较低。
CGLib动态代理
直接操作字节码, 生成类的子类,重写类的方法完成代理。
优点
被代理的类不需要实现接口,代理类可以直接继承被代理的类。
被代理的类是原来那个类的子类,所以能够被子类重写的方法都可以进行代理。
代理效率高于JDK的动态代理。
缺点
无法代理Final类。
无法对final方法, private方法进行代理。
通过字节码生成代理类,其速度要低于JDK通过反射生成代理类的速度。
例子
定义接口:
public interface Star {
void sing(String name);
void dance(String name);
}
接口实现类
public class Ll implements Star {
public final void info(){
System.out.println("info");
}
@Override
public void sing(String name) {
System.out.println(name + " "+ "sing");
}
@Override
public void dance(String name) {
System.out.println(name + " "+ "dance");
}
}
JDK动态代理:
public class StarProxy implements InvocationHandler {
//目标类
private Object object;
public void setObject(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("earn money"); //增强
method.invoke(object, args);
return proxy;
}
//生成代理类
public Object createProxyObject(){
return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), this);
}
}
cglib动态代理:
public class CglibProxy implements MethodInterceptor {
//产生一个代理类
public Object createProxyObject(Class> clazz){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("earn money");
return methodProxy.invokeSuper(o, objects);
}
}
测试:
public class JdkProxyDemo {
public static void main(String[] args) {
Star star = new Ll();
StarProxy starProxy = new StarProxy();
starProxy.setObject(star);
Object proxyObject = starProxy.createProxyObject();
Star proxyStar = (Star)proxyObject;
proxyStar.dance("aa");
}
//代理类不能直接包含被代理的对象, 而是一个InvocationHandler, InvocationHandler包含被代理的对象, 并负责分发请求给代理对象, 分发前后都可以做增强
}
public class CglibDemo {
public static void main(String[] args) {
CglibProxy cglibProxy = new CglibProxy();
Ll star = (Ll) cglibProxy.createProxyObject(Ll.class);
star.sing("bb");
star.dance("cc");
star.info();//因为info是final ,所以无法被代理
}
}