动态代理(CGLib 代理介绍)

1. Enhancer 简介

 enhancer 是`cglib`中使用最频繁的类。enhancer可以用来创建非接口级别的java代理(可以对类或方法进行动态代理
    1. enhancer.create(Object …) 方法可以创建父类的子类对象;
    1. enhancer.createClass() 方法可以创建父类的子类;
    1. 除了 构造器静态方法final方法,父类的所有方法都可以被代理(包含父类的父类);

2. enhancer 回调器介绍

1. FixValue 回调器

FixValue 回调器需要实现一个 loadObject 方法,该方法返回的结果将作为被代理方法的一致返回结果。

/**被代理类*/
public class SampleClass {
  public String test(String input) {
    return "Hello world!";
  }
}

@Test
public void testFixedValue() throws Exception {
  Enhancer enhancer = new Enhancer();
  enhancer.setSuperclass(SampleClass.class);
  enhancer.setCallback(new FixedValue() {
    @Override
    public Object loadObject() throws Exception {
      return "Hello cglib!";
    }
  });
  SampleClass proxy = (SampleClass) enhancer.create();
  assertEquals("Hello cglib!", proxy.test(null));
}
2. InvocationHandler 调度器

InvocationHandler 回调器需要实现一个 invoke 方法,该方法可以在被代理方法调用时进行逻辑织入。

@Test
public void testInvocationHandler() throws Exception {
  Enhancer enhancer = new Enhancer();
  enhancer.setSuperclass(SampleClass.class);
  enhancer.setCallback(new InvocationHandler() {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable {
      if(method.getDeclaringClass() != Object.class && method.getReturnType() == String.class) {
        return "Hello cglib!";
      } else {
        throw new RuntimeException("Do not know what to do.");
      }
    }
  });
  SampleClass proxy = (SampleClass) enhancer.create();
  assertEquals("Hello cglib!", proxy.test(null));
  assertNotEquals("Hello cglib!", proxy.toString());
}
  1. InvocationHandler 实例重写了方法的调用逻辑。当一个实例的对象方法被外部调用时,将会调用invoke方法(包括invoke方法本身)。因此,需要注意不能主动调用 invoke 方法,调用该方法会导致无限死循环。(invoke仅仅是调用逻辑,不是拦截逻辑)
3. MethodInterceptor(方法拦截器)

MethodInterceptor 拦截器需要实现 intercept 方法,该方法可以完全控制拦截策略,因此不存在死循环调用风险

@Test
public void testMethodInterceptor() throws Exception {
  Enhancer enhancer = new Enhancer();
  enhancer.setSuperclass(SampleClass.class);
  enhancer.setCallback(new MethodInterceptor() {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
        throws Throwable {
      if(method.getDeclaringClass() != Object.class && method.getReturnType() == String.class) {
        return "Hello cglib!";
      } else {
        return proxy.invokeSuper(obj, args);
      }
    }
  });
  SampleClass proxy = (SampleClass) enhancer.create();
  assertEquals("Hello cglib!", proxy.test(null));
  assertNotEquals("Hello cglib!", proxy.toString());
  proxy.hashCode(); // Does not throw an exception or result in an endless loop.
# }
4. LazyLoader(延迟加载器)

LazyLoader 延迟加载被代理对象,调用时产生一个父类的实例。

5. Dispatcher(调用分发器)

Disptcher 可以分发被调方法到具体实例。实例改变无需引用更新,需要注意代理创建所用的构造函数必须兼容所有被代理实例。

6. ProxyRefDispatcher(调用分发器-带代理引用承载功能)

ProxyRefDispatcherDisptcher类似,但是可以承载具体被代理对象的引用。

7. NoOp(直接方法委托)

将对方法的调用直接委托到父类的实现中去


3. 代理拦截器介绍

**将方法和对应的 callback(回调器) 关联起来。代理拦截器通过 enhancer.setCallbackFilter 实现。
cglib 提供了 CallbackHelper 类用于简化过滤器的实现。**

public void testCallbackFilter() throws Exception {
  Enhancer enhancer = new Enhancer();
  CallbackHelper callbackHelper = new CallbackHelper(SampleClass.class, new Class[0]) {
    @Override
    protected Object getCallback(Method method) {
      if(method.getDeclaringClass() != Object.class && method.getReturnType() == String.class) {
        return new FixedValue() {
          @Override
          public Object loadObject() throws Exception {
            return "Hello cglib!";
          };
        }
      } else {
        return NoOp.INSTANCE; // A singleton provided by NoOp.
      }
    }
  };
  enhancer.setSuperclass(MyClass.class);
  enhancer.setCallbackFilter(callbackHelper);
  enhancer.setCallbacks(callbackHelper.getCallbacks());
  SampleClass proxy = (SampleClass) enhancer.create();
  assertEquals("Hello cglib!", proxy.test(null));
  assertNotEquals("Hello cglib!", proxy.toString());
  proxy.hashCode(); // Does not throw an exception or result in an endless loop.
}

4. cglib 代理工具类(不全)

1. ImmutableBean (不可变代理)

该代理工具可以确保被代理的对象不被改变

/**
 * bean 样例定义
 */
public class SampleBean {
  private String value;
  public String getValue() {
    return value;
  }
  public void setValue(String value) {
    this.value = value;
  }
}

/**
 * 修改 ImmutableBean 代理的对象将会抛出 IllegalStateException 异常
 */
@Test(expected = IllegalStateException.class)
public void testImmutableBean() throws Exception {
  SampleBean bean = new SampleBean();
  bean.setValue("Hello world!");
  SampleBean immutableBean = (SampleBean) ImmutableBean.create(bean);
  assertEquals("Hello world!", immutableBean.getValue());
  bean.setValue("Hello world, again!");
  assertEquals("Hello world, again!", immutableBean.getValue());
  immutableBean.setValue("Hello cglib!"); // Causes exception.
}
2. BeanGenerator(bean生成器代理)

bean生成器代理主要应用于特定属性bean的创建

@Test
public void testBeanGenerator() throws Exception {
  BeanGenerator beanGenerator = new BeanGenerator();
  beanGenerator.addProperty("value", String.class);
  Object myBean = beanGenerator.create();

  Method setter = myBean.getClass().getMethod("setValue", String.class);
  setter.invoke(myBean, "Hello cglib!");
  Method getter = myBean.getClass().getMethod("getValue");
  assertEquals("Hello cglib!", getter.invoke(myBean));
}
3. BeanCopier(bean复制器代理)

主要实现在不同类型bean之间进行属性赋值

/** 待赋值目标 */
public class OtherSampleBean {
  private String value;
  public String getValue() {
    return value;
  }
  public void setValue(String value) {
    this.value = value;
  }
}

/**
 * 将 SampleBean 实例的属性赋值到 OtherSampleBean 实例上去
 */
@Test
public void testBeanCopier() throws Exception {

  /** false 参数指示 copy 方法不使用 第三方扩展的赋值方法 */
  BeanCopier copier = BeanCopier.create(SampleBean.class, OtherSampleBean.class, false);
  SampleBean bean = new SampleBean();
  bean.setValue("Hello cglib!");
  OtherSampleBean otherBean = new OtherSampleBean();
  /** 第三个参数是自己扩展的赋值实现对象 */
  copier.copy(bean, otherBean, null);
  assertEquals("Hello cglib!", otherBean.getValue()); 
}
4. BulkBean(批处理bean代理)

将对bean的属性操作方式转换成数组成员的操作方式

@Test
public void testBulkBean() throws Exception {
  BulkBean bulkBean = BulkBean.create(SampleBean.class,
      new String[]{"getValue"},
      new String[]{"setValue"},
      new Class[]{String.class});
  SampleBean bean = new SampleBean();
  bean.setValue("Hello world!");
  assertEquals(1, bulkBean.getPropertyValues(bean).length);
  assertEquals("Hello world!", bulkBean.getPropertyValues(bean)[0]);
  bulkBean.setPropertyValues(bean, new Object[] {"Hello cglib!"});
  assertEquals("Hello cglib!", bean.getValue());
}
5. BeanMap(映射表bean代理)

将bean的属性映射成 String-Object 形式的映射表

@Test
public void testBeanGenerator() throws Exception {
  SampleBean bean = new SampleBean();
  BeanMap map = BeanMap.create(bean);
  bean.setValue("Hello cglib!");
  assertEquals("Hello cglib", map.get("value"));
}
6. KeyFactory(键工厂)

KeyFactory 会自动实现正确的 equals 和 hashCode 方法, 保证其生成的对象可以用作 map|set 的主键。需要注意的是 KeyFactory 使用时需要定义一个 单方法接口, 该接口的唯一方法名称为 newInstance 且其返回值为 Object

public interface SampleKeyFactory {
  Object newInstance(String first, int second);
}

@Test
public void testKeyFactory() throws Exception {
  SampleKeyFactory keyFactory = (SampleKeyFactory) KeyFactory.create(Key.class);
  Object key = keyFactory.newInstance("foo", 42);
  Map<Object, String> map = new HashMap<Object, String>();
  map.put(key, "Hello cglib!");
  assertEquals("Hello cglib!", map.get(keyFactory.newInstance("foo", 42)));
}

该文档是对cglib tutorial的总结,更全面的介绍请看原文

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值