共计 8299 个字符,预计需要花费 21 分钟才能阅读完成。
Java 23 种设计模式之代理模式
一:简介
设计模式分为三大类:
创立型模式,共五种:工厂办法模式(已讲过)、形象工厂模式(已讲过)、单例模式(已讲过)、建造者模式(已讲过)、原型模式(已讲过)。
结构型模式,共七种:适配器模式 (已讲过)、装璜器模式、 代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:策略模式、模板办法模式、观察者模式(已讲过)、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
代理模式(Proxy)是通过代理对象拜访指标对象,这样能够在指标对象根底上加强额定的性能,如增加权限,访问控制和审计等性能
。
Java 代理分为 动态代理 和动静代理 和Cglib 代理
二:动态代理
动态代理在应用时, 须要定义接口或者父类, 被代理对象与代理对象一起实现雷同的接口或者是继承雷同父类.
接口类 AdminService 接口
这是一个指标
public interface AdminService {
// 我定义一个用户服务权限接口
// 定义了一个更新办法
void update();
// 定义了一个查找办法,查找返回数据
Object find();}
实现类 AdminServiceImpl
/** 动态接口的实现类 */
public class AdminServiceImpl implements AdminService{
@Override
public void update() {System.out.println("我曾经更新了零碎");
}
@Override
public Object find() {System.out.println("我曾经查看了零碎");
return new Object();}
}
最要害的代理类 AdminServiceProxy,动态代理也要实现目标接口 AdminService
public class AdminServiceProxy implements AdminService {
private AdminService adminService;
public AdminServiceProxy(AdminService adminService) {this.adminService= adminService;}
@Override
public void update() {System.out.println("判断用户是否有权限进行 update 操作");
adminService.update();
System.out.println("记录用户执行 update 操作的用户信息、更改内容和工夫等");
}
@Override
public Object find() {System.out.println("判断用户是否有权限进行 find 操作");
System.out.println("记录用户执行 find 操作的用户信息、查看内容和工夫等");
return adminService.find();}
}
调用
// 创立一个指标对象
AdminService adminService=new AdminServiceImpl();
// 构建一个代理对象
AdminServiceProxy proxy= new AdminServiceProxy(adminService);
// 调用更新
proxy.update();
System.out.println("=============================");
proxy.find()
// 后果
System.out: 判断用户是否有权限进行 update 操作
System.out: 我曾经更新了零碎
System.out: 记录用户执行 update 操作的用户信息、更改内容和工夫等
System.out: =============================
System.out: 判断用户是否有权限进行 find 操作
System.out: 记录用户执行 find 操作的用户信息、查看内容和工夫等
System.out: 我曾经查看了零碎
总结:
动态代理模式在不扭转指标对象的前提下,实现了对指标对象的性能扩大。
有余:动态代理实现了指标对象的所有办法,一旦指标接口减少办法,代理对象和指标对象都要进行相应的批改,减少保护老本。
三:JDK 动静代理
为解决动态代理对象必须实现接口的所有办法的问题,Java 给出了动静代理,动静代理具备如下特点:
1.Proxy 对象不须要 implements 接口;
2.Proxy 对象的生成利用 JDK 的 Api,在 JVM 内存中动静的构建 Proxy 对象。须要应用 java.lang.reflect.Proxy 类的
/**
* Returns an instance of a proxy class for the specified interfaces
* that dispatches method invocations to the specified invocation
* handler.
* @param loader the class loader to define the proxy class
* @param interfaces the list of interfaces for the proxy class
* to implement
* @param h the invocation handler to dispatch method invocations to
* @return a proxy instance with the specified invocation handler of a
* proxy class that is defined by the specified class loader
* and that implements the specified interfaces
*/
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler invocationHandler );
办法,办法参数阐明:
a.ClassLoader loader:指定以后 target 对象应用类加载器,获取加载器的办法是固定的;
b.Class<?>[] interfaces:target 对象实现的接口的类型,应用泛型形式确认类型
c.InvocationHandler invocationHandler: 事件处理, 执行 target 对象的办法时,会触发事件处理器的办法,会把以后执行 target 对象的办法作为参数传入。
接口类 AdminService 接口
这是一个指标
public interface AdminService {
// 我定义一个用户服务权限接口
// 定义了一个更新办法
void update();
// 定义了一个查找办法,查找返回数据
Object find();}
实现类 AdminServiceImpl,这是一个指标对象的实现类
/** 动态接口的实现类 */
public class AdminServiceImpl implements AdminService{
@Override
public void update() {System.out.println("我曾经更新了零碎");
}
@Override
public Object find() {System.out.println("我曾经查看了零碎");
return new Object();}
}
动静代理和动态代理区别,动静代理不必实现目标接口,通过 Jdk 中的 newProxyInstance,动静生成,动静代理
package com.ruan.mygitignore;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class AdminServiceDynamicProxy {
// 保护一个指标对象
private Object target;
// 保护一个事件处理, 执行 target 对象的办法时,会触发事件处理器的办法,会把以后执行 target 对象的办法作为参数传入。private InvocationHandler invocationHandler;
public AdminServiceDynamicProxy(Object target, InvocationHandler invocationHandler) {
this.target = target;
this.invocationHandler = invocationHandler;
}
public Object getPersonProxy(){//target.getClass().getClassLoader(): 获取指标对象的应用类加载器
//target.getClass().getInterfaces(): 获取指标对象实现的接口的类型
//invocationHandler,是构造函数传入的,那咱们就要想怎么创立这个 InvocationHandler
Object obj= Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),invocationHandler);
return obj;
}
下面说了 invocationHandler 须要咱们传入那咱们如何生成它了 AdminServiceInvocation 实现接口 InvocationHandler
package com.ruan.mygitignore;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class AdminServiceInvocation implements InvocationHandler {
private Object target;
public AdminServiceInvocation(Object target) {this.target = target;}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("判断用户是否有权限进行操作");
// 最要害的就是这个 invoke(target): 办法的注入
Object obj =method.invoke(target);
System.out.println("记录用户执行操作的用户信息、更改内容和工夫等");
return obj;
}
}
调用
// 办法一
System.out.println("============ 办法一 ==============");
// 构建指标对象
AdminService adminService=new AdminServiceImpl();
System.out.println("代理的指标对象:" + adminService.getClass());
// 创立事件处理
AdminServiceInvocation adminServiceInvocation=new AdminServiceInvocation(adminService);
// 构建代理对象
AdminServiceDynamicProxy adminServiceDynamicProxy = new AdminServiceDynamicProxy(adminService,adminServiceInvocation);
// 获取代理的指标对象
AdminService proxy= (AdminService) adminServiceDynamicProxy.getPersonProxy();
System.out.println("代理对象:" + proxy.getClass());
Object obj = proxy.find();
System.out.println("find 返回对象:" + obj.getClass());
System.out.println("----------------------------------");
proxy.update();
// 后果
System.out: ============ 办法一 ==============
2021-07-26 16:43:24.602 12407-12407/com.ruan.mygitignore I/ 对象:class com.ruan.mygitignore.AdminServiceImpl
System.out: 代理对象:class $Proxy1
System.out: 判断用户是否有权限进行操作
System.out: 我曾经查看了零碎
System.out: 记录用户执行操作的用户信息、更改内容和工夫等
System.out: find 返回对象:class java.lang.Object
System.out: ----------------------------------
System.out: 判断用户是否有权限进行操作
System.out: 我曾经更新了零碎
System.out: 记录用户执行操作的用户信息、更改内容和工夫等
// 办法二,是把 getPersonProxy()办法拿到里面间接调用,不分装了
System.out.println("============ 办法二 ==============");
AdminService target = new AdminServiceImpl();
AdminServiceInvocation invocation = new AdminServiceInvocation(target);
AdminService proxy2 = (AdminService)Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),invocation);
Object obj2 = proxy2.find();
System.out.println("find 返回对象:" + obj2.getClass());
System.out.println("----------------------------------");
proxy2.update();
// 办法三,连 InvocationHandler 也不封装了,间接调用时候应用传递
System.out.println("============ 办法三 ==============");
final AdminService target3 = new AdminServiceImpl();
AdminService proxy3 = (AdminService) Proxy.newProxyInstance(target3.getClass().getClassLoader(), target3.getClass().getInterfaces(), new InvocationHandler() {public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("判断用户是否有权限进行操作");
Object obj = method.invoke(target3, args);
System.out.println("记录用户执行操作的用户信息、更改内容和工夫等");
return obj;
}
});
Object obj3 = proxy3.find();
System.out.println("find 返回对象:" + obj3.getClass());
System.out.println("----------------------------------");
proxy3.update();
四:Cglib 代理
Cglib 不能在 Android 中应用
JDK 动静代理要求 target 对象是一个接口的实现对象,如果 target 对象只是一个独自的对象,并没有实现任何接口,这时候就会用到 Cglib 代理(Code Generation Library),即通过构建一个子类对象,从而实现对 target 对象的代理,因而指标对象不能是 final 类(报错),且指标对象的办法不能是 final 或 static(不执行代理性能)。
Cglib 依赖的 jar 包
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.10</version>
</dependency>
Cglib 对于 Android 来说,Android 生成的.dex 文件而不是.class 文件须要另外实现形式
指标对象类 AdminCglibService.java
public class AdminCglibService {public void update() {System.out.println("批改管理系统数据");
}
public Object find() {System.out.println("查看管理系统数据");
return new Object();}
}
代理类 AdminServiceCglibProxy.java
public class AdminServiceCglibProxy implements MethodInterceptor {
private Object target;
public AdminServiceCglibProxy(Object target) {this.target = target;}
// 给指标对象创立一个代理对象
public Object getProxyInstance() {
// 工具类
Enhancer en = new Enhancer();
// 设置父类
en.setSuperclass(target.getClass());
// 设置回调函数
en.setCallback(this);
// 创立子类代理对象
return en.create();}
public Object intercept(Object object, Method method, Object[] arg2, MethodProxy proxy) throws Throwable {System.out.println("判断用户是否有权限进行操作");
Object obj = method.invoke(target);
System.out.println("记录用户执行操作的用户信息、更改内容和工夫等");
return obj;
}
}
调用
AdminCglibService target = new AdminCglibService();
AdminServiceCglibProxy proxyFactory = new AdminServiceCglibProxy(target);
AdminCglibService proxy = (AdminCglibService)proxyFactory.getProxyInstance();
System.out.println("代理对象:" + proxy.getClass());
Object obj = proxy.find();
System.out.println("find 返回对象:" + obj.getClass());
System.out.println("----------------------------------");
proxy.update();
// 后果
代理对象:class com.lance.proxy.demo.service.AdminCglibService$$EnhancerByCGLIB$$41b156f9
判断用户是否有权限进行操作
查看管理系统数据
记录用户执行操作的用户信息、更改内容和工夫等
find 返回对象:class java.lang.Object
----------------------------------
判断用户是否有权限进行操作
批改管理系统数据
记录用户执行操作的用户信息、更改内容和工夫等
END: 当你感觉你达到了高峰,其实可能才达到另一座山峰的谷底