AOP之JDK动态代理和CGLib动态代理

林炳文Evankaka原创作品。转自https://blog.csdn.net/Evankaka/article/details/45195383

本文工程免费下载

一、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


   
   
  1. package aop;
  2. public interface ForumService {
  3. public void removeTopic(int topic);
  4. public void removeForum(int forumId);
  5. }
2、ForumServiceImpl实现


   
   
  1. package aop;
  2. public class ForumServiceImpl implements ForumService{
  3. public void removeTopic(int topic){
  4. System.out.println( "模拟删除记录"+topic);
  5. try{
  6. Thread.currentThread().sleep( 20);
  7. } catch(Exception e){
  8. throw new RuntimeException(e);
  9. }
  10. }
  11. public void removeForum(int forumId){
  12. System.out.println( "模拟删除记录"+forumId);
  13. try{
  14. Thread.currentThread().sleep( 20);
  15. } catch(Exception e){
  16. throw new RuntimeException(e);
  17. }
  18. }
  19. }
这里我们可以来看看上面的方法:

先测试下:


   
   
  1. ForumServiceImpl forumServiceImpl= new ForumServiceImpl();
  2. forumServiceImpl.removeForum( 190);
  3. forumServiceImpl.removeTopic( 123);

接下来我们要实现在删除记录之前和之后增加一些方法

3、要在ForumServiceImpl.java中插入的增强方法


   
   
  1. package aop;
  2. public class PerformanceMonitor {
  3. private static ThreadLocal<MethodPerformance> performanceRecord= new ThreadLocal<MethodPerformance>();
  4. public static void begin(String method){
  5. System.out.println( "begin monitor..");
  6. MethodPerformance mp= new MethodPerformance(method);
  7. performanceRecord.set(mp);
  8. }
  9. public static void end(){
  10. System.out.println( "end monitor...");
  11. MethodPerformance mp=performanceRecord.get();
  12. mp.printPerformance();
  13. }
  14. }

MethodPerformance.java是真正加入的方法


   
   
  1. package aop;
  2. public class MethodPerformance {
  3. private long begin;
  4. private long end;
  5. private String serviceMethod;
  6. public MethodPerformance(String serviceMethod){
  7. this.serviceMethod=serviceMethod;
  8. this.begin=System.currentTimeMillis();
  9. }
  10. public void printPerformance(){
  11. end=System.currentTimeMillis();
  12. long elapse=end-begin;
  13. System.out.println(serviceMethod+ "花费"+elapse+ "毫秒");
  14. }
  15. }


4、JDK动态代理PerformanceHandler.java


   
   
  1. package aop;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Method;
  4. public class PerformanceHandler implements InvocationHandler {
  5. private Object target;
  6. public PerformanceHandler(Object object) {
  7. this.target = object;
  8. }
  9. @Override
  10. public Object invoke(Object arg0, Method arg1, Object[] arg2)
  11. throws Throwable {
  12. PerformanceMonitor.begin(target.getClass().getName() + "."
  13. + arg1.getName());
  14. Object obj = arg1.invoke(target, arg2);
  15. PerformanceMonitor.end();
  16. return obj;
  17. }
  18. }

5、使用


   
   
  1. ForumServiceImpl target= new ForumServiceImpl();
  2. PerformanceHandler handler= new PerformanceHandler(target);
  3. ForumService proxy=(ForumService)Proxy.newProxyInstance(target.getClass().getClassLoader(),
  4. target.getClass().getInterfaces(), handler);
  5. proxy.removeForum( 23);
  6. proxy.removeTopic( 678);
  7. System.out.println( "end monitor...");

结果:


三、CGlib动态代理

1、CglibProxy.java


   
   
  1. package aop;
  2. import java.lang.reflect.Method;
  3. import org.springframework.cglib.proxy.Enhancer;
  4. import org.springframework.cglib.proxy.MethodInterceptor;
  5. import org.springframework.cglib.proxy.MethodProxy;
  6. public class CglibProxy implements MethodInterceptor{
  7. private Enhancer enhancer= new Enhancer();
  8. public Object getProxy(Class clazz){
  9. enhancer.setSuperclass(clazz);
  10. enhancer.setCallback( this);
  11. return enhancer.create();
  12. }
  13. @Override
  14. public Object intercept(Object arg0, Method arg1, Object[] arg2,
  15. MethodProxy arg3) throws Throwable {
  16. PerformanceMonitor.begin(arg0.getClass().getName() + "."
  17. + arg1.getName());
  18. Object obj = arg3.invoke(arg0, arg2);
  19. PerformanceMonitor.end();
  20. return obj;
  21. }
  22. }
2、测试


   
   

    
    
  1. CglibProxy proxy2= new CglibProxy();
  2. ForumServiceImpl forumServiceImpl=(ForumServiceImpl)proxy2.getProxy(ForumServiceImpl.class);
  3. forumServiceImpl.removeForum( 456);
  4. forumServiceImpl.removeTopic( 987);
  5. System.out.println( "end monitor...");
3、结果:


四、JDK动态代理和CGLib的比较

CGLib所创建的动态代理对象的性能比JDK所创建的代理对象性能高不少,大概10倍,但CGLib在创建代理对象时所花费的时间却比JDK动态代理多大概8倍,所以对于singleton的代理对象或者具有实例池的代理,因为无需频繁的创建新的实例,所以比较适合CGLib动态代理技术,反之则适用于JDK动态代理技术。另外,由于CGLib采用动态创建子类的方式生成代理对象,所以不能对目标类中的final,private等方法进行处理。所以,大家需要根据实际的情况选择使用什么样的代理了。同样的,Spring的AOP编程中相关的ProxyFactory代理工厂内部就是使用JDK动态代理或CGLib动态代理的,通过动态代理,将增强(advice)应用到目标类中。

本文工程免费下载

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值