《转》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 }

输出结果:

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

时间: 2025-01-05 15:52:48

《转》java动态代理(JDK和cglib)的相关文章

Java动态代理——JDK和CGlib(简单易懂)

转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6542259.html 一:代理模式(静态代理) 代理模式是常用设计模式的一种,我们在软件设计时常用的代理一般是指静态代理,也就是在代码中显式指定的代理. 静态代理由 业务实现类.业务代理类 两部分组成.业务实现类 负责实现主要的业务方法,业务代理类负责对调用的业务方法作拦截.过滤.预处理,主要是在方法中首先进行预处理动作,然后调用业务实现类的方法,还可以规定调用后的操作.我们在需要调用业务时,不是直接通过业

java动态代理(JDK和cglib)

转自:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html JAVA的动态代理 代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务. 按照代理的创建时期,

java 静态代理 JDK动态代理 Cglib动态代理

下面以一个简单的银行账户为例讲述讲述动态代理. 设计一个银行账户类,包含用户的账户余额,实现查询和更新余额功能 这个系统用了一段时间,有客户要求对账说账户余额给弄错了?因为上面没有存取款记录,最后银行不认账,客户收到了损失.银行为了避免这种现象再次发生,决定对这个系统进行修改,但是因为bankAccount太过复杂,希望在不修改bankAccount的情况下,增加日志功能. 静态代理 使用静态代理解决上面的问题. 银行要求所有模块都需要添加日志功能,这对苦逼的程序员来说真的是一个不小的工作量啊,

《转》JAVA动态代理(JDK和CGLIB)

该文章转自:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html JAVA的动态代理 代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务. 按照代理的创建

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

博文转自http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html JAVA的动态代理 代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务. 按照代理的创建时期

java 动态代理范例 (jdk ,cglib)

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

(转)Java动态代理与CGLib代理

本文通过spring aop的代理实现简述了java动态代理和cglib的区别,有助于理解java的代理模式 转载自:http://www.iteye.com/topic/182654 Java代码 <br>public class UserDAOImpl{ <br><br>    public void save() { <br>        // TODO Auto-generated method stub <br>        Sys

Java动态代理、CGLIB动态代理

开篇 Java 的代理就是客户类不再直接和委托类打交道, 而是通过一个中间层来访问, 这个中间层就是代理.为啥要这样呢, 是因为使用代理有 2 个优势: 可以隐藏委托类的实现 可以实现客户与委托类之间的解耦, 在不修改委托类代码的情况下能够做一些额外的处理 我们举个很常见的例子: 工厂会生产很多的玩具, 但是我们买玩具都是到商店买的, 而不是到工厂去买的, 工厂怎么生产我们并不关心, 我们只知道到商店可以买到自己想要的玩具,并且,如果我们需要送人的话商店可以把这些玩具使用礼品盒包装.这个工厂就是

java动态代理的实现

动态代理作为代理模式的一种扩展形式,广泛应用于框架(尤其是基于AOP的框架)的设计与开发,本文将通过实例来讲解Java动态代理的实现过程. 友情提示:本文略有难度,读者需具备代理模式相关基础知识,. 通常情况下,代理模式中的每一个代理类在编译之后都会生成一个class文件,代理类所实现的接口和所代理的方法都被固定,这种代理被称之为静态代理(Static Proxy).那么有没有一种机制能够让系统在运行时动态创建代理类?答案就是本文将要介绍的动态代理(Dynamic Proxy).动态代理是一种较