设计模式---代理模式

2023-05-16

代理模式

proxy pattern

定义:指为其他对象提供一种代理,以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介作用。

使用目的

  1. 保护目标对象
  2. 增强目标对象

解释
在这里插入图片描述

Subject是顶层接口,RealSubject是真实对象(被代理对象),proxy是代理对象,代理对象持有被代理对象的引用,客户端调用代理对象的方法,同时也调用被代理对象的方法,但是会在代理对象前后增加一些处理代码。一般代理会被理解为代码增强,实际上是在原代码逻辑前后增加一些代码逻辑。使调用者无感知。

静态代理

eg: 老子给儿子介绍对象案例

Person接口

/**
 * 顶层接口
 */
public interface Person {

    /**
     * 成家
     */
    void getMarried();
}

son类

/**
 * 子类
 */
public class Son implements Person{
    @Override
    public void getMarried() {
        System.out.println("儿子要成家===");
    }
}

Father类

package com.maggie.demo.proxy.quiet.proxy;

import com.maggie.demo.proxy.quiet.pojo.Son;
import lombok.Data;

@Data
public class Father {

    private Son son;

    public Father(Son son) {
        this.son = son;
    }

    public void getProxy() {
        System.out.println("===给介绍===");
        son.getMarried();
        System.out.println("===成家百年===");
    }
}

Test

package com.maggie.demo.proxy.quiet.client;

import com.maggie.demo.proxy.quiet.pojo.Son;
import com.maggie.demo.proxy.quiet.proxy.Father;

public class DemoTest {

    public static void main(String[] args) {

        Father father = new Father(new Son());
        father.getProxy();
    }
}

结果

load mybatis-log agent success.
===给介绍===
儿子要成家===
===成家百年===

Process finished with exit code 0

动态代理

1,JDK实现方式

eg:婚介所案例

customer客户类

package com.maggie.demo.proxy.dynamic.pojo;

import com.maggie.demo.proxy.quiet.pojo.Person;

/**
 * 单身客户类
 */
public class Customer implements Person {

    @Override
    public void getMarried() {
        System.out.println("家里有钱");
        System.out.println("要白富美");
    }
}

动态代理类

package com.maggie.demo.proxy.dynamic.proxy;

import com.maggie.demo.proxy.quiet.pojo.Son;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class JDKMeipo implements InvocationHandler {

    //被代理的对象,把引用保存下来
   private Object target;
   public Object  getInterFace (Object target) throws  Exception{
       this.target=target;
       Class<?> aClass = target.getClass();
       return Proxy.newProxyInstance(aClass.getClassLoader(),aClass.getInterfaces(),this);
   }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        before();
        Object invoke = method.invoke(this.target, args);
        after();

        return invoke;
    }


    //前置增强方法
    private void before(){
        System.out.println("婚介所开始介绍");
    }

    //后置增强方法
    private void after(){
        System.out.println("合适,开始结婚");
    }
}

测试类

package com.maggie.demo.proxy.dynamic.client;

import com.maggie.demo.proxy.dynamic.pojo.Customer;
import com.maggie.demo.proxy.dynamic.proxy.JDKMeipo;
import com.maggie.demo.proxy.quiet.pojo.Person;

public class DemoTest {
    public static void main(String[] args) throws Exception{
        Person person = (Person)new JDKMeipo().getInterFace(new Customer());
        person.getMarried();
    }
}

结果

load mybatis-log agent success.
婚介所开始介绍
家里有钱
要白富美
合适,开始结婚

Process finished with exit code 0

原理

jdk动态代理采用字节重组,重新生成对象来代替原始对象,以达到动态代理的目的。

jdk动态代理生成对象的步骤

  1. 获取被代理对象的引用,并且获取它的所有接口,反射获取。
  2. jdk动态代理类重新生成一个新的类,同时新的类要实现被代理类实现的所有接口。
  3. 动态生成java代码,新加的业务逻辑方法由一定的逻辑代码调用。
  4. 编译新生成的Java代码.class文件。
  5. 重新加载到jvm中运行。
2,CGLIB实现动态代理

沿用以上实例,重新实现

客户类Customer

package com.maggie.demo.proxy.dynamic.waybycglib.pojo;

public class Customer {
    public void getMarried() {
        System.out.println("要白富美");
    }
}

CglibMeipo类

package com.maggie.demo.proxy.dynamic.waybycglib.proxy;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;


public class CglibMeipo implements MethodInterceptor {

    public Object  getInterFace (Class<?> clazz) throws  Exception{
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return enhancer.create();

    }

    //前置增强方法
    private void before(){
        System.out.println("婚介所开始介绍");
    }

