代理模式 & Java原生动态代理技术 & CGLib动态代理技术

第一部分、代理模式 
  代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。(其实就是在代理类中关联一个委托类的实例,然后在代理类中进行包装)。 UML图如下:

第二部分、在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原生的动态代理:

  【原理与区别】其实本质上的原理是跟静态代理一样的,就是为了生成一个代理类,这个代理实现了委托类的接口。

  区别:只不过静态代理是在编译时生成代理类的,而在动态代理是在运行时生成的代理类的。

  原理:JDK动态代理技术中,使用了Jdk的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过这个类和接口,可以生成JDK动态代理类或动态代理对象。

  结果:生成一个动态的代理类对象,这个代理类同样实现了委托类的(比如proxy),在这个proxy中有一个变量(比如
h)引用了InnovativeHandler的实现类的对象,在代理类proxy各个方法中使用变量 h
调用了 InnovativeHandler的实现类中的重写的invoke()方法。然后在invoke()方法中,调用委托类中的相应方法。如下图:

具体如下】   
  首先详细介绍使用到的一个关键类和一个接口。
  1、Proxy提供了用于创建动态代理类和代理对象的静态方法,它也是所有动态代理类的父类,如果在程序中为一个或多个接口动态的生成实现类,就可以使用Proxy来创建动态代理类,如果需要为一个或多个接口动态的创建实例,也可以使用Proxy来创建动态代理实例


1 public static Object newProxyInstance(ClassLoader loader,
2 Class<?>[] interfaces,
3 InvocationHandler h)
4 throws IllegalArgumentException

  Proxy提供了如下两个方法,来创建动态代理类和动态代理实例。 

  getProxyClass(ClassLoader
loader, Class<?>... interfaces)

:创建一个动态代理类所对应的Class对象,该代理类将实现interfaces所指定的多个接口,第一个ClassLoader参数指定生成动态代理类的类加载器。 
  newProxyInstance(ClassLoader
loader, Class<?>[] interfaces, InvocationHandler h)
直接创建一个动态代理对象,该代理对象的实现类,实现了interfaces指定的系列接口,执行代理对象的每个方法都会被替换执行InvocationHandler对象的invoke方法。 
  实际上,即使采用第一个方法获取了一个动态代理类之后,当程序需要通过该代理类,来创建对象时一样,需要传入一个InvocationHandler对象,也就是说,系统生成的每个代理对象都有一个与之关联的的InvocationHandler对象。

  2、InvocationHandler接口:在调用代理类中任何方法时都会调用这个接口实现类的invoke()方法,这样就实现只需写一个invoke方法就使得所有方法都实现了代理。


1 public interface InvocationHandler{
2 public Object invoke(Object proxy,Method method,Object[] args)throws Throwable
3 }

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

【示例】

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


package net.battier.test;

import net.battier.dao.BookFacade;
import net.battier.dao.impl.BookFacadeImpl;
import net.battier.proxy.BookFacadeProxy;

public class TestProxy {

public static void main(String[] args) {
BookFacadeProxy proxy = new BookFacadeProxy();
BookFacade bookProxy = (BookFacade) proxy.bind(new BookFacadeImpl());
bookProxy.addBook();
}

}

  来看一下这个继承了Proxy的$Proxy0的源代码(转自其他地方,不是本文演示的程序所产生的代理类,主要为了加深一点理解,就是:动态代理最终其实也是生成了代理类):

 1 public final class $Proxy0 extends Proxy implements Subject {
2 private static Method m1;
3 private static Method m0;
4 private static Method m3;
5 private static Method m2;
6
7 static {
8 try {
9 m1 = Class.forName("java.lang.Object").getMethod("equals",
10 new Class[] { Class.forName("java.lang.Object") });
11
12 m0 = Class.forName("java.lang.Object").getMethod("hashCode",
13 new Class[0]);
14
15 m3 = Class.forName("***.RealSubject").getMethod("request",
16 new Class[0]);
17
18 m2 = Class.forName("java.lang.Object").getMethod("toString",
19 new Class[0]);
20
21 } catch (NoSuchMethodException nosuchmethodexception) {
22 throw new NoSuchMethodError(nosuchmethodexception.getMessage());
23 } catch (ClassNotFoundException classnotfoundexception) {
24 throw new NoClassDefFoundError(classnotfoundexception.getMessage());
25 }
26 } //static
27
28 public $Proxy0(InvocationHandler invocationhandler) {
29 super(invocationhandler);
30 }
31
32 @Override
33 public final boolean equals(Object obj) {
34 try {
35 return ((Boolean) super.h.invoke(this, m1, new Object[] { obj })) .booleanValue();
36 } catch (Throwable throwable) {
37 throw new UndeclaredThrowableException(throwable);
38 }
39 }
40
41 @Override
42 public final int hashCode() {
43 try {
44 return ((Integer) super.h.invoke(this, m0, null)).intValue();
45 } catch (Throwable throwable) {
46 throw new UndeclaredThrowableException(throwable);
47 }
48 }
49
50 public final void request() {
51 try {
52 super.h.invoke(this, m3, null);
53 return;
54 } catch (Error e) {
55 } catch (Throwable throwable) {
56 throw new UndeclaredThrowableException(throwable);
57 }
58 }
59
60 @Override
61 public final String toString() {
62 try {
63 return (String) super.h.invoke(this, m2, null);
64 } catch (Throwable throwable) {
65 throw new UndeclaredThrowableException(throwable);
66 }
67 }
68 }

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

第三部分、CGLib动态代理

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

  【示例】 

1、BookFacadeCglib.java

package net.battier.dao;

