动态代理(CGLib 代理介绍)
来源:互联网 发布:油气田开发工程 知乎 编辑:程序博客网 时间:2024/06/11 03:47
1. Enhancer 简介
enhancer 是`cglib`中使用最频繁的类。enhancer可以用来创建非接口级别的java代理(可以对类或方法进行动态代理
- enhancer.create(Object …) 方法可以创建父类的子类对象;
- enhancer.createClass() 方法可以创建父类的子类;
- 除了
构造器
,静态方法
和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());}
- 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的总结,更全面的介绍请看原文
- 动态代理(CGLib 代理介绍)
- cglib动态代理介绍
- cglib动态代理介绍
- cglib动态代理介绍
- cglib动态代理介绍
- cglib动态代理介绍
- cglib动态代理介绍
- CGLib动态代理介绍
- cglib动态代理介绍
- cglib动态代理介绍(一)
- cglib动态代理介绍(二)
- cglib动态代理简单介绍
- cglib动态代理介绍(二)
- <一> cglib动态代理介绍
- cglib动态代理介绍(一)
- cglib动态代理介绍(一)
- cglib动态代理介绍(一)
- cglib动态代理介绍(二)
- CentOS下zabbix监控mysql5.6版本主从
- div~float~position~我的背景去哪了~上
- 派生类的构造函数
- 正则表达式的贪婪与懒惰模式
- Linux搭建TortoiseSVN服务器安装步骤及配置
- 动态代理(CGLib 代理介绍)
- Maven - 入门
- GCD The Largest
- 解决svnserve --version输入后出现的不是内部或外部命令,也不是可运行的程序或批处理文件的问题
- 教你快速转载别人的博客
- Dojo初识
- vmstat命令动态监控系统的状态
- ARC指南1 - strong和weak指针
- 用grpc_cb代替grpc++