    //后置增强方法
    private void after(){
        System.out.println("合适,开始结婚");
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        before();
        Object invoke = methodProxy.invokeSuper(o, objects);
        after();
        return invoke;
    }
}

Test类

package com.maggie.demo.proxy.dynamic.waybycglib.client;

import com.maggie.demo.proxy.dynamic.waybycglib.pojo.Customer;
import com.maggie.demo.proxy.dynamic.waybycglib.proxy.CglibMeipo;

public class Test {
    public static void main(String[] args)throws Exception{
        Customer interFace =(Customer)new CglibMeipo().getInterFace(Customer.class);
        interFace.getMarried();
    }
}

结果

load mybatis-log agent success.
婚介所开始介绍
要白富美
合适,开始结婚

Process finished with exit code 0

总结一下

cgLib和jdk

  1. jdk动态代理实现了被代理对象的接口,CGLib代理继承了被代理对象。
  2. jdk动态代理和cGlib代理都在运行期生成字节码,jdk动态代理直接写Class字节码。CGLib代理使用ASM框架写Class字节码,实现更复杂,生成代理类效率更低。
  3. jdk动态代理调用代理方法是通过反射机制调用的。
    cglib代理是通过FastClass机制直接调用方法的,执行效率更高。

静态代理和动态代理的本质区别

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

代理模式优缺点

优点:

  1. 代理模式能将代理对象与真是被调用的目标对象分离。
  2. 在一定程度上降低了系统耦合性,扩展性好。
  3. 可以起到保护目标对象的作用。
  4. 可以增强目标对象功能。

缺点:

  1. 代理模式会造成系统设计中类的数量增加。
  2. 在客户端和目标对象中增加一个代理对象,会导致请求处理速度变慢。
  3. 增加了系统的复杂度。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

