博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
《转》java动态代理(JDK和cglib)
阅读量:7085 次
发布时间:2019-06-28

本文共 12141 字,大约阅读时间需要 40 分钟。

该文章转自:

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 student101  * 102  */103 class DynamicProxy implements InvocationHandler {104     private Object target;105 106     /**107      * 绑定委托对象并返回一个代理类108      * 109      * @param target110      * @return111      */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     @Override121     /** 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 }

 输出结果:

一条小狗!

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

转载于:https://www.cnblogs.com/wubingshenyin/p/4416096.html

你可能感兴趣的文章
swift UI专项训练40 用swift实现打电话和发短信功能
查看>>
Windows用户安全小技巧
查看>>
在vim中使用查找命令查找指定字符串
查看>>
Dynamic Linq 的Like扩展
查看>>
AIX 5L学习总结3
查看>>
关于SAP,华为,BEA收购那点事儿
查看>>
黑客攻防专题五:IPC$空连接的入侵和防御
查看>>
SQL SERVER SQLOS的任务调度
查看>>
【javascript】异步编年史,从“纯回调”到Promise
查看>>
教学思路ASP.Net之服务器控件:三、DropDownList、ListBox、CheckBoxList、RadioButtonList控件...
查看>>
puppet之用户管理
查看>>
技术分享连载(三十五)
查看>>
Quartz.net官方开发指南 第八课:SchedulerListeners
查看>>
redhat/centos学习笔记
查看>>
linux系统日志
查看>>
Oracle 11.2.0.3管理ASM实例
查看>>
【物联网中间件平台-06】RFID刷卡拍照
查看>>
【游戏开发备注之三】GameCenter登陆出现“无法识别此游戏”问题的两种解决方法...
查看>>
轻松获取海量长尾词 网站流量提升不再难
查看>>
sysbench的安装和做性能测试
查看>>