代理模式,拿下!!!

开发 前端
代理模式是给一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗来讲,代理模式就是我们所熟知的中介。

[[422489]]

本文转载自微信公众号「小郎码知答」,作者simon郎。转载本文请联系小郎码知答公众号。

代理模式是给一个对象提供一个代理对象,并由代理对象控制对原对象的引用。

通俗来讲,代理模式就是我们所熟知的中介。

以我们熟知的商品代购为例:

商品代购

假如我们需要买一个物品,我们可以直接去工厂里购买;也可以找代购。

如果直接去工厂购买,我们在购买前需要对自己要买的物品做一些调研,然后去工厂直接去提货,这样什么事情都需要自己亲力亲为。

如果我们通过代购购买,我们只需要告诉代购我们需要什么,剩下的事情代购会帮我们处理(调研、拿货),最终给我们需要的相应的物品。

因此,代理模式的目标如下:

(1)通过引用代理对象的方式来间接访问目标对象,防止直接访问目标对象给系统带来不必要的复杂性。

(2)通过代理对象对原有的业务进行增强。

通常情况下,按照代理的创建时期,一般可以分为两种:

  • 静态代理

静态代理是由程序员或者特定的工具自动生成的源代码,再对其编译,在程序运行之前,代理类编译的生成的.class文件就已经存在了

  • 动态代理

动态代理是在程序运行时,通过反射机制动态创建而成。

1、静态代理模式

静态代理中的代理类和委托类的关系在运行前就确定了,如图所示:

静态代理

特别注意几个概念:

  • 抽象对象

抽象对象声明了真实对象和代理对象的公共接口。

  • 真实对象

代理对象所代表的真实对象,最终被引用的对象。

  • 代理对象

包含真实对象进而操作真实对象,相当于访问者与真实对象直接的中介。

下面,我们来举个例子:

