代理模式【静态代理和动态代理实现业务功能扩展】

简介: 代理模式【静态代理和动态代理实现业务功能扩展】

静态代理

  • 我们在不修改业务的情况下想要给它增加一些功能,这就需要使用代理模式。
  • 我们不会在原有业务上直接修改,为了避免修改导致程序不可逆转的破坏。
  • 三种角色:抽象角色-接口、真实角色-实现类和代理角色-代理类。
  • 真实角色和代理角色继承的是同一个抽象角色接口!

业务接口类

负责抽象出业务需要的功能。

//抽象业务
public interface UserService {
    public void add();
    public void delete();
    public void update();
    public void query();
}

业务的实现类

public class UserServiceImpl implements UserService{
    @Override
    public void add() {
        System.out.println("增加了一个用户");
    }
    @Override
    public void delete() {
        System.out.println("删除了一个用户");
    }
    @Override
    public void update() {
        System.out.println("修改了一个用户");
    }
    @Override
    public void query() {
        System.out.println("查询了一个用户");
    }
}

代理类

假如我们现在要给业务增加一个新的功能-输出日志功能,我们需要通过一个代理类来实现 ,而不是直接在旧业务上修改代码。

我们增加一个 log 方法(拓展功能),我们需要一个 set 方法来使代理能够通过旧的实现类调用旧的业务。

//代理实现增删改查
public class UserServiceProxy implements UserService{
    UserServiceImpl userService;
    public void setUserService(UserServiceImpl userService) {
        this.userService = userService;
    }
    @Override
    public void add() {
        log("add");
        userService.add();
    }
    @Override
    public void delete() {
        log("delete");
        userService.delete();
    }
    @Override
    public void update() {
        log("update");
        userService.update();
    }
    @Override
    public void query() {
        log("query");
        userService.query();
    }
    public void log(String message){
        System.out.println("使用了" + message + "方法");
    }
}

测试

这样我们的只需要给代理设置旧业务的实现类就实现了业务的功能扩展。

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

动态代理

  • 动态代理个静态代理角色一样(抽象角色-接口、真实角色-实现类和代理角色-代理类)
  • 动态代理的代理类是通过反射动态生成的!
  • 动态代理按照实现可以分我:基于接口的 和 基于类的动态代理。
  • 基于接口:JDK 动态代理
  • 基于类:cglib
  • 需要了解两个类:Proxy:代理、InvocationHandler:调用处理程序。
  • 一个动态代理类就是一个接口!
  • 一个动态代理类可以代理多个真实角色类,只需要继承同一个业务接口即可。
  • 使用动态代理可以大大减少代码量!因为它使用了反射!

Proxy:

Proxy 一共只有4个方法:

 

InvocationHandler:

InvocationHandler是一个接口!

InvocationHandler 整个类里只有一个方法:invoke方法。

动态代理的实现

抽象角色

//抽象业务
public interface UserService {
    public void add();
    public void delete();
    public void update();
    public void query();
}

真实角色

public class UserServiceImpl implements UserService {
    @Override
    public void add() {
        System.out.println("增加了一个用户");
    }
    @Override
    public void delete() {
        System.out.println("删除了一个用户");
    }
    @Override
    public void update() {
        System.out.println("修改了一个用户");
    }
    @Override
    public void query() {
        System.out.println("查询了一个用户");
    }
}

代理角色

使用 Object 作为抽象角色,这样这一个代理类就可以当做工具类来给任何真实角色进行功能扩展!

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//代理处理程序
public class ProxyInvocationHandler implements InvocationHandler {
    //被代理的接口
    private Object target;
    public void setUserService(Object target) {
        this.target = target;
    }
    //生成并得到代理类
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
    }
    //处理代理实例,调用抽象接口的方法,并返回结果
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //动态代理的本质就是使用反射机制实现!
        fun1();
        log(method.getName());
        Object result = method.invoke(target, args);
        fun2();
        return result;
    }
    public void fun1(){
        System.out.println("扩展功能1");
    }
    public void fun2(){
        System.out.println("扩展功能2");
    }
    public void log(String message){
        System.out.println("执行了" + message + "方法");
    }
}

