多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
**[林炳文Evankaka](http://my.csdn.net/Evankaka)原创作品。转载请注明出处[http://blog.csdn.net/evankaka](http://blog.csdn.net/evankaka)** **[本文工程免费下载](http://download.csdn.net/detail/evankaka/8714913)** # **一、JAVA动态代理 ** 1.1 代理模式        代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。 按照代理的创建时期,代理类可以分为两种。 静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。 动态代理:在程序运行时,运用反射机制动态创建而成。        我们知道,通过使用代理,可以在被代理的类的方法的前后添加一些处理方法,这样就达到了类似AOP的效果。而JDK中提供的动态代理,就是实现AOP的绝好底层技术。 1.2 JDK动态代理       JDK动态代理主要涉及到java.lang.reflect包中的两个类:Proxy和InvocationHandler。InvocationHandler是一个接口,通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编制在一起。 Proxy利用InvocationHandler动态创建一个符合某一接口的实例,生成目标类的代理对象。 1.3 CGLib动态代理       还有一个叫CGLib的动态代理,CGLib全称为Code Generation Library,是一个强大的高性能,高质量的代码生成类库,可以在运行期扩展Java类与实现Java接口,CGLib封装了asm,可以再运行期动态生成新的class。和JDK动态代理相比较:JDK创建代理有一个限制,就是只能为接口创建代理实例,而对于没有通过接口定义业务方法的类,则可以通过CGLib创建动态代理 (以下代码来自Spring.3.x企业应用开发实战,其中有些地方笔者做了些增加) # 二、JDK动态代理 1、接口ForumService ~~~ package aop; public interface ForumService { public void removeTopic(int topic); public void removeForum(int forumId); } ~~~ 2、ForumServiceImpl实现 ~~~ package aop; public class ForumServiceImpl implements ForumService{ public void removeTopic(int topic){ System.out.println("模拟删除记录"+topic); try{ Thread.currentThread().sleep(20); }catch(Exception e){ throw new RuntimeException(e); } } public void removeForum(int forumId){ System.out.println("模拟删除记录"+forumId); try{ Thread.currentThread().sleep(20); }catch(Exception e){ throw new RuntimeException(e); } } } ~~~ 这里我们可以来看看上面的方法: 先测试下: ~~~ ForumServiceImpl forumServiceImpl=new ForumServiceImpl(); forumServiceImpl.removeForum(190); forumServiceImpl.removeTopic(123); ~~~ ![](https://box.kancloud.cn/2016-02-22_56caf9fdbbbfa.jpg) **接下来我们要实现在删除记录之前和之后增加一些方法** 3、要在ForumServiceImpl.java中插入的增强方法 ~~~ package aop; public class PerformanceMonitor { private static ThreadLocal<MethodPerformance> performanceRecord=new ThreadLocal<MethodPerformance>(); public static void begin(String method){ System.out.println("begin monitor.."); MethodPerformance mp=new MethodPerformance(method); performanceRecord.set(mp); } public static void end(){ System.out.println("end monitor..."); MethodPerformance mp=performanceRecord.get(); mp.printPerformance(); } } ~~~ MethodPerformance.java是真正加入的方法 ~~~ package aop; public class MethodPerformance { private long begin; private long end; private String serviceMethod; public MethodPerformance(String serviceMethod){ this.serviceMethod=serviceMethod; this.begin=System.currentTimeMillis(); } public void printPerformance(){ end=System.currentTimeMillis(); long elapse=end-begin; System.out.println(serviceMethod+"花费"+elapse+"毫秒"); } } ~~~ 4、JDK动态代理PerformanceHandler.java ~~~ package aop; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class PerformanceHandler implements InvocationHandler { private Object target; public PerformanceHandler(Object object) { this.target = object; } @Override public Object invoke(Object arg0, Method arg1, Object[] arg2) throws Throwable { PerformanceMonitor.begin(target.getClass().getName() + "." + arg1.getName()); Object obj = arg1.invoke(target, arg2); PerformanceMonitor.end(); return obj; } } ~~~ 5、使用 ~~~ ForumServiceImpl target=new ForumServiceImpl(); PerformanceHandler handler=new PerformanceHandler(target); ForumService proxy=(ForumService)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), handler); proxy.removeForum(23); proxy.removeTopic(678); System.out.println("end monitor..."); ~~~ 结果: ![](https://box.kancloud.cn/2016-02-22_56caf9fdd1b4a.jpg) # 三、CGlib动态代理 1、CglibProxy.java ~~~ package aop; import java.lang.reflect.Method; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; public class CglibProxy implements MethodInterceptor{ private Enhancer enhancer=new Enhancer(); public Object getProxy(Class clazz){ enhancer.setSuperclass(clazz); enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable { PerformanceMonitor.begin(arg0.getClass().getName() + "." + arg1.getName()); Object obj = arg3.invoke(arg0, arg2); PerformanceMonitor.end(); return obj; } } ~~~ 2、测试 ~~~ ~~~ CglibProxy proxy2=new CglibProxy(); ForumServiceImpl forumServiceImpl=(ForumServiceImpl)proxy2.getProxy(ForumServiceImpl.class); forumServiceImpl.removeForum(456); forumServiceImpl.removeTopic(987); System.out.println("end monitor..."); ~~~ ~~~ 3、结果: ![](https://box.kancloud.cn/2016-02-22_56caf9fdf3385.jpg) # **四、JDK动态代理和CGLib的比较** CGLib所创建的动态代理对象的性能比JDK所创建的代理对象性能高不少,大概10倍,但CGLib在创建代理对象时所花费的时间却比JDK动态代理多大概8倍,所以对于singleton的代理对象或者具有实例池的代理,因为无需频繁的创建新的实例,所以比较适合CGLib动态代理技术,反之则适用于JDK动态代理技术。另外,由于CGLib采用动态创建子类的方式生成代理对象,所以不能对目标类中的final,private等方法进行处理。所以,大家需要根据实际的情况选择使用什么样的代理了。同样的,Spring的AOP编程中相关的ProxyFactory代理工厂内部就是使用JDK动态代理或CGLib动态代理的,通过动态代理,将增强(advice)应用到目标类中。 **[本文工程免费下载](http://download.csdn.net/detail/evankaka/8714913)** [林炳文Evankaka](http://my.csdn.net/Evankaka)原创作品。转载请注明出处[http://blog.csdn.net/evankaka](http://blog.csdn.net/evankaka)