(1)创建服务类接口

  1. public interface BuyCar { 
  2.     void buycar(); 

(2)服务实现类

  1. public class BuyCarImpl implements BuyCar{ 
  2.     public void buycar() { 
  3.         System.out.println("买一辆奥迪"); 
  4.     } 

(3)创建代理类

  1. public class BuyCarProxy implements BuyCar{ 
  2.      
  3.     private BuyCar buyCar; 
  4.  
  5.     public BuyCarProxy(BuyCar buyCar){ 
  6.         this.buyCar = buyCar; 
  7.     } 
  8.     public void buycar() { 
  9.         System.out.println("买车前的调研......"); 
  10.         buyCar.buycar(); 
  11.         System.out.println("买车后的保养......"); 
  12.  
  13.  
  14.     } 

(4)编写测试类

  1. public class ProxyTest { 
  2.     public static void main(String[] args) { 
  3.         BuyCarImpl buyCar = new BuyCarImpl(); 
  4.         BuyCarProxy buyCarProxy = new BuyCarProxy(buyCar); 
  5.         buyCarProxy.buycar(); 
  6.     } 

优点:静态代理在不修改目标对象的前提下,可以通过代理对象对目标对象进行扩展。

代理类可以使得客户端不需要知道具体的实现类是什么,怎么做的,客户端只需知道代理即可(解耦合)

缺点:代理类和具体的实现类实现了相同的接口,代理类通过实现类实现了相同的方法。这样就出现了大量的代码重复。如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。

代理对象只服务于一种类型的对象,如果要服务多类型的对象。势必要为每一种对象都进行代理,静态代理在程序规模稍大时就无法胜任了。

2、动态代理模式

2.1 JDK自带

事实上,单一的代理是不存的,一个代理可以同时身兼数职。既可以代购车,也可以代购房。

在动态代理中我们不再需要手动的创建代理类,我们只需要一个动态处理器就可以了,而真正的代理对象由JDK运行时动态的创建。

(1)创建服务类接口

  1. //买车接口 
  2. public interface BuyCar { 
  3.     void buycar(); 
  4. //买房接口 
  5. public interface BuyHouse { 
  6.     void buyHouse(); 

(2)服务实现类

  1. //买车接口的实现类 
  2. public class BuyCarImpl implements BuyCar { 
  3.     public void buycar() { 
  4.         System.out.println("买一辆奥迪"); 
  5.     } 
  6. //买房接口的实现类 
  7. public class BuyHouseImpl implements BuyHouse{ 
  8.     public void buyHouse() { 
  9.         System.out.println("买一栋大别墅"); 
  10.     } 

(3)动态代理类

  1. //通过实现 InvocationHandler 接口创建自己的调用处理器; 
  2. public class ProxyHandler implements InvocationHandler { 
  3.  
  4.     private Object object; 
  5.     //通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。 
  6.     public ProxyHandler(Object object){ 
  7.         this.object = object; 
  8.     } 
  9.  
  10.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
  11.         System.out.println("Before invoke "+method.getName()); 
  12.         method.invoke(object,args); 
  13.         System.out.println("After invoke "+method.getName()); 
  14.         return null
  15.     } 

(4)测试类

  1. public class DynamicProxyTest { 
  2.     public static void main(String[] args){ 
  3.         BuyHouse buyHouse = new BuyHouseImpl(); 
  4.         BuyCar buyCar = new BuyCarImpl(); 
  5.  
  6.         InvocationHandler handler = new ProxyHandler(buyHouse); 
  7.         InvocationHandler handler1 = new ProxyHandler(buyCar); 
  8.  
  9.         /** 
  10.          * 通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类; 
  11.          */ 
  12.         BuyHouse proxyHouse = (BuyHouse) Proxy.newProxyInstance(buyHouse.getClass().getClassLoader(), buyHouse.getClass().getInterfaces(),handler); 
  13.         BuyCar proxyCar = (BuyCar) Proxy.newProxyInstance(buyCar.getClass().getClassLoader(), buyCar.getClass().getInterfaces(),handler1); 
  14.         proxyHouse.buyHouse(); 
  15.         proxyCar.buycar(); 
  16.          
  17.     } 

注意Proxy.newProxyInstance()方法接受三个参数:

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

ClassLoader loader:指定当前目标对象使用类加载器,获取加载器的方法是固定的。

Class[] interfaces:指定目标对象实现的接口的类型,使用泛型方式确认类型。

InvocationHandler h:指定动态处理器,执行目标对象的方法时,会触发事件处理器的方法。

2.2 CGLIB

CGLIB相比于JDK动态代理更加强大,JDK动态代理虽然简单易用,但是其有一个致命缺陷是,只能对接口进行代理。如果要代理的类为一个普通类、没有接口,那么Java动态代理就没法使用了。

在使用cglib前,需要先添加依赖。

  1. <dependency> 
  2.             <groupId>cglib</groupId> 
  3.             <artifactId>cglib</artifactId> 
  4.             <version>3.2.12</version> 
  5.         </dependency> 

(1)目标类

  • Dao
  1. public class Dao { 
  2.     public void update() { 
  3.         System.out.println("PeopleDao.update()"); 
  4.     } 
  • Dao1
  1. public class Dao1 { 
  2.     public void select(){ 
  3.         System.out.println("PeopleDao.select"); 
  4.     } 

(2)代理类

  1. public class DaoProxy implements MethodInterceptor { 
  2.     public Object intercept(Object object, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { 
  3.         System.out.println("Befor Metod Invoke"); 
  4.         methodProxy.invokeSuper(object,objects); 
  5.         System.out.println("After Method Invoke"); 
  6.         return null
  7.     } 

参数解释:

  • Object表示要进行增强的对象
  • Method表示拦截的方法
  • Object[]数组表示参数列表,基本数据类型需要传入其包装类型,如int-->Integer、long-Long、double-->Double
  • MethodProxy表示对方法的代理,invokeSuper方法表示对被代理对象方法的调用

(3)测试

  1. public class CglibProxyTest { 
  2.     public static void main(String[] args) { 
  3.         DaoProxy daoProxy = new DaoProxy(); 
  4.         Enhancer enhancer = new Enhancer(); 
  5.         Enhancer enhancer1 = new Enhancer(); 
  6.   //设置要继承的父类 
  7.         enhancer.setSuperclass(Dao.class); 
  8.         enhancer1.setSuperclass(Dao1.class); 
  9.         //设置回调方法 
  10.         enhancer.setCallback(daoProxy); 
  11.         enhancer1.setCallback(daoProxy); 
  12.  
  13.         //创建动态代理类 
  14.         Dao dao = (Dao)enhancer.create(); 
  15.         Dao1 dao1= (Dao1) enhancer1.create(); 
  16.         dao.update(); 
  17.         System.out.println("..................................."); 
  18.         dao1.select(); 
  19.     } 

 

责任编辑:武晓燕 来源: 小郎码知答
相关推荐

2011-04-06 11:41:25

Java动态代理

2012-02-29 09:41:14

JavaScript

2021-06-29 08:54:23

设计模式代理模式远程代理

2012-01-13 15:59:07

2011-03-23 10:40:51

java代理模式

2010-03-25 08:52:30

PHP设计模式代理模式

2024-02-26 11:52:38

代理模式设计

2022-11-30 17:05:33

代码程序场景

2024-04-10 12:27:43

Python设计模式开发

2022-09-07 08:25:08

代理模式设计模式代码

2025-01-09 11:15:47

2011-11-17 14:32:45

Java静态代理动态代理

2011-11-21 12:56:10

Java代理模式设计模式

2021-08-04 09:51:02

代理设计模式

2011-11-24 21:03:10

ibmdw

2021-10-26 10:40:26

代理模式虚拟

2023-09-28 15:43:03

装饰者模式代理定义

2012-06-28 13:55:10

2024-04-16 00:07:36

设计模式代理模式替身

2021-01-07 09:34:19

HTTPSHTTP抓包
点赞
收藏

51CTO技术栈公众号