前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >【Java设计模式】之代理模式

【Java设计模式】之代理模式

作者头像
用户5640963
发布于 2019-07-26 06:12:11
发布于 2019-07-26 06:12:11
34700
代码可运行
举报
文章被收录于专栏:卯金刀GG卯金刀GG
运行总次数:0
代码可运行

代理模式是Java常见的设计模式之一。所谓代理模式是指客户端并不直接调用实际的对象,而是通过调用代理,来间接的调用实际的对象。 为什么要采用这种间接的形式来调用对象呢?一般是因为客户端不想直接访问实际的对象,或者访问实际的对象存在困难,因此通过一个代理对象来完成间接的访问。

代理模式的UML图

从UML图中,可以看出代理类与真正实现的类都是继承了抽象的主题类,这样的好处在于代理类可以与实际的类有相同的方法,可以保证客户端使用的透明性。

代理模式的实现

代理模式可以有两种实现的方式,一种是静态代理类,另一种是各大框架都喜欢的动态代理。下面我们主要讲解一下这两种代理模式

1、静态代理

我们先看针对上面UML实现的例子,再看静态代理的特点。 Subject接口的实现

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface Subject {
    void visit();
}

实现了Subject接口的两个类:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class RealSubject implements Subject {

    private String name = "byhieg";
    @Override
    public void visit() {
        System.out.println(name);
    }
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class ProxySubject implements Subject{

    private Subject subject;

    public ProxySubject(Subject subject) {
        this.subject = subject;
    }

    @Override
    public void visit() {
        subject.visit();
    }
}

具体的调用如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class Client {

    public static void main(String[] args) {
        ProxySubject subject = new ProxySubject(new RealSubject());
        subject.visit();
    }
}

通过上面的代理代码,我们可以看出代理模式的特点,代理类接受一个Subject接口的对象,任何实现该接口的对象,都可以通过代理类进行代理,增加了通用性。但是也有缺点,每一个代理类都必须实现一遍委托类(也就是realsubject)的接口,如果接口增加方法,则代理类也必须跟着修改。其次,代理类每一个接口对象对应一个委托对象,如果委托对象非常多,则静态代理类就非常臃肿,难以胜任。

2、动态代理(JDK)

动态代理有别于静态代理,是根据代理的对象,动态创建代理类。这样,就可以避免静态代理中代理类接口过多的问题。动态代理是实现方式,是通过反射来实现的,借助Java自带的java.lang.reflect.Proxy,通过固定的规则生成。 其步骤如下:

  1. 编写一个委托类的接口,即静态代理的(Subject接口)
  2. 实现一个真正的委托类,即静态代理的(RealSubject类)
  3. 创建一个动态代理类,实现InvocationHandler接口,并重写该invoke方法
  4. 在测试类中,生成动态代理的对象。

第一二步骤,和静态代理一样,不过说了。第三步,代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class DynamicProxy implements InvocationHandler {
    private Object object;
    public DynamicProxy(Object object) {
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = method.invoke(object, args);
        return result;
    }
}

第四步,创建动态代理的对象

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Subject realSubject = new RealSubject();
DynamicProxy proxy = new DynamicProxy(realSubject);
ClassLoader classLoader = realSubject.getClass().getClassLoader();
Subject subject = (Subject) Proxy.newProxyInstance(classLoader, new  Class[]{Subject.class}, proxy);
subject.visit();

创建动态代理的对象,需要借助Proxy.newProxyInstance。该方法的三个参数分别是:

  • ClassLoader loader表示当前使用到的appClassloader。
  • Class<?>[] interfaces表示目标对象实现的一组接口。
  • InvocationHandler h表示当前的InvocationHandler实现实例对象。

JDK代理模式

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class ProxyFactory {  
      
    private Object obj;  
      
      
    public ProxyFactory(Object obj) {  
        super();  
        this.obj = obj;  
    }  
  
    public Object getTransactionProxyInstance(){  
          
        Object proxy = Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new InvocationHandler() {  
            /** 
             * 三个参数:1、代理对象,2、目标对象的方法,3、目标对象的参数值列表 
             */  
            @Override  
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
                System.out.println("开启事务..."); //执行核心业务之前执行的内容  
                method.invoke(obj, args);      //执行目标对象方法,即核心业务  
                System.out.println("关闭事务..."); //执行核心业务之后执行的内容  
                return proxy;  
            }  
        });  
          
        return proxy;  
    }  
    
} 

3、动态代理(CGLIB)

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

