java动态代理(JDK和cglib)

来源:互联网 发布:windows10软件用不了 编辑:程序博客网 时间:2024/05/05 01:20

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.     }  

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 华为畅享7s声音小怎么办 华为畅享8手机声音小怎么办 华为畅享8plus声音小怎么办 荣耀7x锁屏密码忘记怎么办 华为荣耀7x锁屏密码忘记了怎么办 苹果耳机进水后声音变了怎么办 华为荣耀开了数据用不了怎么办 华为手机高德地图信号弱怎么办? 手机QQ浏览器看视频有广告怎么办 手机显示网络连接但不可上网怎么办 华为手机关机后开不了机怎么办 华为畅享8p相机拍照模糊怎么办 手机触屏不准怎么办荣耀青春版九 华为手机锁屏手势密码忘了怎么办 荣耀手机锁屏密码忘了怎么办 华为p20隐私空间密码忘了怎么办 安全管家隐私保护的密码忘了怎么办 华为手机自带截图键删除了怎么办 飞科电吹风吹一会就断电怎么办 住酒店时电吹风吹坏了怎么办 把话费充到停机的号码上去了怎么办 电信手机卡充值了还停机怎么办 电信手机一直没用却欠费了怎么办 苹果se开起4g信号不好怎么办 触屏华为手机充不了电怎么办 华为手机自拍出来的字反向怎么办 华为微信隐藏了怎么弄出来怎么办 酷派手机酷管家密码忘了怎么办 手机磁盘目录不具有读写权限怎么办 魅族手机像素突然变模糊了怎么办 手机忽然所有软件都没了怎么办 魅族读书下架的书怎么办 我的电信大王卡激活了没信号怎么办 三星翻盖手机忘记锁屏密码怎么办 小米2s电信版信号不好怎么办 4s微信版本过低怎么办 换了一个城市牵的电信网线怎么办 联通电话卡注销了里面的钱怎么办 红米4a上网太慢怎么办 华为光猫网线接囗接触不良怎么办? 苹果电信4g信号变3g怎么办