Spring的OverrideMethod

OverrideMethod,顾名思义,就是将原方法重写。OverrideMethod使用了CGLib动态代理。

Look-up Method 与 Replace Method

Spring的OverrideMethod分为两类:

  • Look-up Method:将原方法替换为Spring的getBean()方法
  • Replace Method:将原方法替换为任意方法

Look-up Method 是 Replace Method 的子集。

Look-up Method

<bean id="fruitPlate" class="com.xxx.overridemethod.FruitPlate">
    <lookup-method bean="apple" name="getFruit"/>
</bean>
<bean id="apple" class="com.xxx.overridemethod.Apple"></bean>
public class FruitPlate {
    public Fruit getFruit() {return null;}
}

public interface Fruit{}

public class Apple implement Fruit{}

在这个例子中,我们希望每次调用FruitPlate的getFruit方法,都返回一个新的苹果。因此,Apple是原型的,每次调用getFruit,都通过Spring的getBean方法返回一个新的Apple。

Replace Method

<bean id="fruitPlate" class="com.xxx.overridemethod.FruitPlate">
    <replace-method bean="apple" name="getFruit"/>
</bean>
<bean name="getFruit" class="com.xxx.overridemethod.FruitPlateMethodReplacer"> </bean>
public class FruitPlateMethodReplacer implements MethodReplacer {
    public Object reimplement(Object obj, Method method, Object[] args) throws Throwable {
        return new Apple();
    }
}

这个例子中,我们通过FruitPlateMethodReplacer替换getFruit,每次调用getFruit,都手动new一个新的Apple。

CGLib

介绍

CGLIB 原理:动态生成一个要代理类的子类,子类重写要代理的类的所有不是final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。它比使用java反射的JDK动态代理要快。

CGLIB 底层:使用字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。

CGLIB 缺点:对于final方法,无法进行代理。

CGLIB(Code Generation Library) 介绍与原理

https://www.runoob.com/w3cnote/cglibcode-generation-library-intro.html

使用示例

拦截器(MethodInterceptor)

public class FruitPlate {
    public Fruit getFruit(String fruitName) {return null;}
}

public interface Fruit{}

public class Apple implement Fruit{}

public class GetAppleInterceptor implements MethodInterceptor{

    /**
     * 重写方法拦截在方法前和方法后加入业务
     * Object obj为目标对象
     * Method method为目标方法
     * Object[] params 为参数,
     * MethodProxy proxy CGlib方法代理对象
     */
    @Override
    public Object intercept(Object obj, Method method, Object[] params,
            MethodProxy proxy) throws Throwable {
        if (!method.getName().equals("getFruit")) {
            throw new UnsupportedOperationException();
        }
        return new Apple();
    }
 }
public class TestFruitPlate {
    public static void main(String args[]) {
        Enhancer enhancer =new Enhancer();
        enhancer.setSuperclass(FruitPlate.class);
        enhancer.setCallback(new GetAppleInterceptor());
        FruitPlate fruitPlate =(FruitPlate)enhancer.create();

        System.out.println(fruitPlate.getFruit());
    }
}

运行上述代码,在执行fruitPlate.getFruit("apple")方法时,成功被拦截器拦截,返回Apple对象。

回调过滤器(CallbackFilter)

public class GetAppleInterceptor implements MethodInterceptor{
    @Override
    public Object intercept(Object obj, Method method, Object[] params,
            MethodProxy proxy) throws Throwable {
        if (!method.getName().equals("getFruit")) {
            throw new UnsupportedOperationException();
        }
        return new Apple();
    }
 }


public class GetBananaInterceptor implements MethodInterceptor{
    @Override
    public Object intercept(Object obj, Method method, Object[] params,
            MethodProxy proxy) throws Throwable {
        if (!method.getName().equals("getFruit")) {
            throw new UnsupportedOperationException();
        }
        return new Banana();
    }
 }
public class GetFruitTypeCallbackFilter implements CallbackFilter {

    /**
     * 过滤方法
     * 返回的值为数字,代表了Callback数组中的索引位置,要到用的Callback
     */
    @Override
    public int accept(Method method) {
        if(!method.getName().equals("getFruit")){
            return 0;
        }
        int fruitType = (int) (Math.random() * 2)
        switch(fruitType) {
            case 0:
                return 1;
            case 1:
                return 2;
        }
        return 0;
    }
 }
public class TestCglib {
    public static void main(String args[]) {
        Enhancer enhancer =new Enhancer();
        enhancer.setSuperclass(FruitPlate.class);
        CallbackFilter callbackFilter = new GetFruitTypeCallbackFilter();

        /**
         *
           (1)NoOp.INSTANCE:这个NoOp表示no operator,即什么操作也不做,代理类直接调用被代理的方法不进行拦截。
           (2)FixedValue:表示锁定方法返回值,无论被代理类的方法返回什么值,回调方法都返回固定值。
           (3)callback1:方法拦截器
         */
        Callback noopCb=NoOp.INSTANCE;
        Callback appleCallback=new GetAppleInterceptor();
        Callback bananaCallback=new GetBananaInterceptor();
        Callback[] cbarray=new Callback[]{noopCb, appleCallback, bananaCallback};

        enhancer.setCallbacks(cbarray);
        enhancer.setCallbackFilter(callbackFilter);
        FruitPlate fruitPlate =(FruitPlate)enhancer.create();

        System.out.println(fruitPlate.getFruit());
        System.out.println(fruitPlate.getFruit());
        System.out.println(fruitPlate.getFruit());
        System.out.println(fruitPlate.getFruit());
    }
}