使用cglib实现动态代理,完全不受代理类必须实现接口的限制,而且cglib底层采用ASM字节码生成框架,使用字节码技术生成代理类,比使用java反射效率要高。

需要引入两个jar包:cglib.jar,asm.jar

定义了一个拦截器,在调用目标方法之前,cglib回调MethodInterceptor接口方法拦截,来实现自己的业务逻辑,类似

于JDK中的InvocationHandler接口。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override  
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable ;

proxy:为cglib动态生成的代理实例

method:为上文中实体类所调用的被代理的方法调用

args:为method参数数值列表

methodProxy:为生成代理类对方法的代理引用

返回:从代理实例方法调用返回的值

其中,methodProxy.invokeSuper(obj,arg):

调用代理类实例上的proxy方法的父类方法

UserDaoImpl.java

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class CglibProxyFactory {  
      
    private Object obj;  
  
    public CglibProxyFactory(Object obj) {  
        super();  
        this.obj = obj;  
    }  
      
    public Object getProxyFactory(){  
        //Enhancer类是cglib中的一个字节码增强器,它可以方便的为你所要处理的类进行扩展  
        Enhancer enhancer = new Enhancer();  
        enhancer.setSuperclass(obj.getClass());//将目标对象所在的类作为Enhaner类的父类  
        enhancer.setCallback(new MethodInterceptor() {  
            //通过实现MethodInterceptor实现方法回调  
            @Override  
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {  
                System.out.println("事务开启...");  
                method.invoke(obj, args);  
                System.out.println("事务结束...");  
                  
                return proxy;  
            }  
        });  
          
        return enhancer.create();//生成目标对象并返回  
    }  
}  

测试类

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class TestCglibProxy {  
      
    @Test  
    public void test1(){  
        UserDaoImpl userDao = new UserDaoImpl();  
        UserDaoImpl userDaoProxy = (UserDaoImpl) new CglibProxyFactory(userDao).getProxyFactory();  
        userDaoProxy.save();  
        System.out.println("目标对象类型:"+userDao.getClass());  
        System.out.println("代理对象类型:"+userDaoProxy.getClass());  
    }  
      
      
}  
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Java设计模式(八)----代理模式
代理模式 1.生活中: 代理就是一个人或者一个组织代表其他人去做一件事的现实生活中的。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作
汤高
2018/01/11
8610
Java设计模式(八)----代理模式
23种设计模式(四)-代理模式
一般是因为客户端不想直接访问实际的对象, 或者不方便直接访问实际对象,因此通过一个代理对象来完成间接的访问。
用户7798898
2021/06/24
3560
java设计模式之代理模式
比较官方一点解释:为另一对象提供一个替身或者占位符,以控制对这个对象的访问,这句话看起来有一些比较难理解,那么下面我们用几个方便我们理解的场景去理解这句话;
一行Java
2022/04/06
1550
java设计模式之代理模式
23天读懂23种设计模式:代理模式(结构型)
结构型模式讨论的是类和对象的结构,它采用继承机制来组合接口或实现(类结构型模式),或者通过组合一些对象实现新的功能(对象结构型模式)。
后台技术汇
2022/05/28
2180
23天读懂23种设计模式:代理模式(结构型)
设计模式之代理模式(结构型)
代理模式:代理模式就是引入一个代理对象,通过代理对象实现对原对象的引用。代理模式是一种对象结构型。
SmileNicky
2019/01/22
2800
详解设计模式:代理模式
代理模式(Proxy Pattern),Java 常见的设计模式之一,是 GoF 的 23 种设计模式中的一种结构型设计模式。
栗筝i
2022/12/02
5430
详解设计模式:代理模式
Java设计模式(八)----代理模式
代理描述 1.生活中: 代理就是一个人或者一个组织代表其他人去做一件事的现实生活中的。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间
汤高
2018/01/11
6810
Java设计模式(八)----代理模式
Java Review - 关于代理的二三事儿
代理模式是一种结构型设计模式,其目的是为其他对象提供一种代理以控制对这个对象的访问。
小小工匠
2023/08/15
1890
Java Review - 关于代理的二三事儿
设计模式-代理模式
日常生活中,有非常多的代办、代处理,比如代找货源、代租房、代记、代办证件等,代办人就是这个代理的对象,通过代理人来达到办理的目的或结果,并且得到一样的结果。就比如:你想喝多了,回家找一个滴滴代驾,把车开到目的地,一样实现到达的结果是一样。
逍遥壮士
2020/09/18
2920
设计模式-代理模式
代理模式 代理模式
1、远程代理:对一个位于不同地址空间的对象提供一个本地代表,隐藏这个对象存在于不同地址空间的事实,例如RMI的stub(RMI也是比较重要的概念)。这个不同的地址空间可以是在同一主机中,也可以是在不同主机中。
mingmingcome
2021/11/29
3560
代理模式
    





        代理模式
