代理设计模式

代理设计模式

1. 静态代理模式(基于接口的代理)

1. 前提条件

  • 代理对象
    • 对被代理对象中的方法再不修改其源代码的情况小进行增强,要实现被代理接口
  • 被代理对象
    • 该对象中包含了被代理方法的具体实现,要实现被代理接口
  • 被代理接口
    • 该接口中包含了要被代理的抽象方法

2. 案例需求说明

用户要进行登录操作,在登录操作过程中进行日志的记录

3. 创建的三个前提条件

  1. 代理对象:ClientRequestProxy
  2. 被代理对象:ClientRequest
  3. 被代理接口:Client

1. 被代理接口:Client

/**
 * 处理的客户端接口,定义一些公共方法标准
 */
public interface Client {
    // 登录方法
    abstract public void login();
}

2. 被代理对象:ClientRequest

/**
 * 处理请求的客户端,实现Client
 * 使用代理类对该客户端的请求进行代理,给处理请求的方法进行一定的增强
 * 在不修改原方法的前提下进行日志的记录
 */
public class ClientRequest implements Client {

    /**
     * 模拟用户进行登录操作
     */
    @Override
    public void login(){
        System.out.println("用户登录中...");
    }

    /**
     * 测试静态代理模式
     */
    public static void main(String[] args) {
        // 被代理对象
        ClientRequest clientRequest = new ClientRequest();
        // 代理对象,并且将被代理对象作为参数传递到代理对象中
        ClientRequestProxy clientRequestProxy = new ClientRequestProxy(clientRequest);
        // 调用登录方法
        clientRequestProxy.login();
    }
}

3. 代理对象:ClientRequestProxy

/**
 * 代理处理客户端请求的代理类,实现Client
 */
public class ClientRequestProxy implements Client {

    // 创建一个客户端对象,用于接收通过构造函数传递进来的对象
    private Client client;

    /**
     * 创建代理类的有参构造,传入客户端对象,实现了客户端接口的所有类都可以传入
     * @param client 客户端对象
     */
    public ClientRequestProxy(Client client) {
        this.client = client;
    }
	/**
     * 无参构造
     */
    public ClientRequestProxy() {}

    /**
     * 对用户登录操作进行代理
     */
    @Override
    public void login() {
        System.out.println("静态代理代理开始...");
        System.out.println("登录开始,开始记录日志...");
        this.client.login();
        System.out.println("登录结束,记录日志结束...");
    }
}

4. 测试结果

2. JDK动态代理设计模式(基于接口的代理)

基于JDK实现的动态代理模式(基于JDK的动态代理模式格式相对是固定的,要修改的地方几个)
基于JDK的动态代理是调用 java.lang.reflect.Proxy 中的 newProxyInstance方法实现的,
在调用该方法传入三个参数
1.目标对象使用的类加载器:目标对象.getClass().getClassLoader()
2.目标对象实现的接口类型:目标对象.getClass().getInterfaces()
3.事情处理:执行目标对象的方法时,会触发事情处理器方法,会把当前执行的目标对象方法作为参数传入,里面就是具体增强业务

1. 前提条件

  1. 被代理接口
    1. 包含需要代理的抽象方法
  2. 被代理对象(目标对象)
    1. 包含需要代理的方法的具体业务逻辑,需要实现被代理接口
  3. 代理对象(基于JDK创建)
    1. 基于JDK的代理创建,不需要实现代理接口,通过反射的方式动态获取到目标对象进行生成代理对象

2. 案例需求说明

​ 用户要进行登录操作,在登录操作过程中进行日志的记录

3. 创建三个前提条件

  1. 代理对象:ProxyFactory(基于JDK创建)
  2. 被代理对象:ClientRequest
  3. 被代理接口:Client

1. 被代理接口Client

/**
 * 处理的客户端接口,定义一些公共方法标准
 */
public interface Client {
    // 登录方法
    abstract public void login();
}

2. 被代理对象:ClientRequest

/**
 * 处理请求的客户端,实现Client
 * 使用代理类对该客户端的请求进行代理,给处理请求的方法进行一定的增强
 * 在不修改原方法的前提下进行日志的记录
 *
 * @author : 可乐
 * @version : 1.0
 * @since : 2021/7/18 16:58
 */
@SuppressWarnings("all")
public class ClientRequest implements Client {

    /**
     * 模拟用户进行登录操作
     */
    @Override
    public void login() {
        System.out.println("用户登录中...");
    }

