Spring AOP底层是通过动态代理来实现的,其中包括JDK动态代理和cglib动态代理。
JDK动态代理
手写JDK动态代理
public interface UserInterface {
Integer test();
}
被代理类
public class User implements UserInterface {
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private String name;
@Override
public Integer test() {
return Integer.valueOf(name);
}
}
代理类
public class JDKProxy implements InvocationHandler {
private Object target;
public JDKProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("-----before-----" + method.getName());
Object result = method.invoke(target, args);
System.out.println("-----after-----" + result);
return result;
}
}
测试类
public class ProxyTest {
public static void main(String[] args) {
User user = new User();
user.setName("123");
UserInterface proxyInstance = (UserInterface) Proxy.newProxyInstance(User.class.getClassLoader(), User.class.getInterfaces(), new JDKProxy(user));
proxyInstance.test();
}
}
输出结果为:
-----before-----test
123
-----after-----123
还可能通过匿名内部类来实现,如下
public static void main(String[] args) {
User user = new User();
user.setName("123");
UserInterface proxyInstance = (UserInterface) Proxy.newProxyInstance(user.getClass().getClassLoader(), user.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("----before----" + method.getName());
Object result = method.invoke(user, args);
System.out.println("----after----" + result);
return result;
}
});
proxyInstance.test();
}
输出结果同上:
----before----test
123
----after----123
cglib动态代理
手写cglib动态代理
被代理类
public class User {
void test() {
System.out.println("test");
}
}
代理类
public class UserCglibProxy implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("---before---" + method.getName());
Object result = methodProxy.invokeSuper(o, args);
System.out.println("---after---" + result);
return result;
}
}
测试类
public class CglibTest {
public static void main(String[] args) {
UserCglibProxy cglibProxy = new UserCglibProxy();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(User.class);
enhancer.setCallback(cglibProxy);
User userTest = (User) enhancer.create();
userTest.test();
}
}
输出结果为:
---before---test
test
---after---null
JDK动态代理和cglib动态代理的区别
写法不同
根据以上代码,可以看出:
JDK动态代理需要实现InvocationHandler接口重写invoke方法。
cglib动态代理需要实现MethodInterceptor接口重写intercept方法,并通过Enhancer设置被代理类与代理类。
实现原理不同
JDK动态代理是利用拦截器(拦截器必须实现InvocationHandler)加上反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvocationHandler来实现的,所以Jdk动态代理必须是基于接口进行动态代理,并且成生的动态代理类实现了该接口。
cglib动态代理是利用ASM技术,加载代理类class文件并修改字节码生成子类来实现的,所以无法动态代理final修饰的方法。
效率不同
随着JDK版本升级,JDK动态代理一直在优化。在JDK1.6之前JDK动态代理效率低于cglib动态代理。JDK在1.6和1.7版本JDK动态代理效率高于cglib动态代理,只有当进行大量调用的时候,才会比cglib动态代理效率低一点。JDK1.8及之后JDK动态代理效率高于cglib动态代理。
JDK自带
JDK动态代理功能是JDK自带的,不需要任何依赖。
cglib动态代理功能不是JDK自带的需要引用相关依赖。
SpringAop用哪个?
默认用的是JDK动态代理,当未实现接口时用cglib动态代理。