《转》java动态代理(JDK和cglib)

该文章转自:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html

JAVA的动态代理 
代理模式 
代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。 
按照代理的创建时期,代理类可以分为两种。 
静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。 
动态代理:在程序运行时,运用反射机制动态创建而成。 

首先看一下静态代理: 
1、Count.java 

 1 package net.battier.dao;  2   

 3 /** 

 4  * 定义一个账户接口  5  *  6  * @author Administrator  7  *  8  */  

 9 public interface Count { 10     // 查看账户方法 

11     public void queryCount(); 12   

13     // 修改账户方法 

14     public void updateCount(); 15   

16 }  

2、CountImpl.java 

 1 package net.battier.dao.impl;  2   

 3 import net.battier.dao.Count;  4   

 5 /** 

 6  * 委托类(包含业务逻辑)  7  *  8  * @author Administrator  9  * 10  */  

11 public class CountImpl implements Count { 12   

13  @Override 14     public void queryCount() { 15         System.out.println("查看账户方法..."); 16   

17  } 18   

19  @Override 20     public void updateCount() { 21         System.out.println("修改账户方法..."); 22   

23  } 24   

25 } 26   

27 、CountProxy.java 28 package net.battier.dao.impl; 29   

30 import net.battier.dao.Count; 31   

32 /** 

33  * 这是一个代理类(增强CountImpl实现类) 34  * 35  * @author Administrator 36  * 37  */  

38 public class CountProxy implements Count { 39     private CountImpl countImpl; 40   

41     /** 

42  * 覆盖默认构造器 43  * 44  * @param countImpl 45      */  

46     public CountProxy(CountImpl countImpl) { 47         this.countImpl = countImpl; 48  } 49   

50  @Override 51     public void queryCount() { 52         System.out.println("事务处理之前"); 53         // 调用委托类的方法; 

54  countImpl.queryCount(); 55         System.out.println("事务处理之后"); 56  } 57   

58  @Override 59     public void updateCount() { 60         System.out.println("事务处理之前"); 61         // 调用委托类的方法; 

62  countImpl.updateCount(); 63         System.out.println("事务处理之后"); 64   

65  } 66   

67 }  

3、TestCount.java 

 1 package net.battier.test;  2   

 3 import net.battier.dao.impl.CountImpl;  4 import net.battier.dao.impl.CountProxy;  5   

 6 /** 

 7  *测试Count类  8  *  9  * @author Administrator 10  * 11  */  

12 public class TestCount { 13     public static void main(String[] args) { 14         CountImpl countImpl = new CountImpl(); 15         CountProxy countProxy = new CountProxy(countImpl); 16  countProxy.updateCount(); 17  countProxy.queryCount(); 18   

19  } 20 }  

 

观察代码可以发现每一个代理类只能为一个接口服务,这样一来程序开发中必然会产生过多的代理,而且,所有的代理操作除了调用的方法不一样之外,其他的操作都一样,则此时肯定是重复代码。解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成。 
再来看一下动态代理: 
JDK动态代理中包含一个类和一个接口: 
InvocationHandler接口: 
public interface InvocationHandler { 
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable; 

参数说明: 
Object proxy:指被代理的对象。 
Method method:要调用的方法 
Object[] args:方法调用时所需要的参数 

可以将InvocationHandler接口的子类想象成一个代理的最终操作类,替换掉ProxySubject。 

Proxy类: 
Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法: 
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, 
InvocationHandler h) 
                               throws IllegalArgumentException 
参数说明: 
ClassLoader loader:类加载器 
Class<?>[] interfaces:得到全部的接口 
InvocationHandler h:得到InvocationHandler接口的子类实例 

Ps:类加载器 
在Proxy类中的newProxyInstance()方法中需要一个ClassLoader类的实例,ClassLoader实际上对应的是类加载器,在Java中主要有一下三种类加载器; 
Booststrap ClassLoader:此加载器采用C++编写,一般开发中是看不到的; 
Extendsion ClassLoader:用来进行扩展类的加载,一般对应的是jre\lib\ext目录中的类; 
AppClassLoader:(默认)加载classpath指定的类,是最常使用的是一种加载器。 

动态代理 
与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。 

动态代理示例: 
1、BookFacade.java 

 

1 package net.battier.dao; 2   

3 public interface BookFacade { 4     public void addBook(); 5 }  

 

2、BookFacadeImpl.java 

 1 package net.battier.dao.impl;  2   

 3 import net.battier.dao.BookFacade;  4   

 5 public class BookFacadeImpl implements BookFacade {  6   

 7  @Override  8     public void addBook() {  9         System.out.println("增加图书方法。。。"); 10  } 11   

12 } 13   

