当前位置: 首页 > article >正文

SpringAOP前置——代理模式

代理模式是SpringAOP(面向切面编程)的底层原理

代理模式的分类

  • 静态代理
  • 动态代理

静态代理

角色分析:
抽象角色:一般使用抽象类或接口来解决
代理角色:代理真实角色,在代理真实角色后,一般会做一些附属操作
真实角色:被代理的角色
客户:访问代理对象的角色,可以理解为一个处理事务的线程,多为一次业务处理

以租房举例子进行理解

房东有房子要出租,将房源信息告诉中介,也就是让中介代理房东进行房屋租赁这件事。房东是真实角色(被代理的角色),中介是代理角色,房屋租赁这件事是抽象角色。
租房者是客户,相当于一次租房业务。
接下来上代码
抽象角色:房屋租赁这件事

package com.zbt.proxy.demo01;

/**
 * @author
 * @createAt 2025/1/12 20:58
 */

/**
 * 租房 接口
 */
public interface Rent {
    //出租事件 出租的是房子 对应着一个房东
    void rent(Host host);
}

真实角色:房东 有两个属性 一个名字,一个房屋地址

package com.zbt.proxy.demo01;

/**
 * @author
 * @createAt 2025/1/12 20:59
 */

/**
 * 房东
 */
public class Host implements Rent{
    private String name;
    private String address;

    public Host() {
    }

    public Host(String name, String address) {
        this.name = name;
        this.address = address;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public void rent(Host host) {
        System.out.println("我是房东:"+name+",我要出租房子,地址是:"+address);
    }
}

代理角色:中介

package com.zbt.proxy.demo01;

/**
 * @author
 * @createAt 2025/1/12 21:01
 */

import java.util.ArrayList;
import java.util.List;

/**
 * 中介 代理租房
 */
public class Proxy implements Rent{
    //被代理的对象 对于中介来说就是一个房东
    private Host;

    public void setHost(Host host){
        hostLs.add(host);
    }
    public Host getHost(){
        return host;
    }

    public void rent(Host host) {
        //中介知道房东要出租房子  也就是中介对于你来说 代理了这套房子的房东
        host.rent(host);
        //带你去看房子
        seeHouse(host);
        //你看中了房子 签合同
        hetong();
        //中介收了中介服务费
        fare();
    }

    public void seeHouse(Host host){
        System.out.println("中介带你看了在"+host.getAddress()+"的房子");
    }

    public void hetong(){
        System.out.println("签租赁合同");
    }

    public void fare(){
        System.out.println("收中介费");
    }


}

客户:你 你要租房子 触发了一次租房业务流程(main方法)

package com.zbt.proxy.demo01;

/**
 * @author
 * @createAt 2025/1/12 21:00
 */

/**
 * 租客要租房
 */
public class Client {
    
    public static void main(String[] args) {
    	//被代理对象 -- 房东
        Host host1 = new Host("房东1号","南京南街5-5-1号");
        //代理对象 -- 中介
        Proxy proxy;= new Proxy();
        //房东在中介登记房子
        proxy.setHostLs(host3);
        //你要租房子  找到了中介 触发了租房流程
        //中介给你介绍了一套房子
        Host host = proxy.getHostLs(0);
        //中介带你走租房流程  看房 签合同
        proxy.rent(host);
    }
}

静态代理模式的好处

  • 可以使真实角色的“动作”更加纯粹:例如上面的例子,房东就只需要找中介登记一下房源,就可以等着房子出租出去了,不需要进行公共业务(带人看房,贴租房广告等)
  • 公共业务交给代理角色来进行,进行过了业务的分工,
  • 在公共业务需要进行扩展的时候方便集中管理,只需要改代理对象就可以了。
    静态代理模式缺点
    一个真实角色就会产生一个代理角色,代码量会增加,开发效率降低

模拟实际开发逻辑理解静态代理

实际开发经常用到用户信息的增删查改
我们通常的写法是:

package com.zbt.proxy.demo02;

/**
 * 接口类
 */
public interface UserService {
    void insert();
    void delete();
    void update();
    void select();
}

package com.zbt.proxy.demo02;

/**
 * @author
 * @createAt 2025/1/12 22:01
 */

/**
 * 实现类
 */
public class UserServiceImpl implements UserService{

    public void insert() {
        System.out.println("插入了一个用户");
    }

    public void delete() {
        System.out.println("删除了一个用户");
    }

    public void update() {
        System.out.println("修改了一个用户");
    }

    public void select() {
        System.out.println("查询了一个用户");
    }
}

package com.zbt.proxy.demo02;

/**
 * 调用
 * @author
 * @createAt 2025/1/12 22:02
 */


public class Client {
    public static void main(String[] args) {
        UserServiceImpl userService = new UserServiceImpl();
        userService.insert();
    }
}

这样当然可以实现业务需求,但是当后期,如果在此基础上需要增加新的需求时,就得修改原有的业务逻辑代码,例如在调用每个方法时,增加一条日志记录,我们就需要去修改原来的UserServiceImpl 里面每一个方法,添加一条打印语句。如果需要进行的改较为复杂,那么修改原业务逻辑是致命的,此时我们将写法改为静态代理模式。
在原有基础上,增加一个代理类UserServiceProxy 代理UserServiceImpl

package com.zbt.proxy.demo02;

/**
 * 代理类  代理UserServiceImpl  将UserServiceImpl 对象通过set方法传入 里面直接通过UserServiceImpl 对象调用对应方法,需要修改逻辑时,直接修改代理类,例如上面提到的增加一条调用日志打印
 * @author
 * @createAt 2025/1/12 22:03
 */


public class UserServiceProxy implements UserService{
    private UserServiceImpl userService;

