龙空技术网

Java的设计模式(七):代理模式,让你的代码优雅灵活!

Code404 147

前言:

此时姐妹们对“java的代码区”大致比较关心,姐妹们都想要分析一些“java的代码区”的相关内容。那么小编同时在网上汇集了一些有关“java的代码区””的相关知识,希望咱们能喜欢,姐妹们快快来了解一下吧!

一、 代理模式概述

代理模式是一种为其他对象提供一种代理以控制对这个对象的访问的设计模式。它通常是为了实现控制访问、缓冲、延迟加载、日志记录等一系列目的而被使用。代理模式有两种实现方式:静态代理和动态代理。

1、静态代理

静态代理也被称为编译时代理,它要求代理对象在编译期间就已经确定,代理类和委托类的关系在编译阶段就已经确定下来了。静态代理的优点是结构简单,易于理解和掌握,缺点是可扩展性差,每一个代理只能为一个类服务。

2、动态代理

动态代理也被称为运行时代理,它要求代理对象在运行时才能确定,代理类和委托类的关系在运行时才能确定下来。动态代理的优点是具有很高的可扩展性,缺点是复杂度高,需要使用一定的反射技术来实现。

二、 代理模式原理

代理模式的实现通常包括三种角色:抽象角色、代理角色和真实角色。

抽象角色(Subject)定义了代理角色和真实角色之间共同的接口,这样一来代理角色就可以使用相同的方式来操作真实角色。

代理角色(Proxy)持有一个真实角色的引用,在请求达到真实角色之前,代理角色会先进行某些处理,例如对请求进行验证、鉴权、限流等,然后才将请求转发给真实角色。

真实角色(Real Subject)是代理角色要访问的对象,它实现了抽象角色指定的接口。

在Java语言中,静态代理是通过实现同一个接口来实现的,这样代理类和委托类就共享同样的接口。动态代理则是通过Java反射机制,动态生成代理类的字节码文件,并将其加载到JVM中,使得代理类可以动态地代理任何实现了某个接口的委托类。

三、 Java静态代理代码示例

接下来我们来看一个简单的Java静态代理的代码示例。

1、定义接口

首先我们需要定义一个共同的接口:

public interface Subject {    public void request();}

2、实现抽象角色

真实角色:

public class RealSubject implements Subject {    @Override    public void request() {        System.out.println("执行真实的请求...");    }}

代理角色:

public class Proxy implements Subject {    private RealSubject realSubject;    public Proxy(RealSubject realSubject) {        this.realSubject = realSubject;    }    @Override    public void request() {        System.out.println("执行代理的操作...");        realSubject.request();        System.out.println("代理操作执行完毕");    }}

3、测试

通过以下代码测试:

public class StaticProxyTest {    public static void main(String[] args) {        RealSubject realSubject = new RealSubject();        Proxy proxy = new Proxy(realSubject);        proxy.request();    }}

在这个示例中,RealSubject 是真实角色,Proxy 是代理角色,通过实现相同的接口来共享同样的方法。对于客户端来说,它不需要知道代理类和真实类的区别,由代理类来完成一些操作,例如对请求进行验证、鉴权、限流等,然后再将请求转发给真实角色。

四、 Java动态代理代码示例

下面我们来看一下Java动态代理的代码示例。

1、定义接口

首先我们依然需要定义一个公共接口:

public interface Subject {    void request();}

2、实现抽象角色

真实角色:

public class RealSubject implements Subject {    @Override    public void request() {        System.out.println("执行真实的请求...");    }}

3、实现代理角色

动态代理需要实现 InvocationHandler 接口,并重写 invoke 方法,这个方法会在代理接收到请求时被调用。这里我们定义了一个 MyInvocationHandler 类来实现 InvocationHandler 接口:

public class MyInvocationHandler implements InvocationHandler {    private Object obj;    public MyInvocationHandler(Object obj) {        this.obj = obj;    }    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        System.out.println("执行代理的操作...");        Object result = method.invoke(obj, args);        System.out.println("代理操作执行完毕");        return result;    }}

4、测试

通过以下代码测试:

public class DynamicProxyTest {    public static void main(String[] args) {        RealSubject realSubject = new RealSubject();        // 创建MyInvocationHandler对象,将RealSubject对象传入        InvocationHandler handler = new MyInvocationHandler(realSubject);        // 创建代理对象,使用Proxy.newProxyInstance()方法,实现动态代理。        // 传入ClassLoader、接口、以及MyInvocationHandler对象        Subject proxySubject = (Subject) Proxy.newProxyInstance(handler.getClass().getClassLoader(),                realSubject.getClass().getInterfaces(), handler);        // 调用代理对象的request()方法        proxySubject.request();    }}

与静态代理不同,动态代理在运行时创建代理类,并将它的实现委托给InvocationHandler,InvocationHandler在代理接收到请求时被调用来处理请求。这里我们定义了一个MyInvocationHandler类来实现InvocationHandler接口,并传入RealSubject对象来进行代理。

五、 Spring Boot源码中的代理模式应用

在 Spring Boot 框架中,最核心的就是它的 AOP(面向切面编程)的功能。Spring AOP原理是基于动态代理的实现方式,通过生成代理对象,并在代理对象中增加相应的通知逻辑来实现横向切面功能。Spring容器中每个Bean都会自动创建一个代理对象,在代理对象执行相应方法时会自动执行切面逻辑。

Spring AOP 底层使用了 JDK 动态代理和 CGLIB 动态代理两种技术。在 JDK 动态代理中,代理对象必须实现一个上面示例中的 InvocationHandler 接口;而在 CGLIB 动态代理中,代理对象可以是任何普通类。Spring AOP会根据使用场景自动选择相应的代理技术,以实现最佳的性能和灵活性。

关于 Spring AOP,可查看我的其它文章了解详细内容:

【Spring Boot中AOP介绍(一)原来AOP是这么回事】

【Spring Boot的AOP(二)五种通知方法是这么用的】

【SpringBoot的AOP(三)五大通知方式的顺序和异常你都知道吗?】

对于本文中的内容,不知道你有没有什么看法,欢迎在评论区里留言。如果你对我的文章内容感兴趣,欢迎点击关注,谢谢支持![谢谢][谢谢][谢谢]

文章链接:【Java程序员必须掌握的15个设计模式,特点和使用场景汇总整理!】

标签: #java的代码区