    /**
     * 测试静态代理模式
     */
    public static void main(String[] args) {
        // 被代理接口对象
        Client client = new ClientRequest();
        // 给目标对象,创建代理对象,内存中动态生成了代理对象(proxyInstance.getClass()可以查看到)
        Client proxyInstance = (Client) new ProxyFactory(client).getProxyInstance();
        // 通过生成的代理对调用需要增强的方法
        proxyInstance.login();
    }
}

3. 代理对象:ProxyFactory(基于JDK创建)

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

/**
 * 基于JDK实现的动态代理模式(基于JDK的动态代理模式格式相对是固定的,要修改的地方几个)
 * 基于JDK的动态代理是调用 java.lang.reflect.Proxy 中的 newProxyInstance方法实现的,
 * 在调用该方法传入三个参数
 * 1.目标对象使用的类加载器:目标对象.getClass().getClassLoader()
 * 2.目标对象实现的接口类型:目标对象.getClass().getInterfaces()
 * 3.事情处理:执行目标对象的方法时,会触发事情处理器方法,
 *   会把当前执行的目标对象方法作为参数传入,里面就是具体增强业务
 */
public class ProxyFactory {

    // 被代理对象,因为是动态代理,被代理的对象类型不确定,所以使用Object
    private Object target;

    // 创建代理类的有参构造,将被代理进行初始化
    public ProxyFactory(Object target) {
        this.target = target;
    }

    /**
     * 为目标对象生成代理对象
     * @return 生成的代理对象
     */
    public Object getProxyInstance() {

        /**
         * 使用JDK的代理方法生成代理对象
         *
         * 方法原型:
         *  public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
         *
         * 参数一:ClassLoader loader :  指定当前目标对象使用的类加载器, 获取加载器的方法固定
         * 参数二:Class<?>[] interfaces: 目标对象实现的接口类型,使用泛型方法确认类型
         * 参数三:InvocationHandler h :  事情处理,执行目标对象的方法时,会触发事情处理器方法, 会把当前执行的目标对象方法作为参数传入
         */
        Object object = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
                new InvocationHandler() {
                    /**
                     * 对被代理对象实现业务增强
                     * @param proxy
                     * @param method
                     * @param args
                     * @return
                     * @throws Throwable
                     */
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("JDK动态代理开始...");
                        System.out.println("开始记录日志...");
                        // 反射机制调用目标对象的方法
                        Object result = method.invoke(target, args);
                        System.out.println("记录日志结束...");
                        return result;
                    }
                });
        return object;
    }
}

4. 测试结果

3. Cglib代理模式(可以不基于接口进行动态代理)

1. 特点

cgilb代理的目标对象不需要实现接口,cglib代理会在内存中动态生成一个目标类的一个子类,在这个子类的继承上对方法进行增强操作。

2. 前提条件

  1. 被代理类(目标对象)
  2. cglib的jar包,创建一个类实现cglib中的MethodInterceptor接口中的intercept方法

3. 案例说明

用户要进行登录操作,在登录操作过程中进行日志的记录

4. 创建两个前提条件

1. 被代理对象

/**
 * 用户登录类
 */
public class UserLogin {
    // 用户登录方法
    public void login(){
        System.out.println("用户登录中...");
    }

    /**
     * 测试cglib代理
     */
    public static void main(String[] args) {
        // 创建被代理对象
        UserLogin userLogin = new UserLogin();
        // 创建代理对象,并且将被代理对象当做参数传入到代理对象的构造函数中
        UserLogin proxyFactory = (UserLogin)new ProxyFactory(userLogin).getProxyInstance();
        proxyFactory.login();
    }
}

2. 实现了cglib中MethodInterceptor接口

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

import java.lang.reflect.Method;

/**
 * 实现cglib中的MethodInterceptor接口中的intercept方法
 */
public class ProxyFactory implements MethodInterceptor {

    // 维护一个目标对象
    private Object target;

    // 构造器,传入一个被代理的对象
    public ProxyFactory(Object target) {
        this.target = target;
    }

    // 返回一个代理对象:  是 target 对象的代理对象
    public Object getProxyInstance() {
        // 1.创建一个工具类
        Enhancer enhancer = new Enhancer();
        // 2.设置父类
        enhancer.setSuperclass(target.getClass());
        // 3.设置回调函数
        enhancer.setCallback(this);
        // 4.创建子类对象,即代理对象
        return enhancer.create();
    }

    /**
     * 重写  intercept 方法,会调用目标对象的方法
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("Cglib代理模式开始...");
        System.out.println("开始记录日志...");
        Object returnVal = method.invoke(target, objects);
        System.out.println("记录日志结束...");
        return returnVal;
    }
}
posted on 2021-07-19 21:23  秃头靓仔-001  阅读(49)  评论(0编辑  收藏  举报