设计模式---代理模式 的相关文章

  • C++设计模式(二)观察者模式

    1 观察者模式知识点 1 定义 定义对象间的一种一对多的依赖关系 当一个对象的状态发生改变的时候 所有依赖它的对象都得到通知并自动更新 2 动机 将一个系统分割成一系列相互协作的类有一个常见的副作用 需要维护相关对象间的一致性 我们不希望为
  • 设计模式——原型模式

    原型模式顾名思义 就是指以某个实例为原型 copy出一个新的实例 该实例属性与原型相同或者是类似 很多时候 我们需要创建大量的相同或者相似的对象 如果一个个用new 构造函数的形式去创建的话比较繁琐 就像孙悟空要想变出成千上万个猴子猴孙总不
  • 小谈设计模式(1)—总序

    小谈设计模式 1 总序 专栏地址 开始操作 设计模式总论 设计模式是什么 组成要素 模式名称 问题描述 解决方案 效果描述 设计模式有什么作用 提供可重用的解决方案 提高代码的可读性和可维护性 促进代码的可扩展性 提高代码的灵活性和可重用性
  • Java设计模式:装饰者模式(Decorator Pattern)

    装饰者模式 涉及的重要设计原则 类应该对扩展开放 对修改关闭 装饰者模式定义 装饰者模式动态地将责任附加到对象上 若要扩展功能 装饰者提供了比继承更有弹性的替代方案 UML类图 装饰者模式事例 咖啡店 咖啡种类 1 深焙咖啡 DarkRoa
  • 简单工厂模式

    简单工厂模式 一 概念 从设计模式的类型上来说 简单工厂模式是属于创建型模式 又叫做静态工厂方法 StaticFactory Method 模式 但不属于23种GOF设计模式之一 简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例 简
  • 行为型模式-状态模式

    package per mjn pattern state after 环境角色类 public class Context 定义对应状态对象的常量 public final static OpeningState OPENING STAT
  • Spring系列之@Aspect中@Pointcut 12种用法

    先了解几个概念 文中会涉及几个概念 先了解一下 target 用来表示目标对象 即需要通过aop来增强的对象 proxy 代理对象 target通过aop增强之后生成的代理对象 AspectJ AspectJ是什么 AspectJ是一个面向
  • 设计模式——导论

    作为软件开发人员 我们在平时工作的过程中 往往需要编写很多的代码来实现我们的需求 很多的时候会造成代码臃肿和代码冗余的情况 这个时候我们需要引入一个理念 设计模式 设计模式存在的意义在于 1 使得我们的代码更加精炼 2 使我们代码的可读性更
  • Java 多线程模式 —— Guarded Suspension 模式

    Part1Guarded Suspension 模式的介绍 我们只从字面上看 Guarded Suspension 是受保护暂停的意思 1Guarded Suspension 模式 在实际的并发编程中 Guarded Suspension
  • 设计模式七大原则

    1 设计模式的目的 编写软件过程中 程序员面临着来自耦合性 内聚性以及可维护性 可扩展性 重用性 灵活性 等多方面的挑战 设计模式是为了让程序 软件 具有更好 1 代码重用性 即 相同功能的代码 不用多次编写 2 可读性 即 编程规范性 便
  • [设计模式]模板方法模式(Template Method)

    1 意图 定义一个操作中的算法的骨架 而将一些步骤延迟到子类中 TemplateMethod使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤 2 动机 其实就是如意图所描述的 算法的骨架是一样的 就是有些特殊步骤不一样 就可以
  • 设计模式——State(状态)模式

    目录 前言 1 定义 2 适用性 3 结构 3 1 结构图 3 2 参与者 4 应用举例 4 1 State TcpState 4 2 Context TcpConnection 4 3 ConcreteState ListeningTcp
  • 设计模式-享元模式

    一 概念 如果在一个系统中存在多个相同的对象 那么只需要共享一份对象的拷贝 而不必为每一次使用都创建新的对象 目的是提高系统性能 上面的概念乍一听好像单例模式其实不是 单例模式只保存一个对象 但是这里可以有很多个不同对象 但是每个对象只有一
  • 【设计模式】工厂模式(Factory Pattern)

    1 概述 工厂模式 Factory Pattern 是最常用的设计模式之一 它属于创建类型的设计模式 它提供了一种创建对象的最佳方式 在工厂模式中 我们在创建对象时不会对客户端暴露创建逻辑 并且是通过一个共同的接口来指向新创建的对象 工厂模
  • 在AI技术的无情侵袭下,学学Java的23种设计模式还是非常有必要的

    目前国内80 程序员的主要工作是调用组合api实现各种业务需求 在顶层架构师设定好的框架下 做着重复且无聊的编码工作 如果未来ai被广泛应用 那么被替代的风险是很高的 比较扎心的是 其实目前用ai生成片段代码已经是各个公司比较普遍的做法了
  • 自动化测试面试题(附答案)

    1 自动化代码中 用到了哪些设计模式 单例设计模式 工厂模式 PO设计模式 数据驱动模式 面向接口编程设计模式 2 什么是断言 Assert 断言Assert用于在代码中验证实际结果是不是符合预期结果 如果测试用例执行失败会抛出异常并提供断
  • C++设计模式 #3策略模式(Strategy Method)

    动机 在软件构建过程中 某些对象使用的的算法可能多种多样 经常改变 如果将这些算法都写在类中 会使得类变得异常复杂 而且有时候支持不频繁使用的算法也是性能负担 如何在运行时根据需求透明地更改对象的算法 将算法和对象本身解耦 从而避免上述问题
  • 【设计模式之美】理论一:怎么才算是单一原则、如何取舍单一原则

    文章目录 一 如何判断类的职责是否足够单一 二 类的职责是否设计得越单一越好 开始学习一些经典的设计原则 其中包括 SOLID KISS YAGNI DRY LOD 等 本文主要学习单一职责原则的相关内容 单一职责原则的定义 一个类只负责完
  • 关于burpsuite对app(移动端)进行抓包的配置

    可以使用手机模拟器 我这里以自己手机 物理机 演示配置过程 如果是使用的模拟器那么肯定和电脑是在同一局域网 如果使用物理机 那么可以通过连接同一WiFi确保在同一局域网环境下 查看电脑内网ip 192 168 1 105 注意 看的是无线局
  • C++设计模式 --1.工厂模式和单例模式

    文章目录 1 工厂模式 简单工厂模式 工厂方法模式 抽象工厂模式 2 单例模式 懒汉式 饿汉式 1 工厂模式 简单工厂模式

