设计模式学习08----之代理模式

简介: 今天接着学习设计模式,今天要学习的模式是代理模式。代理模式的应用场景有很多,例如:生活中的代购,明星的经纪人。

概述


今天接着学习设计模式,今天要学习的模式是代理模式。代理模式的应用场景有很多,例如:生活中的代购,明星的经纪人。


定义与结构

代理模式(Proxy)是一种设计模式,为其他对象提供一种代理以控制对这个对象的访问。

在软件开发中有个原则:就是开-闭原则,对新增开放,对修改关闭。尽量不要去修改已经写好的代码。如果需要可以增加一个代理类,来扩展目标代码。


实例

假设某人需要购买一块不在国内销售的化妆品,这时他找到了一个代购来帮他买。

ISubject 买化妆品的接口类,

RealSubject 某人

Proxy 代理类


静态代理模式

静态代理模式,是目标类和代理类都要实现相同的接口。代理角色依赖于真实角色,因为代理角色内部有对真实角色的引用,代理在操作真实角色去执行动作时,必须要知道是哪个真实角色。

接口:

public interface ISubject {
    /**
     *
     * @return
     */
    void buyCosmetics();
}


目标类

public class RealSubject  implements ISubject {
    @Override
    public void buyCosmetics() {
        System.out.println("买某种进口化妆品");
    }
}


代理类:

public class Proxy implements ISubject {
    //接收目标对象
    private ISubject target;
    public Proxy(ISubject iSubject) {
        this.target = iSubject;
    }
    @Override
    public void buyCosmetics() {
        target.buyCosmetics();
    }
}

测试类

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


静态代理类的优缺点:

优点:可以在不修改目标类的前提下扩展目标类

缺点:每个目标类都对应一个代理类,当目标类过多时,会导致类急剧增加,而一旦接口增加方法,目标类都代理类都要维护。

针对这个缺点,动态代理可以解决


JDK动态代理

动态代理的特点


代理对象不需要实现接口

代理对象的生成是利用JDK的API,动态的在内存中创建代理对象(需要我们制定代理对象/目标对象实现的接口类型)

动态代理也叫做:JDK代理,接口代理。

JDK中生成代理对象的API

代理类所在的包是 :java.lang.reflect.Proxy

JDK 实现代理只需要调用newProxyInstance方法,该方法需要接受三个参数。

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h){}


该方法是Proxy类中的静态方法, 且接收的三个参数依次为:

ClassLoader loader:指定当前目标对象使用的类加载器,获取类加载器的方法是RealSubject.class.getClassLoader()

Class[] interfaces:目标对象实现的接口的类型,使用泛型方式确认类型。

InvocationHandler h:事件处理,执行目标对象的方法是,会触发时间处理器的方法。会把当前执行目标的方法作为参数传入。

代码示例:

接口类ISubject.java 以及接口实现类,目标对象RealSubject也是一样的,不做修改,在此基础上增加一个代理工厂类(ProxyFactory),将代理类写在这个地方,然后在测试类中先建立目标对象和代理对象的联系,然后代用代理对象中的同名方法。

代理工厂类

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
 * @author xiang.wei
 */
public class ProxyFactory {
    /**
     * 目标对象
     */
    private Object target;
    public ProxyFactory(Object target) {
        this.target = target;
    }
    /**
     * 给目标对象生成代理对象
     * @return
     */
    public Object getProxyInstance() {
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("前置处理");
                        //执行目标对象方法
                        Object returnValue = method.invoke(target, args);
                        System.out.println("后置处理");
                        return returnValue;
                    }
                }
        );
    }
}


如上,该代理工程实现了InvocationHandler接口,并且实现了接口中的invoke方法,就是在这个方法中加入切面的。

测试类:

public class Client {
    public static void main(String[] args) {
        ISubject target =  new RealSubject();
        ProxyFactory proxyFactory = new ProxyFactory(target);
        ISubject proxy = (ISubject) proxyFactory.getProxyInstance();
        proxy.buyCosmetics();
    }
}


总结:

代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能使用动态代理。


Cglib动态代理


以上的静态代理和动态代理模式都要求目标对象是实现一个接口的目标对象,但是有时候目标对象只是一个单独的对象。并没有实现任何的接口,这个时候就可以使用以目标对象子类的方式来实现代理,这种方法就叫做:Cglib代理。

Cglib 代理,也叫做子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展,


JDK 的动态代理有一个限制,就是使用动态代理的对象必须实现一个或者多个接口,如果代理没有实现接口的类,可以使用Cglib实现。


Cglib 是一个强大的高性能的代码生成包,它可以在运行期扩展Java类与实现Java接口,他广泛的被许多AOP的框架使用,例如,Spring AOP和synaop,为他们提供方法的interception(拦截)


Cglib 包的底层是通过使用一个小而快的字节码处理框架ASM来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部接口包括class文件的格式和指令集都很熟悉。

Cglib 子类代理实现方法:


需要引入cglib的jar文件,但是Spring的核心包中已经包括了Cglib功能,所以直接添加spring-core的依赖即可。


