CGlib动态代理

原文地址:https://my.oschina.net/huangyong/blog/159788
做者:黄勇
黄勇,从事近十年的 JavaEE 应用开发工做,曾任阿里巴巴公司系统架构师,现任特赞CTO。对分布式服务架构与大数据技术有深刻研究,具备丰富的 B/S 架构开发经验与项目实战经验,擅长敏捷开发模式。国内开源软件推进者之一,Smart Framework 开源框架创始人。热爱技术交流,乐于分享本身的工做经验。目前著有《架构探险——从零开始写Java Web框架》和《架构探险-轻量级微服务架构.上册》两本书,下半年即将出版《架构探险-轻量级微服务架构.下册》。java

一. 点睛

在前面的文章:jdk的动态代理,介绍了JDK动态代理,用了这个DynamicProxy之后,以为它仍是很是好的,好的地方是,接口变了,这个动态代理类不用作改动。而静态代理就不同了,接口变了,实现类还须要动,代理类也须要动。可是JDK动态代理也并非”万灵丹”,也有局限性,它也有搞不定的时候,好比要代理一个没有任何接口的类,它就没有用武之地了。架构

那么,可否代理没有接口的类呢?答案是确定的,那就是CGlib这个类库。虽然它看起来不太起眼,可是SpringHibernate这样高端的开源框架都用到了它。它是一个在运行期间动态生成字节码的工具,也就是动态生成代理类了。提及来很高深,实际用起来一点也不难,下面再写一个CGlibProxy框架

二. 示例

我使用的maven工程进行构建,先引入依赖:maven

<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.1</version> </dependency>

编写CGlibProxy 分布式

package org.light4j.proxy.dynamicProxy; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class CGLibProxy implements MethodInterceptor { @SuppressWarnings("unchecked") public <T> T getProxy(Class<T> cls){ return (T) Enhancer.create(cls, this); } @Override public Object intercept(Object obj, Method method, Object[] arg, MethodProxy proxy) throws Throwable { before(); Object result = proxy.invokeSuper(obj, arg); after(); return result; } private void before() { System.out.println("Before..."); } private void after() { System.out.println("After..."); } }

须要实现CGLib给咱们提供的MethodInterceptor接口,并填充intercept方法。方法中最后一个MethodProxy类型的参数proxy值得注意,CGLib给咱们提供的是方法级别的代理,也能够理解为对方法的拦截(这不就是传说中的”方法拦截器”吗?)。这个功能对于咱们来讲,如同雪中送炭。咱们直接调用proxyinvokeSuper方法,将被代理的对象obj以及方法参数args传入其中便可。ide

DynamicProxy相似,在CGLibProxy中也添加一个泛型的getProxy方法,便于咱们能够快速地获取自动生成的代理对象。下面用一个main方法来描述:微服务

package org.light4j.proxy; import org.light4j.proxy.dynamicProxy.CGLibProxy; import org.light4j.proxy.impl.HelloImpl; public class Main { public static void main(String[] args) { CGLibProxy cgLibProxy = new CGLibProxy(); Hello helloProxy = cgLibProxy.getProxy(HelloImpl.class); helloProxy.say("longjiazuo"); } }

仍然经过两行代码就能够返回代理对象,与JDK动态代理不一样的是,这里不须要任何的接口信息,对谁均可以生成动态代理对象(无论它是”矮穷挫”,仍是”高富帅”)。工具

因为我一贯都追求完美,用两行代码返回代理对象仍是有些多余的,不想老是去new这个CGLibProxy对象,最好new一次,之后随时拿随时用,因而想到了”单例模式”:大数据

package org.light4j.proxy.dynamicProxy; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class CGLibProxy implements MethodInterceptor { private static CGLibProxy instance = new CGLibProxy(); private CGLibProxy(){ } public static CGLibProxy getInstance(){ return instance; } @SuppressWarnings("unchecked") public <T> T getProxy(Class<T> cls){ return (T) Enhancer.create(cls, this); } @Override public Object intercept(Object obj, Method method, Object[] arg, MethodProxy proxy) throws Throwable { before(); Object result = proxy.invokeSuper(obj, arg); after(); return result; } private void before() { System.out.println("Before..."); } private void after() { System.out.println("After..."); } }

加上了以上几行代码就解决问题了,须要说明的是,这里有一个private的构造方法,就是为了限制外界不能再去new它了,换句话说,这个类被”阉割”了。this

下面用一个main方法来证实个人简单主义思想:

package org.light4j.proxy; import org.light4j.proxy.dynamicProxy.CGLibProxy; import org.light4j.proxy.impl.HelloImpl; public class Main { public static void main(String[] args) { Hello helloProxy = CGLibProxy.getInstance().getProxy(HelloImpl.class); helloProxy.say("longjiazuo"); } }

没错,只需一行代码就能够获取代理对象了!
到此,经过三篇文章的分析,前后介绍了无代理,静态代理,JDK动态代理,CGLib动态代理,其实代理的世界远不止这么小,还有不少实际的应用场景。

摘自 http://blog.longjiazuo.com/archives/1851

相关文章
相关标签/搜索