背景
工作也有四年了,基础的东西许久不看有些遗忘。一起来复习一下吧
JDK动态代理和CGLib的区别
JDK动态代理主要是针对类实现了某个接口,AOP则会使用JDK动态代理。它基于反射的机制实现,生成一个实现同样接口的一个代理类,然后通过重写方法的方式,实现对代码的增强。
而如果某个类没有实现接口,AOP则会使用CGLIB代理。它的底层原理是基于asm第三方框架,通过修改字节码生成成一个子类,然后重写父类的方法,实现对代码的增强。
JDK创建代理对象效率较高,执行效率较低;
CGLIB创建代理对象效率较低,执行效率高。
JDK动态代理机制是委托机制,只能对实现接口的类生成代理,通过反射动态实现接口类;
CGLIB则使用的继承机制,针对类实现代理,被代理类和代理类是继承关系,所以代理类是可以赋值给被代理类的,因为是继承机制,不能代理final修饰的类。
代码实现区别
- JDK动态代理实现方式
接口层
package com.springboot.demo.base.service;
public interface UserService {
/**
* 新增用户
* @param name
*/
void addUser(String name);
}
实现类
package com.springboot.demo.base.service;
public class UserServiceImpl implements UserService {
@Override
public void addUser(String name) {
System.out.println("yes i am add one user");
}
}
代理类
package com.springboot.demo.base.utils;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class UserProxy implements InvocationHandler {
private Object target;
public UserProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(target, args);
System.out.println("记录日志");
return result;
}
}
测试类
public static void main(String[] args) {
//jdk
UserServiceImpl impl = new UserServiceImpl();
UserProxy userProxy = new UserProxy(impl);
UserService userService = (UserService) Proxy.newProxyInstance(impl.getClass().getClassLoader(),impl.getClass().getInterfaces(),userProxy);
userService.addUser("aaaaa");
}
执行结果
- CDLib动态代理实现方式
实现类和接口类与JDK一致,这里就不重复贴了。
不一样的是CGLib还依赖一个包
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.5</version>
</dependency>
代理类
package com.springboot.demo.base.utils;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class UserCGLib implements MethodInterceptor {
private Object target;
public UserCGLib() {
}
public UserCGLib(Object target) {
this.target = target;
}
//返回一个代理对象: 是 target对象的代理对象
public Object getProxyInstance() {
//1. 创建一个工具类
Enhancer enhancer = new Enhancer();
//2. 设置父类
enhancer.setSuperclass(target.getClass());
//3. 设置回调函数
enhancer.setCallback(this);
//4. 创建子类对象,即代理对象
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("增强开始~~~");
Object result = methodProxy.invokeSuper(o, objects);
System.out.println("增强结束~~~");
return result;
}
}
测试类
public static void main(String[] args) {
//cglib
UserCGLib serviceCGlib = new UserCGLib(new UserServiceImpl());
UserServiceImpl userServic1e = (UserServiceImpl)serviceCGlib.getProxyInstance();
userServic1e.addUser("add");
System.out.println();
}
执行结果
总结
1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理
2、如果目标对象实现了接口,也可以强制使用CGLIB
3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换
如果需要强制使用CGLIB来实现AOP,需要配置spring.aop.proxy-target-class=true或@EnableAspectJAutoProxy(proxyTargetClass = true
参考
https://zhuanlan.zhihu.com/p/440452860
https://blog.csdn.net/qq_59527118/article/details/127386305