    public UserServiceImpl getUserService() {
        return userService;
    }

    public void setUserService(UserServiceImpl userService) {
        this.userService = userService;
    }

    public void insert() {
        log("insert");
        userService.insert();
    }

    public void delete() {
        log("delete");
        userService.delete();
    }

    public void update() {
        log("update");
        userService.update();
    }

    public void select() {
        log("select");
        userService.select();
    }

    //日志打印方法
    public void log(String msg){
        System.out.println("调用了"+msg+"方法");
    }
}


package com.zbt.proxy.demo02;

/**
 * 调用
 * @author
 * @createAt 2025/1/12 22:02
 */


public class Client {
    public static void main(String[] args) {
        UserServiceImpl userService = new UserServiceImpl();
        UserServiceProxy proxy = new UserServiceProxy();
        proxy.setUserService(userService);
        proxy.insert();
    }
}


动态代理

  • 动态代理和静态代理角色分类一样
  • 动态代理的代理类是动态生成的,不是提前写好的
  • 动态代理分为两大类:基于接口的动态代理(JDK的动态代理)、基于类的动态代理(cglib)
    两个关键的类:Proxy、InvocationHandler
  • Proxy用来生成动态代理实例
  • InvocationHandler用来调用处理程序并返回结果
    上代码:还是上面用户信息的增删查改的例子
package com.zbt.proxy.demo03;

/**
 * 接口类
 */
public interface UserService {
    void insert();
    void delete();
    void update();
    void select();
}
package com.zbt.proxy.demo03;

/**
 * @author
 * @createAt 2025/1/12 22:01
 */

/**
 * 实现类
 */
public class UserServiceImpl implements UserService {

    public void insert() {
        System.out.println("插入了一个用户");
    }

    public void delete() {
        System.out.println("删除了一个用户");
    }

    public void update() {
        System.out.println("修改了一个用户");
    }

    public void select() {
        System.out.println("查询了一个用户");
    }
}
package com.zbt.proxy.demo03;

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

/**
 * 动态获得代理类的工具类
 * @author
 * @createAt 2025/1/13 21:04
 */
public class ProxyInvocationHandler implements InvocationHandler {
    //被代理的接口——真实对象
    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }

    //生成得到代理类实例
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(), this);
    }

    //处理代理实例 并返回结果
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        log(method.getName());//method.getName() 获取调用的方法名
        return method.invoke(target, args);
    }

    public void log(String msg){
        System.out.println("调用了"+msg+"方法");
    }
}
package com.zbt.proxy.demo03;

import com.zbt.proxy.demo02.UserServiceProxy;

/**
 * @author
 * @createAt 2025/1/12 22:02
 */


public class Client {
    public static void main(String[] args) {
        //真实角色
        UserServiceImpl userService = new UserServiceImpl();
        //代理角色 原本并不存在的类,动态生成的类
        ProxyInvocationHandler handler = new ProxyInvocationHandler();
        handler.setTarget(userService);
        //生成动态代理类
        UserService proxy = (UserService)handler.getProxy();
        //调用方法
        proxy.insert();
    }
}

这个动态代理我也没太理解。。。。等我再研究研究,应该就是利用反射的机制,借用Proxy、InvocationHandler来动态生成代理类


http://www.kler.cn/a/505170.html

相关文章:

  • 光谱相机的光谱分辨率可以达到多少?
  • 豆包MarsCode:可以在线用的智能AI编程助手
  • favor的本质
  • 2024年11月系统架构设计师考试复盘
  • 如何通过腾讯云平台执行SFT微调大语言模型
  • Vue篇-07
  • Python爬取豆瓣图书网Top250 实战
  • 【工具类】获取日出日落时间的Java工具类
  • 全网唯一的工具 苹果手机备忘录全自动导出备份
  • QT与基恩士PLC采用上位链路通信实现
  • Jmeter配置服务代理器 Proxy(二)
  • 云计算技术深度解析与代码实践
  • 机器学习实战33-LSTM+随机森林模型在股票价格走势预测与买卖点分类中的应用
  • Python AI教程之二十一:监督学习之支持向量机(SVM)算法
  • 「实战应用」如何为DHTMLX JavaScript 甘特图添加进度线
  • 深入剖析 Wireshark:网络协议分析的得力工具
  • 在 Go语言中一个字段可以包含多种类型的值的设计与接种解决方案
  • 如何修复Android上未安装的应用程序
  • 【声音场景分类--论文阅读】
  • 【Rust练习】28.use and pub