随机推荐

  • 解析Android自带的SettingActivity——>Proference

    1 在res xml中 的代码解析 Preference是采用SharedPreference保存数据的 这里的属性key表示默认存储的键 xff0c defaultValue表示默认存储的值 如果是使用preference的话 xff0c
  • Android中使用lottie资源

    lottie资源的使用 1 下载lottie文件的网址 xff1a https lottiefiles com xff0c 下载的文件为 json的文件 2 存放在Android的位置为 3 在应用级别的 build gradle 文件中添
  • 【实验七】Linux生产者消费者问题(线程)

    目录 一 问题介绍 二 代码 1 prod cons cpp 2 producer h 3 producer cpp 4 consumer h 5 consumer cpp 6 mq h 7 mq cpp 8 message h 9 mes
  • HTTP-响应数据格式及常见地状态响应码(403,404,405)

    HTTP 响应数据格式 响应数据分为3部分 1 响应行 响应数据的第一行 其中HTTP 1 1表示协议版本 xff0c 200表示响应状态码 xff0c OK表示状态码描述 2 响应头 第二行开始 xff0c 格式为键值对的形式 3 响应体
  • 【Linux】TigerVNC安装指导

    1 以单一用户远程访问桌面 1 1 服务端中启用桌面共享 在统信服务器操作系统V20 1020a 上配置为启用单一客户端的远程桌面连接 1 2 配置远程桌面服务端 1 配置防火墙规则来启用对服务端的VNC访问或关闭防火墙 xff1a fir
  • 使用console.log输出特殊字符图案或自定义图片

    最近看到一篇比较有趣的文章 程序员的浪漫 console log 在浏览器控制台输出特殊字符编码的图案 想自己动手试一试 xff0c 很明显我做的效果不好 xff0c 弄了很久还是没弄出来 下面介绍另外一种方法 xff0c 方法来自 使用c
  • IDEA中添加了vue.js插件后setting就打不开;添加vue.js报错Requires plugin ‘intellij.webpack‘ to be installed

    IDEA版本要和vue js版本对应 查看IDEA版本 xff0c help about 然后再去官网查找和自己IDEA版本对应的vue js Versions Vue js IntelliJ IDEs Plugin Marketplace
  • yml配置文件简单语法及小坑

    yml文件使用方法 1 语法 K 空格 V 表示一对键值对 xff0c 以空格缩进来控制层级关系 xff0c 只要左对齐的一列数据 xff0c 都是一个层级的 属性和值是大小写敏感 2 写法 普通值 字符串默认不加单引号或者双引号 xff1
  • 抽象工厂模式

    工厂模式 工厂方法模式 xff08 Fatory Method Pattern xff09 提供一个接口 xff0c 一个可创建一系列相关对象的 无需指定他们的具体类 一个抽象工厂类 xff0c 不同的具体工厂产生不同的对象实体 eg 冰箱
  • docker简介--01

    官方文档 xff1a https docs docker com engine reference commandline docker 官方仓库 xff1a https hub docker com docker基本组成 image 镜像
  • docker网络配置和名称空间管理

    docker容器虚拟化 虚拟化网络 Network Namespace 是 Linux 内核提供的功能 xff0c 是实现网络虚拟化的重要功能 xff0c 它能创建多个隔离的网络空间 xff0c 它们有独自网络栈信息 不管是虚拟机还是容器
  • CentOS系统下安装docker简易步骤

    docker 官网地址 https www docker com docker 开发文档 https docs docker com manuals 手册 gt install gt Linux xff08 centos xff09 环境为
  • linux环境安装jdk

    linux环境安装jdk 1 查看本环境下是否java环境 java version 不存在 已存在 2 如果不存在 xff0c 先去下载jdk 到官网下载jdk 注 xff1a 一定要根据具体的linux系统按需下载对应的安装包 我的是l
  • linux环境下安装tomcat

    配置tomcat 到官网下载tar包 将tar包上传到服务器 并解压 span class token function tar span zxvf apache tomcat 9 0 65 tar gz 重命名tomcat9 span c
  • docker基础命令以及常用命令

    docker 基本命令 1 其他命令 span class token comment 查看版本 span docker version span class token comment 查看信息 span docker info span
  • Redis基础数据结构及其使用

    Redis 一 xff0c docker方式安装redis span class token comment 拉取 redis 镜像 span span class token operator gt span span class tok
  • 设计模式之--原型模式

    原型模式 原型实例指定创建对象的种类 xff0c 并且通过复制这些原型创建新对象 使用场景 xff1a 类初始化消耗资源比较多 使用new生成一个对象需要非常繁琐的过程 构造函数比较复杂 在循环体中产生大量对象 浅克隆 浅克隆只是完整复制了
  • redis分布式锁使用方式

    为什么使用锁 xff1f 锁的作用是要解决多线程对共享资源的访问而产生的线程安全问题 当多个线程并发操作某个对象时 xff0c 可以通过synchronized来保证同一时刻只能有一个线程获取到对象锁进而处理synchronized关键字修
  • Redis的延时队列

    延时队列 redis的list数据结构用来做一部消息队列 xff0c 使用rpush lpush操作入队列 使用lpop rpop来出队列 span class token operator gt span rpush notify que
  • 设计模式---代理模式

    代理模式 proxy pattern 定义 xff1a 指为其他对象提供一种代理 xff0c 以控制对这个对象的访问 代理对象在客户端和目标对象之间起到中介作用 使用目的 保护目标对象增强目标对象 解释 Subject是顶层接口 xff0c