百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT技术 > 正文

Java设计模式-代理模式_java编写代理服务

wptr33 2025-02-21 15:39 32 浏览

代理模式定义:给目标对象提供一个代理对象,并且由代理对象控制对目标对象的访问。

代理模式分为两类:静态代理、动态代理。

  • 静态代理:在编译期间就确定代理类,代理类和被代理类在编译时就已经确定,需要针对每个被代理类编写一个代理类。
  • 动态代理:在运行时动态生成代理类。Java 中主要有基于接口的 JDK 动态代理和基于类的 CGLIB 动态代理。JDK 动态代理要求被代理类必须实现接口,通过java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口实现。CGLIB 代理不需要被代理类实现接口,通过继承被代理类来创建代理对象,被代理类不能为 final 类。

代理模式的应用场景:

功能增强:

  • 日志记录与性能监控:在不修改原有业务逻辑的情况下,通过代理在方法调用前后记录日志或监控性能。
  • 事务管理:在业务方法执行前后添加事务开启和提交等逻辑。

控制访问:

  • 远程代理:控制访问远程对象,为一个位于不同机器的 JVM 上的对象提供一个本地的代理对象,如远程方法调用(RMI)。
  • 虚拟代理:根据实际需要创建开销很大的对象,先创建一个消耗相对较小的对象表示较大的对象,大对象只在需要时才会被真正创建。
  • 保护代理:进行权限控制,用于对象有不同访问权限的情况。

代理模式的主要优点:

  • 职责清晰:将核心业务逻辑和辅助功能分离,如将日志记录、权限控制等功能从核心业务中分离到代理类中。
  • 解耦合:客户端和目标对象之间通过代理对象进行交互,降低了两者之间的耦合度。
  • 可扩展性好:可以在不修改目标类代码的情况下,通过代理类方便地添加新功能。
  • 便于维护和管理:将横切关注点(如日志、事务等)集中在代理类中,便于统一维护和管理。
  • 增强代码的可测试性:在单元测试中,可以使用代理对象模拟目标对象的行为,方便对相关代码进行测试。

代理模式Java样例:

静态代理:

// 定义接口
interface Rent {
    void rent();
}

// 目标类
class Host implements Rent {
    // 房东出租房子的方法
    @Override
    public void rent() {
        System.out.println("房东出租房子。");
    }
}

// 代理类
class StaticProxy implements Rent {
    // 持有目标对象的引用
    private Rent rent;

    // 构造方法,传入目标对象
    public StaticProxy(Rent rent) {
        this.rent = rent;
    }

    // 实现rent方法,在调用目标对象的方法前后添加额外逻辑
    @Override
    public void rent() {
        seeHouse();
        rent.rent();
    }

    // 代理类的额外方法,带房客看房
    public void seeHouse() {
        System.out.println("中介带房客看房子。");
    }
}

// 测试类
class Test {
    public static void main(String[] args) {
        // 创建目标对象
        Rent host = new Host();
        // 创建代理对象,将目标对象传入
        StaticProxy proxy = new StaticProxy(host);
        // 通过代理对象调用方法
        proxy.rent();
    }
}


动态代理-JDK 动态代理

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

// 定义接口
interface Rent {
    void rent();
}

// 目标类
class Host implements Rent {
    // 房东出租房子的方法
    @Override
    public void rent() {
        System.out.println("房东出租房子。");
    }
}

// 代理实例的调用处理程序,实现InvocationHandler接口
class ProxyInvocationHandler implements InvocationHandler {
    // 被代理的对象
    private Object target;

    // 设置被代理的对象
    public void setTarget(Object target) {
        this.target = target;
    }

    // 当通过代理对象调用方法时,会调用此方法
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 在调用目标对象的方法前添加额外逻辑
        System.out.println("中介带房客看房子。");
        // 调用目标对象的方法
        Object result = method.invoke(target, args);
        // 在调用目标对象的方法后添加额外逻辑
        System.out.println("中介帮助签合同。");
        return result;
    }
}

// 测试类
class Test {
    public static void main(String[] args) {
        // 创建目标对象
        Host host = new Host();
        // 创建代理实例的调用处理程序
        ProxyInvocationHandler handler = new ProxyInvocationHandler();
        // 设置被代理的对象
        handler.setTarget(host);
        // 创建代理对象
        Rent proxy = (Rent) Proxy.newProxyInstance(
                host.getClass().getClassLoader(),
                host.getClass().getInterfaces(),
                handler
        );
        // 通过代理对象调用方法
        proxy.rent();
    }
}


动态代理-CGLIB 动态代理

1 在pom中添加cglib的依赖


    cglib
    cglib
    3.3.0

