设计模式之代理模式

简介: 设计模式之代理模式

代理模式

所有代码地址: https://gitee.com/zyxscuec/Design-pattern.git

文章目录

(1) 概念

代理模式(ProxyPattern)的定义也非常简单,是指为其他对象提供一种代理,以控制对这个对象的访问。

代理对象在客服端和目标对象之间起到中介作用,代理模式属于结构型设计模式。

(2)适用场景

使用代理模式主要有两个目的:一保护目标对象,二增强目标对象。

Subject 是顶层接口,RealSubject 是真实对象(被代理对象),Proxy 是代理对象,代

理对象持有被代理对象的引用,客户端调用代理对象方法,同时也调用被代理对象的方法,但是在代理对象前后增加一些处理。在代码中,我们想到代理,就会理解为是代码增强,其实就是在原本逻辑前后增加一些逻辑,而调用者无感知。代理模式属于结构型模式,有静态代理和动态代理

(3)代码示例

1. 静态代理模式

举个例子:人到了适婚年龄,父母总是迫不及待希望早点抱孙子。而现在社会的人在各种压力之下,都选择晚婚晚育。于是着急的父母就开始到处为自己的子女相亲,比子女自己还着急。这个相亲的过程,就是一种我们人人都有份的代理。来看代码实现:

顶层接口 Person:

package com.alibaba.design.proxypattern;
/**
 * @author zhouyanxiang
 * @create 2020-07-2020/7/30-10:54
 */
public interface Person {
    public void findLove();
}

儿子要找对象,实现 Son 类:

package com.alibaba.design.proxypattern.staticproxy;
import com.alibaba.design.proxypattern.Person;
/**
 * @author zhouyanxiang
 * @create 2020-07-2020/7/30-10:55
 */
public class Son implements Person {
    @Override
    public void findLove() {
        System.out.println("儿子要求:肤白貌美大长腿");
    }
}

父亲要帮儿子相亲,实现 Father 类:

package com.alibaba.design.proxypattern.staticproxy;
import com.alibaba.design.proxypattern.Person;
/**
 * @author zhouyanxiang
 * @create 2020-07-2020/7/30-10:55
 */
public class Father implements Person {
    private Son son;
    public Father(Son son){
        this.son = son;
    }
    @Override
    public  void findLove(){
        System.out.println("父亲物色对象");
        this.son.findLove();
        System.out.println("双方父母同意,确立关系");
    }
    public void findJob(){
    }
}

来看测试代码:

  • FatherTest
package com.alibaba.design.proxypattern.staticproxy;
/**
 * @author zhouyanxiang
 * @create 2020-07-2020/7/30-10:58
 */
public class FatherTest {
    public static void main(String[] args) {
        Father father = new Father(new Son());
        father.findLove();
        //农村,媒婆
        //婚介所
        //大家每天都在用的一种静态代理的形式
        //对数据库进行分库分表
        //ThreadLocal
        //进行数据源动态切换
    }
}

2. 动态代理模式

动态代理和静态对比基本思路是一致的,只不过动态代理功能更加强大,随着业务的扩展适应性更强。如果还以找对象为例,使用动态代理相当于是能够适应复杂的业务场景。不仅仅只是父亲给儿子找对象,如果找对象这项业务发展成了一个产业,进而出现了媒婆、婚介所等这样的形式。那么,此时用静态代理成本就更大了,需要一个更加通用的解决方案,要满足任何单身人士找对象的需求。我们升级一下代码,先来看 JDK 实现方式:

创建媒婆(婚介)JDKMeipo 类:

package com.alibaba.design.proxypattern.dynamicproxy.jdkproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
 * @author zhouyanxiang
 * @create 2020-07-2020/7/30-10:52
 */
public class JDKMeipo implements InvocationHandler {
    private Object target;
    public Object getInstance(Object target) throws Exception{
        this.target = target;
        Class<?> clazz = target.getClass();
        return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object obj = method.invoke(this.target,args);
        after();
        return obj;
    }
    private void before(){
        System.out.println("我是媒婆,我要给你找对象,现在已经确认你的需求");
        System.out.println("开始物色");
    }
    private void after(){
        System.out.println("OK的话,准备办事");
    }
}

创建单身客户 Customer 类:

package com.alibaba.design.proxypattern.dynamicproxy.jdkproxy;
import com.alibaba.design.proxypattern.Person;
/**
 * @author zhouyanxiang
 * @create 2020-07-2020/7/30-11:11
 */
public class Customer implements Person {
    @Override
    public void findLove() {
        System.out.println("高富帅");
        System.out.println("身高180cm");
        System.out.println("有6块腹肌");
    }
}

测试代码

package com.alibaba.design.proxypattern.dynamicproxy.jdkproxy;
import java.lang.reflect.Method;
/**
 * @author zhouyanxiang
 * @create 2020-07-2020/7/30-11:11
 */
