代理设计模式
1. 静态代理模式(基于接口的代理)
1. 前提条件
- 代理对象
- 对被代理对象中的方法再不修改其源代码的情况小进行增强,要实现被代理接口
- 被代理对象
- 该对象中包含了被代理方法的具体实现,要实现被代理接口
- 被代理接口
- 该接口中包含了要被代理的抽象方法
2. 案例需求说明
用户要进行登录操作,在登录操作过程中进行日志的记录
3. 创建的三个前提条件
- 代理对象:ClientRequestProxy
- 被代理对象:ClientRequest
- 被代理接口: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. 前提条件
- 被代理接口
- 包含需要代理的抽象方法
- 被代理对象(目标对象)
- 包含需要代理的方法的具体业务逻辑,需要实现被代理接口
- 代理对象(基于JDK创建)
- 基于JDK的代理创建,不需要实现代理接口,通过反射的方式动态获取到目标对象进行生成代理对象
2. 案例需求说明
用户要进行登录操作,在登录操作过程中进行日志的记录
3. 创建三个前提条件
- 代理对象:ProxyFactory(基于JDK创建)
- 被代理对象:ClientRequest
- 被代理接口: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. 前提条件
- 被代理类(目标对象)
- 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;
}
}