2 定义目标类

public class UserService {
    public void addUser(String username) {
        System.out.println("User " + username + " added.");
    }
}

3 使用cglib创建代理类

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class CglibDemo {
    public static void main(String[] args) {
        // 创建Enhancer对象
        Enhancer enhancer = new Enhancer();
        // 设置要代理的目标类
        enhancer.setSuperclass(UserService.class);
        // 设置回调函数,即方法拦截器
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args, MethodProxy proxy) throws Throwable {
                // 在调用目标方法前执行的逻辑
                System.out.println("Before method: " + method.getName());
                // 调用目标类的方法
                Object result = proxy.invokeSuper(obj, args);
                // 在调用目标方法后执行的逻辑
                System.out.println("After method: " + method.getName());
                return result;
            }
        });
        // 创建代理对象
        UserService userService = (UserService) enhancer.create();
        // 调用代理对象的方法
        userService.addUser("Alice");
    }
}

相关推荐

redis的八种使用场景

前言:redis是我们工作开发中,经常要打交道的,下面对redis的使用场景做总结介绍也是对redis举报的功能做梳理。缓存Redis最常见的用途是作为缓存,用于加速应用程序的响应速度。...

基于Redis的3种分布式ID生成策略

在分布式系统设计中,全局唯一ID是一个基础而关键的组件。随着业务规模扩大和系统架构向微服务演进,传统的单机自增ID已无法满足需求。高并发、高可用的分布式ID生成方案成为构建可靠分布式系统的必要条件。R...

基于OpenWrt系统路由器的模式切换与网页设计

摘要:目前商用WiFi路由器已应用到多个领域,商家通过给用户提供一个稳定免费WiFi热点达到吸引客户、提升服务的目标。传统路由器自带的Luci界面提供了工厂模式的Web界面,用户可通过该界面配置路...

这篇文章教你看明白 nginx-ingress 控制器

主机nginx一般nginx做主机反向代理(网关)有以下配置...

如何用redis实现注册中心

一句话总结使用Redis实现注册中心:服务注册...

爱可可老师24小时热门分享(2020.5.10)

No1.看自己以前写的代码是种什么体验?No2.DooM-chip!国外网友SylvainLefebvre自制的无CPU、无操作码、无指令计数器...No3.我认为CS学位可以更好,如...

Apportable:拯救程序员,IOS一秒变安卓

摘要:还在为了跨平台使用cocos2d-x吗,拯救objc程序员的奇葩来了,ApportableSDK:FreeAndroidsupportforcocos2d-iPhone。App...

JAVA实现超买超卖方案汇总,那个最适合你,一篇文章彻底讲透

以下是几种Java实现超买超卖问题的核心解决方案及代码示例,针对高并发场景下的库存扣减问题:方案一:Redis原子操作+Lua脚本(推荐)//使用Redis+Lua保证原子性publicbo...

3月26日更新 快速施法自动施法可独立设置

2016年3月26日DOTA2有一个79.6MB的更新主要是针对自动施法和快速施法的调整本来内容不多不少朋友都有自动施法和快速施法的困扰英文更新日志一些视觉BUG修复就不翻译了主要翻译自动施...

Redis 是如何提供服务的

在刚刚接触Redis的时候,最想要知道的是一个’setnameJhon’命令到达Redis服务器的时候,它是如何返回’OK’的?里面命令处理的流程如何,具体细节怎么样?你一定有问过自己...

lua _G、_VERSION使用

到这里我们已经把lua基础库中的函数介绍完了,除了函数外基础库中还有两个常量,一个是_G,另一个是_VERSION。_G是基础库本身,指向自己,这个变量很有意思,可以无限引用自己,最后得到的还是自己,...

China's top diplomat to chair third China-Pacific Island countries foreign ministers' meeting

BEIJING,May21(Xinhua)--ChineseForeignMinisterWangYi,alsoamemberofthePoliticalBureau...

移动工作交流工具Lua推出Insights数据分析产品

Lua是一个适用于各种职业人士的移动交流平台,它在今天推出了一项叫做Insights的全新功能。Insights是一个数据平台,客户可以在上面实时看到员工之间的交流情况,并分析这些情况对公司发展的影响...

Redis 7新武器:用Redis Stack实现向量搜索的极限压测

当传统关系型数据库还在为向量相似度搜索的性能挣扎时,Redis7的RedisStack...

Nginx/OpenResty详解,Nginx Lua编程,重定向与内部子请求

重定向与内部子请求Nginx的rewrite指令不仅可以在Nginx内部的server、location之间进行跳转,还可以进行外部链接的重定向。通过ngx_lua模块的Lua函数除了能实现Nginx...