设计模式之代理模式(Java) (2)

Factory,也可以不用工厂客户端直接new

public class ProxyFactory { public static LifeService getLifeServiceProxyInstance(Class clz) throws IllegalAccessException, InstantiationException { // 创建被代理对象 LifeService target = (LifeService) clz.newInstance(); // 绑定到代理执行器中 InvocationHandler handler = new InvocationProxy(target); // JVM层面对被代理对象进行监控,行为发生就动态创建代理对象处理 LifeService $proxy = (LifeService) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), handler); return $proxy; } }

Client

public class Test { public static void main(String[] args) throws InstantiationException, IllegalAccessException, InterruptedException { LifeService zhang = ProxyFactory.getLifeServiceProxyInstance(Person.class); System.out.println(zhang.sleep()); System.out.println(zhang.wake()); } /** * 输出: * 2019-11-10T05:24:16.932Z * 晚安晚安 * 2019-11-10T05:24:16.942Z * 早鸭 */ }

用了动态代理我们把所有代理需要实现的行为集中到了invoke这一个方法去执行,不要再写大量模板代码了,并且我们实际上可以在一个InvocationHandler代理多个接口

不足

如果InvocationHandler中代理了两个接口,两个接口中有完全一模一样的两个方法,就没法去区分了

代理必须基于接口,没有实现接口的类没法被代理

三方库Cglib

Cglib 基于 ASM 框架操作字节码帮我们生成需要的代理对象,并且不要求实现接口

加入依赖

<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version> </dependency>

RealSubject

我们不需要实现特定接口了

public class Person { public String sleep() { return "晚安晚安"; } public String wake() { return "早鸭"; } }

Proxy

我们的逻辑和JDK自带的动态代理是一样的

public class CglibProxy implements MethodInterceptor { //需要代理的目标对象 private Object target; public CglibProxy(Object target) { this.target = target; } /** * * @param o 监控对象:监控行为是否发生 * @param method 被监控的行为方法 * @param objects 被监控行为方法的参数 * @param methodProxy 代理中生成的方法 * @return * @throws Throwable */ @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { Object result = null; String methodName = method.getName(); if ("sleep".equals(methodName)) { result = getTime(); result += (String) method.invoke(this.target, objects); } else if ("wake".equals(methodName)) { result = getTime(); result += (String) method.invoke(this.target, objects); } return result; } // 辅助行为 private String getTime() { return Clock.systemDefaultZone().instant().toString() + "\n"; } }

Factory,也可以不用工厂客户端直接new

public class ProxyFactory { public static Object getCglibProxyInstance(Class clz) throws IllegalAccessException, InstantiationException { // Enhancer类是CGLib中的一个字节码增强器 Enhancer enhancer=new Enhancer(); // 设置被代理类的字节码文件,这里我们关注的不再是接口 enhancer.setSuperclass(clz); // 创建被代理对象 Object target = clz.newInstance(); // 绑定到代理执行器中 CglibProxy proxy = new CglibProxy(target); // 设置回调这个代理对象 enhancer.setCallback(proxy); // 生成返回代理对象 return enhancer.create(); } }

Client

public class Test { public static void main(String[] args) throws InstantiationException, IllegalAccessException { Person zhang = (Person) ProxyFactory.getCglibProxyInstance(Person.class); System.out.println(zhang.sleep()); System.out.println(zhang.wake()); } /** * 输出: * 2019-11-10T06:01:13.105Z * 晚安晚安 * 2019-11-10T06:01:13.115Z * 早鸭 */ }

不需要实现接口也可以动态代理啦,真的很了不起

不足

依赖三方库

对于final的类和方法不能代理, 因为Cglib 生成的代理类需要重写代理类中所有的方法

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpwwws.html