public class JDKProxyTest {
    public static void main(String[] args) {
        try {
            Object obj = new JDKMeipo().getInstance(new Customer());
            Method method = obj.getClass().getMethod("findLove",null);
            method.invoke(obj);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

(4) 模式在源码中的体现

代理模式在 Spring 源码中的应用,先看 ProxyFactoryBean 核心的方法就是 getObject()方法,我们来看一下源码:

public Object getObject() throws BeansException {
    initializeAdvisorChain();
    if (isSingleton()) {
      return getSingletonInstance();
    }else {
      if (this.targetName == null) {
      logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " + "Enable prototype proxies by setting the 'targetName' property.");
      } 
      return newPrototypeInstance();
    }
}

在 getObject()方法中,主要调用 getSingletonInstance()和 newPrototypeInstance();在 Spring 的配置中,如果不做任何设置,那么 Spring 代理生成的 Bean 都是单例对象。如果修改 scope 则每次创建一个新的原型对象。

Spring 利用动态代理实现 AOP 有两个非常重要的类,一个是 JdkDynamicAopProxy 类

和 CglibAopProxy 类,来看一下类图:

Spring 中的代理选择原则

  • 1、当 Bean 有实现接口时,Spring 就会用 JDK 的动态代理。
  • 2、当 Bean 没有实现接口时,Spring 选择 CGLib。
  • 3、Spring 可以通过配置强制使用 CGLib,只需在 Spring 的配置文件中加入如下代码:
<aop:aspectj-autoproxy proxy-target-class="true"/>

(5)代理模式的优缺点

  • 优点:
    1、代理模式能将代理对象与真实被调用的目标对象分离。
    2、一定程度上降低了系统的耦合度,扩展性好。
    3、可以起到保护目标对象的作用。
    4、可以对目标对象的功能增强。
  • 缺点:
    1、代理模式会造成系统设计中类的数量增加。
    2、在客户端和目标对象增加一个代理对象,会造成请求处理速度变慢。
    3、增加了系统的复杂度。

(6) 动态代理模式和静态代理模式的区别

  • 1、静态代理只能通过手动完成代理操作,如果被代理类增加新的方法,代理类需要同步
    新增,违背开闭原则。
  • 2、动态代理采用在运行时动态生成代码的方式,取消了对被代理类的扩展限制,遵循开
    闭原则。
  • 3、若动态代理要对目标类的增强逻辑扩展,结合策略模式,只需要新增策略类便可完成,
    无需修改代理类的代码。


相关文章
|
6月前
|
设计模式 缓存 监控
【设计模式系列笔记】代理模式
代理模式是一种结构型设计模式,它允许一个对象(代理对象)控制另一个对象的访问。代理对象通常充当客户端和实际对象之间的中介,用于对实际对象的访问进行控制、监控或其他目的。
118 1
|
6月前
|
设计模式 缓存 安全
小谈设计模式(8)—代理模式
小谈设计模式(8)—代理模式
|
2月前
|
设计模式 缓存 安全
设计模式——代理模式
静态代理、JDK动态代理、Cglib 代理
设计模式——代理模式
|
6月前
|
设计模式 Java
Java一分钟之-设计模式:装饰器模式与代理模式
【5月更文挑战第17天】本文探讨了装饰器模式和代理模式,两者都是在不改变原有对象基础上添加新功能。装饰器模式用于动态扩展对象功能,但过度使用可能导致类数量过多;代理模式用于控制对象访问,可能引入额外性能开销。文中通过 Java 代码示例展示了两种模式的实现。理解并恰当运用这些模式能提升代码的可扩展性和可维护性。
63 1
|
2月前
|
设计模式 Java 数据安全/隐私保护
Java设计模式-代理模式(7)
Java设计模式-代理模式(7)
|
6月前
|
设计模式 Java 数据库连接
【重温设计模式】代理模式及其Java示例
【重温设计模式】代理模式及其Java示例
|
3月前
|
设计模式 缓存 Java
【十一】设计模式~~~结构型模式~~~代理模式(Java)
文章详细介绍了代理模式(Proxy Pattern),这是一种对象结构型模式,用于给对象提供一个代理以控制对它的访问。文中阐述了代理模式的动机、定义、结构、优点、缺点和适用环境,并探讨了远程代理、虚拟代理、保护代理等不同代理形式。通过一个商务信息查询系统的实例,展示了如何使用代理模式来增加身份验证和日志记录功能,同时保持客户端代码的无差别对待。此外,还讨论了代理模式在分布式技术和Spring AOP中的应用,以及动态代理的概念。
【十一】设计模式~~~结构型模式~~~代理模式(Java)
|
3月前
|
设计模式
设计模式的基础问题之代理模式在工作中的问题如何解决
设计模式的基础问题之代理模式在工作中的问题如何解决
|
4月前
|
设计模式 算法 Go
iLogtail设计模式问题之代理模式在iLogtail中是如何应用的
iLogtail设计模式问题之代理模式在iLogtail中是如何应用的
|
4月前
|
设计模式 缓存 JavaScript
js设计模式【详解】—— 代理模式
js设计模式【详解】—— 代理模式
32 0

热门文章

最新文章

  • 1
    C++一分钟之-设计模式:工厂模式与抽象工厂
    42
  • 2
    《手把手教你》系列基础篇(九十四)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-下篇(详解教程)
    46
  • 3
    C++一分钟之-C++中的设计模式:单例模式
    53
  • 4
    《手把手教你》系列基础篇(九十三)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-上篇(详解教程)
    37
  • 5
    《手把手教你》系列基础篇(九十二)-java+ selenium自动化测试-框架设计基础-POM设计模式简介(详解教程)
    61
  • 6
    Java面试题:结合设计模式与并发工具包实现高效缓存;多线程与内存管理优化实践;并发框架与设计模式在复杂系统中的应用
    56
  • 7
    Java面试题:设计模式在并发编程中的创新应用,Java内存管理与多线程工具类的综合应用,Java并发工具包与并发框架的创新应用
    40
  • 8
    Java面试题:如何使用设计模式优化多线程环境下的资源管理?Java内存模型与并发工具类的协同工作,描述ForkJoinPool的工作机制,并解释其在并行计算中的优势。如何根据任务特性调整线程池参数
    49
  • 9
    Java面试题:请列举三种常用的设计模式,并分别给出在Java中的应用场景?请分析Java内存管理中的主要问题,并提出相应的优化策略?请简述Java多线程编程中的常见问题,并给出解决方案
    105
  • 10
    Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
    75