设计模式学习笔记(七)代理模式以及动态代理的实现
代理模式(Proxy Design Pattern)是为一个对象提供一个替身,以控制对这个对象的访问。即通过代理对象访问目标对象。被代理的对象可以是远程对象、创建开销大的对象或需要安全控制的对象。
归思君
2023/10/16
2040
设计模式学习笔记(七)代理模式以及动态代理的实现
JAVA设计模式6:代理模式,用于控制对目标对象的访问
在代理模式中,代理对象充当了目标对象的中间层,客户端通过代理对象与目标对象进行交互。
Designer 小郑
2023/09/13
3180
JAVA设计模式6:代理模式,用于控制对目标对象的访问
Java设计模式之代理模式
代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能. 这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法
BUG弄潮儿
2022/06/30
1470
Java设计模式之代理模式
设计模式 ——— 代理模式
意图 为其他对象提供一种代理以控制对这个对象的访问 代理模式通过代理目标对象,把代理对象插入到客户和目标对象之间,从而为客户和目标对象引入一定的间接性,正是这个间接性,给了代理对象很多的活动空间,代理对象可以在调用具体的目标对象前后,附加很多操作,从而实现新的功能或是扩展目标对象的功能,更狠的是,代理对象还可以不去创建和调用目标对象,也就是说,目标对象被完全代理掉了,或是被替换掉了。 功能 代理模式是通过创建一个代理对象,用这个代理对象去代表真实的对象,客户端得到这个代理对象过后,对客户端没有什么影响
tomas家的小拨浪鼓
2018/06/27
4820
设计模式实战-代理模式,来看看主公如何托孤
代理模式的定义其实比较简单:代理模式给某对象提供一个代理对象,由代理对象来控制对原对象的引用。生活中比较常见的代理模式的应用比如:火车票代购、代办保险、UU 跑腿、武侠片中的替身、nginx 反向代理等等这种类似于中介的模式统统可以归于代理模式。“本人”和“代理人”都是对象,“代理人”可以代替“本人”去完成一些工作,甚至是出色完成(超期完成)某些工作,这里的“出色完成”就可以理解为对原工作的一种增强实现,这点有点类似于装饰器模式。感兴趣的读者不妨翻到前面装饰器模式一节中了解下装饰器模式。
架构师修炼
2020/07/17
5740
代理模式 PROXY Surrogate 结构型 设计模式(十四)
代理角色和真实对象角色拥有共同的抽象类型,他们拥有相同的对外接口request()方法
noteless
2018/12/24
4960
代理模式 PROXY Surrogate 结构型 设计模式(十四)
傀儡政权之代理模式
代理模式应用非常广泛,特别java领域的Spring框架,可以说把代理模式运用到极致。其中Spring的代理又分JDK动态代理和cglib动态代理。这类不打算深入讲解Spring的动态代理,而是深入讲解一下GOF 23的代理模式。
BUG弄潮儿
2020/12/17
2980
傀儡政权之代理模式
设计模式----代理模式
代理模式,为其他对象提供了一种代理以控制对这个对象的访问。代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介。
大忽悠爱学习
2021/11/15
2280
设计模式-代理模式
官话上讲是一种设计模式,目的是希望代码重用。跟我们以往访问对象的方式不同,代理模式不是直接通过目标对象,而是通过代理访问我们的目标对象以及方法。因为有的时候我们无法直接与目标对象建立联系或者,我们要控制客户端访问。所以便通过代理来访问我们的真实对象。
码哥字节
2020/03/24
3700
设计模式-代理模式
静态代理和动态代理简介
在某些情况下,一个客户不想或者不能直接引用一个对象,此时可以通过一个称之为“代理”的第三者来实现间接引用。代理对象可以在客户端和目标对象之间起到中介的作用,并且可以通过代理对象去掉客户不能看到的内容和服务或者添加客户需要的额外服务。 代理模式的角色分为: 主题接口: 即代理类的所实现的行为接口。 目标对象: 也就是被代理的对象。 代理对象: 用来封装真是主题类的代理类 客户端:即用来实现的类
SmileNicky
2019/01/17
4890
相关推荐
Java设计模式(八)----代理模式
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文