public interface BookFacade {
public void addBook();
}

2、BookCadeImpl1.java

package net.battier.dao.impl;

/**
* 这个是没有实现接口的实现类
*
* @author student
*
*/
public class BookFacadeImpl1 {
public void addBook() {
System.out.println("增加图书的普通方法...");
}
}

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 }

代理模式 & Java原生动态代理技术 & CGLib动态代理技术,布布扣,bubuko.com

时间: 2024-10-27 10:12:26

代理模式 & Java原生动态代理技术 & CGLib动态代理技术的相关文章

深入探索spring技术内幕(六): JDK动态代理和cglib生成代理

[ JDK生成代理 ] JDK中给我们提供了一个Proxy类可以动态的给我们生成代理. 假定我们要做一个权限管理系统, 需要控制用户对某一个方法的访问. 如果user为null, 那么不让用户访问save方法. ① 接口类: PersonService public interface PersonService { public void save(); } ② 实现类: PersonServiceImpl public class PersonServiceImpl implements P

jdk动态代理和cglib动态代理底层实现原理详细解析(cglib动态代理篇)

代理模式是一种很常见的模式,关于底层原理网上看到很多的有关的讲解,但看了一些都觉得比较粗略,很多时候把底层代码copy下来也不大讲解,感觉不如自己详细的写上一篇.本文将以非常详细的说明来分析cglib动态代理底层的实现原理,篇幅较长,但是每个核心方法代码中每步都有说明.还请耐心阅读 1. 举例 使用cglib代理需要引入两个包,maven的话包引入如下 <!-- https://mvnrepository.com/artifact/cglib/cglib --> <dependency&

关于JDK动态代理和CGLIB动态代理

1. 代理模式 一句话总结:为其他对象提供一种代理以控制对这个对象的访问.千篇一律的介绍:代理模式是常用的java设计模式,他的特征是代理类与委托类(或目标类)有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务. 按照代理的创建时期,代理类可以分为两种. 静态代理:由程序员创建或特定工具

设计模式之第16章-代理模式(Java实现)

设计模式之第16章-代理模式(Java实现) “现在朋友圈真是太让人蛋疼了啊.”“怎么说?”“一堆代理,各种卖东西的,看着好烦人.”“哎,删了呗.”“都是朋友,哪里好意思删啊.”“这倒也是...哎,迫于生计,没办法咯.还好我不玩.”“对了,你不就是代理的鼻祖么,身为代理模式,你作何感想.”“以代理之道还治代理之身啊.” 代理模式之自我介绍 最近出场率超级高,哦不,一直以来出场率都挺高的说的大名鼎鼎的模式,就是我-代理模式是也.有关我的定义如下:Provide a surrogate or pla

代理模式深入(一)——静态到动态

故事 周末放假,小孙睡到12点才告别周公醒来,顿时饥肠辘辘.舍长小王正准备去食堂买饭,作为一个好舍长小王主动要帮小孙带饭.小孙点了米饭.宫保鸡丁.芬达.小孙起床洗漱,然后静待舍长.小孙心理寻思道舍长果然是好舍长啊.下面我们先把这个故事抽象一下,画作类图.这个类图即代理模式. 代理模式 定义:为其他对象提供一种代理以控制对这个对象的访问.怎么理解这句话呢?从生活的角度来说就是:用一个对象A代替另一个对象B来处理本来应该由对象B完成的事情,例如上面买饭的例子,又如通过黄牛买票等等.从代码的角度来说则

spring aop原理 JDK动态代理和CGLIB动态代理

Spring的两大特性是IOC和AOPIOC负责将对象动态的注入到容器,从而达到一种需要谁就注入谁,什么时候需要就什么时候注入的效果.理解spring的ioc也很重要.但是今天主要来和大家讲讲aop.AOP 广泛应用于处理一些具有横切性质的系统级服务,AOP 的出现是对 OOP 的良好补充,用于处理系统中分布于各个模块的横切关注点,比如事务管理.日志.缓存等等. AOP实现的关键在于AOP框架自动创建的AOP代理.AOP代理主要分为静态代理和动态代理, 静态代理的代表为AspectJ:动态代理则

大话设计模式_代理模式(Java代码)

代理模式:为其他对象提供一种代理以控制对这个对象的访问 简单描述:1个父类A(或者接口),1个具体执行动作的子类,1个代理类,代理类持有具体子类的引用,在方法中调用具体子类的对象方法.客户端只与代理类交互 大话设计模式中的截图: 例子代码: Subject类: 1 package com.longsheng.proxy; 2 3 public interface IGiveGifts { 4 5 public void giveDolls(); 6 7 public void giveFlowe

java动态代理和cglib动态代理

动态代理应用广泛,Spring,Struts等框架很多功能是通过动态代理,或者进一步封装来实现的. 常见的动态代理模式实现有Java API提供的动态代理和第三方开源类库CGLIB动态代理. Java API提供的动态代理是基于类反射实现的,用到的类有: java.lang.reflect.InvocationHandler; java.lang.reflect.Method; java.lang.reflect.Proxy; 其实现是通过Proxy类的newProxyInstance()方法产

[z]Java代理(jdk静态代理、动态代理和cglib动态代理)

一.代理是Java常用的设计模式,代理类通过调用被代理类的相关方法,并对相关方法进行增强.加入一些非业务性代码,比如事务.日志.报警发邮件等操作. 二.jdk静态代理 1.业务接口 1 2 3 4 5 6 7 8 9 10 11 12 13 /**  * 业务接口  * @author pc  *  */ public interface UserService {          // 增加一个用户     public void addUser();     // 编辑账户     pub