添加完依赖之后,就可以在内存中动态的构建子类。


代理类不能为final,否则报错。


目标对象的方法如果是final/static, 那么就不会被拦截,即不会执行目标对象额外的业务方法。

代码示例:

目标对象类:

package com.proxy.cglib;
/**
 * @author xiang.wei
 * @create 2018/5/28 15:02
 */
public class RealSubject {
    public void buyCosmetics() {
        System.out.println("买某种进口化妆品");
    }
}


Cglib 代理类


package com.proxy.cglib;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
 * @author xiang.wei
 * @create 2018/5/28 15:03
 */
public class ProxyFactory implements MethodInterceptor{
    //维护目标对象
    private Object target;
    public ProxyFactory(Object target) {
        this.target = target;
    }
    /**
     * 给目标对象创建一个代理对象
     * @return
     */
    public Object getProxyInstance() {
        //1.工具类
        Enhancer enhancer = new Enhancer();
        //2.设置代理目标
        enhancer.setSuperclass(target.getClass());
        //3.设置回调函数
        enhancer.setCallback(this);
        //4.创建子类(代理对象)
        return enhancer.create();
    }
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("前置处理");
        Object returnValue = methodProxy.invoke(target, objects);
        System.out.println("后置处理");
        return returnValue;
    }
}


测试类:

public class Client {
    public static void main(String[] args) {
        //目标对象
        RealSubject realSubject = new RealSubject();
        //代理对象
        RealSubject proxy = (RealSubject) new ProxyFactory(realSubject).getProxyInstance();
        proxy.buyCosmetics();
    }
}


总结:

如果代理对象有实现接口,那么使用JDK代理,如果目标对象没有实现接口,那么使用Cglib代理。


参考

https://www.cnblogs.com/cenyu/p/6289209.html


相关文章
|
设计模式 Java 数据库连接
【设计模式】【结构型模式】代理模式(Proxy)
一、入门 什么是代理模式? 代理模式(Proxy Pattern)是一种结构型设计模式,允许你提供一个代理对象来控制对另一个对象的访问。 代理对象在客户端和目标对象之间起到中介作用,可以在不改变目标对
357 10
|
设计模式 缓存 Java
「全网最细 + 实战源码案例」设计模式——代理模式
代理模式(Proxy Pattern)是一种结构型设计模式,通过代理对象控制对目标对象的访问并添加额外功能。它分为静态代理和动态代理,后者包括JDK动态代理和CGLIB动态代理。JDK动态代理基于接口反射生成代理类,而CGLIB通过继承目标类生成子类。代理模式适用于延迟初始化、访问控制、远程服务、日志记录和缓存等场景,优点是职责分离、符合开闭原则和提高安全性,缺点是增加系统复杂性。
393 25
|
设计模式 前端开发 数据安全/隐私保护
前端必须掌握的设计模式——代理模式
代理模式(Proxy Pattern)是一种结构型设计模式,通过引入“替身”对象来间接访问真实对象,从而解耦并提升性能和安全性。例如,知名艺人复出后,经纪人作为代理筛选商单,确保只处理符合团队利益的请求。代码实现中,定义接口`IService`,艺人和经纪人都实现该接口,经纪人在访问时进行过滤和转发。代理模式常用于权限控制、性能优化等场景,如前端中的Tree-shaking和ES6的Proxy构造方法。
前端必须掌握的设计模式——代理模式
|
设计模式 缓存 安全
设计模式——代理模式
静态代理、JDK动态代理、Cglib 代理
设计模式——代理模式
|
设计模式 缓存 Java
【十一】设计模式~~~结构型模式~~~代理模式(Java)
文章详细介绍了代理模式(Proxy Pattern),这是一种对象结构型模式,用于给对象提供一个代理以控制对它的访问。文中阐述了代理模式的动机、定义、结构、优点、缺点和适用环境,并探讨了远程代理、虚拟代理、保护代理等不同代理形式。通过一个商务信息查询系统的实例,展示了如何使用代理模式来增加身份验证和日志记录功能,同时保持客户端代码的无差别对待。此外,还讨论了代理模式在分布式技术和Spring AOP中的应用,以及动态代理的概念。
【十一】设计模式~~~结构型模式~~~代理模式(Java)
|
设计模式 Java 数据安全/隐私保护
Java设计模式-代理模式(7)
Java设计模式-代理模式(7)
174 2
|
设计模式
设计模式的基础问题之代理模式在工作中的问题如何解决
设计模式的基础问题之代理模式在工作中的问题如何解决
186 0
|
设计模式 算法 Go
iLogtail设计模式问题之代理模式在iLogtail中是如何应用的
iLogtail设计模式问题之代理模式在iLogtail中是如何应用的
|
设计模式 缓存 JavaScript
js设计模式【详解】—— 代理模式
js设计模式【详解】—— 代理模式
174 0
|
设计模式 监控 安全
设计模式之代理模式(Java)
设计模式之代理模式(Java)