测试

public class Client {
    public static void main(String[] args) {
        //真实角色
        UserServiceImpl userService = new UserServiceImpl();
        //代理角色
        ProxyInvocationHandler handler = new ProxyInvocationHandler();
        //设置要代理的真实对象
        handler.setUserService(userService);
        //动态生成代理类
        UserService proxy = (UserService) handler.getProxy();
        proxy.add();
        proxy.delete();
    }
}

输出结果:

扩展功能1
执行了add方法
增加了一个用户
扩展功能2
扩展功能1
执行了delete方法
删除了一个用户
扩展功能2


相关文章
|
7月前
|
弹性计算 网络协议 数据可视化
2026年阿里云我的世界(MC)服务器一键部署详细教程
2026年,阿里云通过“计算巢”平台实现《我的世界》服务器一键部署:无需技术基础,几分钟完成开服。支持Java/基岩版、整合包及自定义配置,提供稳定低延迟服务。图文教程详尽易操作,新手也能轻松搭建专属世界。
5776 5
|
9月前
|
XML Dubbo Java
|
SQL 数据可视化 BI
挖掘QuickBI产品的独特价值——模板市场一键应用篇
模板市场一键应用的独特价值在于: - 所见即所得、丰富的数据看板模板参考,提效业务人员工作方式及时间,对于数据人来说,日常大量的数据需要分析,追求更快地赋能业务决策,同时可以有效降低设计数据看板的时长耗用,是BI产品很重要的一项落地企业业务的能力; - 一键应用按钮减少了业务人员对产品的学习成本、操作成本; - 拖拉拽字段的操作本身是敏捷BI工具相较于其它数据处理方式(如SQL、Python、Excel)的一大超越,但替换数据集的支持直接节省了用户进行拖拉拽,可谓又是一增效点。同时也可以帮助日常业务人员(非专业数据处理人员)快速理解他需要提供的分析数据的数据类型。
373 1
|
Arthas 监控 Java
Arthas thread(查看当前JVM的线程堆栈信息)
Arthas thread(查看当前JVM的线程堆栈信息)
2352 10
|
存储 Kubernetes API
k8s学习-ConfigMap(创建、使用、更新、删除等)
k8s学习-ConfigMap(创建、使用、更新、删除等)
4248 0
|
存储 Kubernetes 应用服务中间件
应用存储和持久化数据卷:核心知识(二)|学习笔记
快速学习应用存储和持久化数据卷:核心知识(二)
265 0
应用存储和持久化数据卷:核心知识(二)|学习笔记
|
设计模式 Java 数据库连接
Spring高手之路7——事件机制与监听器的全面探索
本篇文章为你详细解析了Spring的事件机制,包括了Spring事件模型的四个核心概念:事件源、事件、广播器、监听器。我们通过深入浅出的实例解析了如何自定义事件和监听器,以及如何在实际项目中应用。最后,我们还详细探讨了监听器和Bean的生命周期的关系。无论你是Spring初学者,还是有一定经验的开发者,阅读本文都将帮助你更深入地理解Spring的事件机制和监听器,掌握Spring框架的核心技术。
2337 0
Spring高手之路7——事件机制与监听器的全面探索
|
SQL XML 关系型数据库
PostgreSQL 和openGauss错误代码整理(一)
PostgreSQL 和openGauss错误代码整理
1101 0
|
Serverless
Aliyun Serverless VSCode Extension v1.12.0 发布
Aliyun Serverless VSCode Extension 是阿里云 Serverless 产品 函数计算 Function Compute 的 VSCode 插件,该插件结合了函数计算 Fun 工具以及函数计算 SDK ,是一款 VSCode 图形化开发调试函数计算以及操作函数计算资源的工具。
1184 0

热门文章

最新文章