运行上述代码,执行fruitPlate.getFruit()时,回调过滤器使用随机的方式,返回下标1或2,再根据下标调用GetAppleInterceptor或GetBananaInterceptor,返回Apple或Banana。

源码分析

Spring的Bean创建过程中,会检测BeanDefinition是否存在OverrideMethod,如果存在,则会在实例化使使用CGLib进行代理。

CGLib实例化过程

public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {
   // Don't override the class with CGLIB if no overrides.
   if (bd.getMethodOverrides().isEmpty()) {
      ...
   }
   else {
      // Must generate CGLIB subclass.
      return instantiateWithMethodInjection(bd, beanName, owner);
   }
}
private static class CglibSubclassCreator {

   private static final Class<?>[] CALLBACK_TYPES = new Class<?>[]
         {NoOp.class, LookupOverrideMethodInterceptor.class, ReplaceOverrideMethodInterceptor.class};

   private final RootBeanDefinition beanDefinition;

   private final BeanFactory owner;

   CglibSubclassCreator(RootBeanDefinition beanDefinition, BeanFactory owner) {
      this.beanDefinition = beanDefinition;
      this.owner = owner;
   }

   /**
    * Create a new instance of a dynamically generated subclass implementing the
    * required lookups.
    * @param ctor constructor to use. If this is {@code null}, use the
    * no-arg constructor (no parameterization, or Setter Injection)
    * @param args arguments to use for the constructor.
    * Ignored if the {@code ctor} parameter is {@code null}.
    * @return new instance of the dynamically generated subclass
    */
public Object instantiate(Constructor<?> ctor, Object... args) {
      Class<?> subclass = createEnhancedSubclass(this.beanDefinition);
      Object instance;
      // 省略subclass实例化为instance过程
      ...
      return instance;
   }

   /**
    * Create an enhanced subclass of the bean class for the provided bean
    * definition, using CGLIB.
    */
   // 创建CGLib子类
private Class<?> createEnhancedSubclass(RootBeanDefinition beanDefinition) {
      Enhancer enhancer = new Enhancer();
      enhancer.setSuperclass(beanDefinition.getBeanClass());
      enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
      ...
      // CallbackFilter
      enhancer.setCallbackFilter(new MethodOverrideCallbackFilter(beanDefinition));
      // 拦截器
      enhancer.setCallbackTypes(CALLBACK_TYPES);
      return enhancer.createClass();
   }
}

CallbackFilter

/**
 * CGLIB callback for filtering method interception behavior.
 */
private static class MethodOverrideCallbackFilter extends CglibIdentitySupport implements CallbackFilter {
   public MethodOverrideCallbackFilter(RootBeanDefinition beanDefinition) {
      super(beanDefinition);
   }

   @Override
   public int accept(Method method) {
      MethodOverride methodOverride = getBeanDefinition().getMethodOverrides()
              .getOverride(method);
      // 如果该方法没被覆盖,返回下标0
      if (methodOverride == null) {
         return PASSTHROUGH;
      }
      // 如果该方法被LookupOverride覆盖,返回下标1
      else if (methodOverride instanceof LookupOverride) {
         return LOOKUP_OVERRIDE;
      }
      // 如果该方法被ReplaceOverride覆盖,返回下标2
      else if (methodOverride instanceof ReplaceOverride) {
         return METHOD_REPLACER;
      }
      // 如果都不是,抛出异常
      throw new UnsupportedOperationException("Unexpected MethodOverride subclass: " +
            methodOverride.getClass().getName());
   }
}

MethodInterceptor

LookupOverrideMethodInterceptor

/**
 * CGLIB MethodInterceptor to override methods, replacing them with an
 * implementation that returns a bean looked up in the container.
 */
private static class LookupOverrideMethodInterceptor extends CglibIdentitySupport implements MethodInterceptor {

   private final BeanFactory owner;

   public LookupOverrideMethodInterceptor(RootBeanDefinition beanDefinition, BeanFactory owner) {
      super(beanDefinition);
      this.owner = owner;
   }

   @Override
   public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp) throws Throwable {
      // Cast is safe, as CallbackFilter filters are used selectively.
      // 获取BD中的lookup-method信息
      LookupOverride lo = (LookupOverride) getBeanDefinition().getMethodOverrides().getOverride(method);
      Object[] argsToUse = (args.length > 0 ? args : null);  // if no-arg, don't insist on args at all
      // 如果指定了name属性,就getBeanByName
      if (StringUtils.hasText(lo.getBeanName())) {
         return this.owner.getBean(lo.getBeanName(), argsToUse);
      }
      // 否则,getBeanByType
      else {
         return this.owner.getBean(method.getReturnType(), argsToUse);
      }
   }
}

ReplaceOverrideMethodInterceptor

/**
 * CGLIB MethodInterceptor to override methods, replacing them with a call
 * to a generic MethodReplacer.
 */
private static class ReplaceOverrideMethodInterceptor extends CglibIdentitySupport implements MethodInterceptor {

   private final BeanFactory owner;

   public ReplaceOverrideMethodInterceptor(RootBeanDefinition beanDefinition, BeanFactory owner) {
      super(beanDefinition);
      this.owner = owner;
   }

   @Override
   public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp) throws Throwable {
      // 获取BD中的replace-method信息
      ReplaceOverride ro = (ReplaceOverride) getBeanDefinition().getMethodOverrides().getOverride(method);
      // TODO could cache if a singleton for minor performance optimization
      // 获取对应的 MethodReplacer Bean对象
      MethodReplacer mr = this.owner.getBean(ro.getMethodReplacerBeanName(), MethodReplacer.class);
      // 执行reimplement方法
      return mr.reimplement(obj, method, args);
   }
}
上一篇
下一篇