动态代理(CGLib 代理介绍)

来源:互联网 发布:油气田开发工程 知乎 编辑:程序博客网 时间:2024/06/11 03:47

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!";  }}@Testpublic 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 方法,该方法可以在被代理方法调用时进行逻辑织入。

@Testpublic 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 方法,该方法可以完全控制拦截策略,因此不存在死循环调用风险

@Testpublic 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(调用分发器-带代理引用承载功能)

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

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的创建

@Testpublic 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 实例上去 */@Testpublic 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的属性操作方式转换成数组成员的操作方式

@Testpublic 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 形式的映射表

@Testpublic 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);}@Testpublic 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的总结,更全面的介绍请看原文

0 0
原创粉丝点击