14 、BookFacadeProxy.java 15   

16 package net.battier.proxy; 17   

18 import java.lang.reflect.InvocationHandler; 19 import java.lang.reflect.Method; 20 import java.lang.reflect.Proxy; 21   

22 /** 

23  * JDK动态代理代理类 24  * 25  * @author student 26  * 27  */  

28 public class BookFacadeProxy implements InvocationHandler { 29     private Object target; 30     /** 

31  * 绑定委托对象并返回一个代理类 32  * @param target 33  * @return 

34      */  

35     public Object bind(Object target) { 36         this.target = target; 37         //取得代理对象 

38         return Proxy.newProxyInstance(target.getClass().getClassLoader(), 39                 target.getClass().getInterfaces(), this);   //要绑定接口(这是一个缺陷,cglib弥补了这一缺陷) 

40  } 41   

42  @Override 43     /** 

44  * 调用方法 45      */  

46     public Object invoke(Object proxy, Method method, Object[] args) 47             throws Throwable { 48         Object result=null; 49         System.out.println("事物开始"); 50         //执行方法 

51         result=method.invoke(target, args); 52         System.out.println("事物结束"); 53         return result; 54  } 55   

56 }  

3、TestProxy.java 

 1 package net.battier.test;  2   

 3 import net.battier.dao.BookFacade;  4 import net.battier.dao.impl.BookFacadeImpl;  5 import net.battier.proxy.BookFacadeProxy;  6   

 7 public class TestProxy {  8   

 9     public static void main(String[] args) { 10         BookFacadeProxy proxy = new BookFacadeProxy(); 11         BookFacade bookProxy = (BookFacade) proxy.bind(new BookFacadeImpl()); 12  bookProxy.addBook(); 13  } 14   

15 }  

但是,JDK的动态代理依靠接口实现,如果有些类并没有实现接口,则不能使用JDK代理,这就要使用cglib动态代理了。 

Cglib动态代理 
JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。 
示例 
1、BookFacadeCglib.java 

1 package net.battier.dao; 2   

3 public interface BookFacade { 4     public void addBook(); 5 }  

2、BookCadeImpl1.java 

 1 package net.battier.dao.impl;  2   

 3 /** 

 4  * 这个是没有实现接口的实现类  5  *  6  * @author student  7  *  8  */  

 9 public class BookFacadeImpl1 { 10     public void addBook() { 11         System.out.println("增加图书的普通方法..."); 12  } 13 }  

3、BookFacadeProxy.java 

 1 package net.battier.proxy;  2   

 3 import java.lang.reflect.Method;  4   

 5 import net.sf.cglib.proxy.Enhancer;  6 import net.sf.cglib.proxy.MethodInterceptor;  7 import net.sf.cglib.proxy.MethodProxy;  8   

 9 /** 

10  * 使用cglib动态代理 11  * 12  * @author student 13  * 14  */  

15 public class BookFacadeCglib implements MethodInterceptor { 16     private Object target; 17   

18     /** 

19  * 创建代理对象 20  * 21  * @param target 22  * @return 

23      */  

24     public Object getInstance(Object target) { 25         this.target = target; 26         Enhancer enhancer = new Enhancer(); 27         enhancer.setSuperclass(this.target.getClass()); 28         // 回调方法 

29         enhancer.setCallback(this); 30         // 创建代理对象 

31         return enhancer.create(); 32  } 33   

34  @Override 35     // 回调方法 

36     public Object intercept(Object obj, Method method, Object[] args, 37             MethodProxy proxy) throws Throwable { 38         System.out.println("事物开始"); 39  proxy.invokeSuper(obj, args); 40         System.out.println("事物结束"); 41         return null; 42   

43   

44  } 45   

46 }  

4、TestCglib.java 

 1 package net.battier.test;  2   

 3 import net.battier.dao.impl.BookFacadeImpl1;  4 import net.battier.proxy.BookFacadeCglib;  5   

 6 public class TestCglib {  7       

 8     public static void main(String[] args) {  9         BookFacadeCglib cglib=new BookFacadeCglib(); 10         BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1()); 11  bookCglib.addBook(); 12  } 13 }  

 

