JDK动态代理和CGLIB动态代理

目录

 

JDK动态代理

CGLIB动态代理

为什么Spring使用CGLIB动态代理调用同类方法时不会重复增强?


JDK动态代理

基于InvocationHandler接口实现,demo如下
public class JdkProxy implements InvocationHandler {
    private Object target;


    public void setTarget(Object target) {
        this.target = target;
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("JDK代理增强...");
        Object result = method.invoke(target, args);
        return result;
    }


    public Object createProxy(){
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }


    public static void main(String[] args) {
        UserServiceImpl userService = new UserServiceImpl();
        JdkProxy proxyFactory = new JdkProxy();
        proxyFactory.setTarget(userService);
        IUserService proxy = (IUserService) proxyFactory.createProxy();
        proxy.sayHello();
    }
}

 

被代理的接口

public interface IUserService {
    void sayHello();


    void otherMethod();
}

 

被代理的默认实现,sayHello内部会调用otherMethod方法

@Component
public class UserServiceImpl implements IUserService{
    @Value("${user.name}")
    private String username;


    private Integer age;


    @Log
    @Override
    public void sayHello(){
        System.out.println("hello:"+username);
        otherMethod();
    }


    @Override
    public void otherMethod() {
        System.out.println("内部调用的其他方法");
    }


    public String getUsername() {
        return username;
    }


    public Integer getAge() {
        return age;
    }
}

 

输出结果

因为JDK动态代理基于反射实现,所以并不会重复增强
JDK代理增强...
hello:null
内部调用的其他方法


Process finished with exit code 0

 

CGLIB动态代理

CGLIB 是基于FastClass来实现的,动态生成一个新的类,继承FastClass, 向类中写入委托类实例直接调用方法的语句。 动态类为委托类方法调用语句建立索引,使用者根据方法签名(方法名+参数类型)得到索引值,再通过索引值进入相应的方法调用语句,得到调用结果。所以在方法内部调用方法时,会重新获取索引,使用代理类调用方法,所以会重复增强
public class CglibProxy implements MethodInterceptor{
    public Object createProxy(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("cglib代理增强");
        return methodProxy.invokeSuper(o, objects);
    }


    public static void main(String[] args) {
        CglibProxy proxyFactory = new CglibProxy();
        IUserService userService = (IUserService) proxyFactory.createProxy(UserServiceImpl.class);
        userService.sayHello();
    }
}

 

执行结果

cglib代理增强
hello:null
cglib代理增强
内部调用的其他方法


Process finished with exit code 0

 

为什么Spring使用CGLIB动态代理调用同类方法时不会重复增强?

因为spring使用的回调是DynamicAdvisedInterceptor,核心代码如下:如果切点命中,拦截器链非空,将不会调用methodProxy的Invoke方法,而是调用CglibMethodInvocation的proceed方法
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
   // We can skip creating a MethodInvocation: just invoke the target directly.
   // Note that the final invoker must be an InvokerInterceptor, so we know
   // it does nothing but a reflective operation on the target, and no hot
   // swapping or fancy proxying.
   Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
   retVal = methodProxy.invoke(target, argsToUse);
}
else {
   // We need to create a method invocation...
   retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}

 

proceed方法 在调用了各种增强通知之后,最终也是反射调用被代理对象,所以不会重复增强。
public Object proceed() throws Throwable {
   // We start with an index of -1 and increment early.
   if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
      return invokeJoinpoint();
   }


   Object interceptorOrInterceptionAdvice =
         this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
   if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
      // Evaluate dynamic method matcher here: static part will already have
      // been evaluated and found to match.
      InterceptorAndDynamicMethodMatcher dm =
            (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
      Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
      if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
         return dm.interceptor.invoke(this);
      }
      else {
         // Dynamic matching failed.
         // Skip this interceptor and invoke the next in the chain.
         return proceed();
      }
   }
   else {
      // It's an interceptor, so we just invoke it: The pointcut will have
      // been evaluated statically before this object was constructed.
      return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
   }
}

 

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值