本文主要讲解jdk与cglib的区别以及在spring中的实现原理,希望你阅读本文章后能对jdk和cglib有个清晰的认知。
JDK动态代理是面向接口,在创建代理实现类时比CGLib要快,创建代理速度快。
CGLib动态代理是通过字节码技术底层生成一个继承代理类的类来实现,然后重写代理类的方法(如果被代理类被final关键字所修饰,那么抱歉会失败,如果代理类中方法被final修饰,该方法无法代理成功),但是运行速度比JDK动态代理要快。
JDK代理
public interface UserService {
void add();
}
实现类
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("執行add");
}
}
创建代理类,实现InvocationHandler接口
public class MyInvocationHandler implements InvocationHandler {
private Object object;
public MyInvocationHandler(Object object){
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("方法執行前-----");
Object result = method.invoke(object, args);
System.out.println("方法執行后-----");
return result;
}
public Object getProxy() {
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), object.getClass().getInterfaces(), this);
}
}
测试类调用
public class ProxyTest {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
MyInvocationHandler myInvocationHandler = new MyInvocationHandler(userService);
UserService proxy = (UserService) myInvocationHandler.getProxy();
proxy.add();
}
}
执行结果
方法執行前-----
執行add
方法執行后-----
cglib动态代理
实例展示
实现MethodInterceptor接口
import org.springframework.cglib.proxy.MethodInterceptor;
public class MethodInterceptorImpl implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("Before invoke");
Object result = methodProxy.invokeSuper(o, objects);
System.out.println("After invoke");
return result;
}
}
类的调用
public class CglibDemp {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(CglibDemp.class);
enhancer.setCallback(new MethodInterceptorImpl());
CglibDemp demp = (CglibDemp) enhancer.create();
demp.test();
}
public void test(){
System.out.println("CglibDeamo test()");
}
}
返回结果
Before invoke
CglibDeamo test()
After invoke
spring中
spring源码实现
本方法在AopProxyFactory接口的实现类DefaultAopProxyFactory中,是spring获取aop代理选择jdk代理还是cglib动态代理的逻辑所在。
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass()||
hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
//代理类是否为接口,代理类是否为Proxy类派生出来的
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
//jdk动态代理
return new JdkDynamicAopProxy(config);
}
//cglib动态代理
return new ObjenesisCglibAopProxy(config);
}
else {
//jdk动态代理
return new JdkDynamicAopProxy(config);
}
}
总结
- spring中jdk代理的实现在JdkDynamicAopProxy类中,它也实现了InvocationHandler,所以可以看它的invoke的实现方法。
- cglib代理,通过上面源码得知在ObjenesisCglibAopProxy类中实现,但是你进去会发现getProxy方法在它的父类CglibAopProxy中。如果你根据之前的示例留下的线索enhancer.setCallbacks方法一路追终下去会发现实现了MethodInterceptor接口的代理类都属于CglibAopProxy的内部类。
spring如何指定cglib动态代理?
代理类不是接口且不是Proxy类及其子类
在以上前提下有以下三种方式:
- proxy-target-class 属性设为true。
- 目标类没有实现接口。
- 使用激进的优化策略。
参考:《spring源码深度解析》