以上为转载内容,下面是自己写的Test

 1 package com.xt.test;  2 

 3 import java.lang.reflect.InvocationHandler;  4 import java.lang.reflect.Method;  5 import java.lang.reflect.Proxy;  6 

 7 interface Anim {  8     public void sound();  9 

 10     public void name();  11 }  12 

 13 class Dog implements Anim {  14 

 15  @Override  16     public void sound() {  17         // TODO Auto-generated method stub

 18         System.out.println("汪汪汪!");  19  }  20 

 21  @Override  22     public void name() {  23         // TODO Auto-generated method stub

 24         System.out.println("一条小狗!");  25  }  26 

 27 }  28 

 29 class Cat implements Anim {  30 

 31  @Override  32     public void sound() {  33         // TODO Auto-generated method stub

 34         System.out.println("喵喵喵!");  35  }  36 

 37  @Override  38     public void name() {  39         // TODO Auto-generated method stub

 40         System.out.println("一只小猫!");  41  }  42 

 43 }  44 

 45 interface Car {  46     public void name();  47 

 48     public void color();  49 

 50     public void run();  51 }  52 

 53 class Bmw implements Car {  54 

 55  @Override  56     public void name() {  57         // TODO Auto-generated method stub

 58         System.out.println("一辆宝马!");  59  }  60 

 61  @Override  62     public void color() {  63         // TODO Auto-generated method stub

 64         System.out.println("黑色!");  65  }  66 

 67  @Override  68     public void run() {  69         // TODO Auto-generated method stub

 70         System.out.println("车子开动!");  71  }  72 

 73 }  74 

 75 class Wm implements Car {  76 

 77  @Override  78     public void name() {  79         // TODO Auto-generated method stub

 80         System.out.println("一辆大众!");  81  }  82 

 83  @Override  84     public void color() {  85         // TODO Auto-generated method stub

 86         System.out.println("银色!");  87  }  88 

 89  @Override  90     public void run() {  91         // TODO Auto-generated method stub

 92         System.out.println("车子开动!");  93  }  94 

 95 }  96 

 97 /**

 98  * JDK动态代理代理类  99  * 100  * @author student 101  * 102  */

103 class DynamicProxy implements InvocationHandler { 104     private Object target; 105 

106     /**

107  * 绑定委托对象并返回一个代理类 108  * 109  * @param target 110  * @return

111      */

112     public Object bind(Object target) { 113         this.target = target; 114         // 取得代理对象

115         Object o = Proxy.newProxyInstance(target.getClass().getClassLoader(), 116                 target.getClass().getInterfaces(), this); // 要绑定接口(这是一个缺陷,cglib弥补了这一缺陷)

117         return o; 118  } 119 

120  @Override 121     /** 

122  * 调用方法 123      */

124     public Object invoke(Object proxy, Method method, Object[] args) 125             throws Throwable { 126         Object result = null; 127         if (target instanceof Anim && method.getName().equals("sound")) 128             System.out.println("准备叫:"); 129         if (target instanceof Car && method.getName().equals("run")) 130             System.out.println("车子点火!"); 131         // 执行方法

132         result = method.invoke(target, args); 133         if (target instanceof Anim && method.getName().equals("sound")) 134             System.out.println("叫响了"); 135         if (target instanceof Car && method.getName().equals("run")) 136             System.out.println("车子停了!"); 137         return result; 138  } 139 

140 } 141 

142 public class DynamicProxyTest { 143     public static void main(String[] args) { 144         DynamicProxy proxy = new DynamicProxy(); 145         Anim dog = (Anim) proxy.bind(new Dog()); 146  dog.name(); 147  dog.sound(); 148         System.out.println("---------------------"); 149         Anim cat = (Anim) proxy.bind(new Cat()); 150  cat.name(); 151  cat.sound(); 152         System.out.println("---------动态的精髓来了,无需再构建代理,不同接口使用相同代理即可------------"); 153         // 动态的精髓来了,无需再构建代理,不同接口使用相同代理即可

154         Car bmw = (Car) proxy.bind(new Bmw()); 155  bmw.name(); 156  bmw.color(); 157  bmw.run(); 158         System.out.println("---------------------"); 159         Car wm = (Car) proxy.bind(new Wm()); 160  wm.name(); 161  wm.color(); 162  } 163 }

 输出结果:

一条小狗!
准备叫:
汪汪汪!
叫响了
---------------------
一只小猫!
准备叫:
喵喵喵!
叫响了
---------动态的精髓来了,无需再构建代理,不同接口使用相同代理即可------------
一辆宝马!
黑色!
车子点火!
车子开动!
车子停了!
---------------------
一辆大众!
银色!

你可能感兴趣的:(java动态代理)