代理模式在开源代码中的应用
16lz
2021-01-22
代理模式的作用:为某对象提供一种代理以控制对该对象的访问。即客户端通过代理间接地访问该对象,从而限制、增强或修改该对象的一些特性。
由于静态代理会导致类文件大量增多,所以 Java 中动态代理使用的较多。
案例一
JDK 中的动态代理的使用,实现 InvocationHandler 接口,只能代理接口的实现类
package com.xiongjun.proxy.dynamicproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* JDK 自带动态代理
*
* @author ConstXiong
*/
public class JdkDynamicProxy implements InvocationHandler {
private Object target;
public JdkDynamicProxy(Object target) {
this.target = target;
}
@SuppressWarnings("unchecked")
public <T> T getProxy() {
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
long t1 = System.currentTimeMillis();
result = method.invoke(target, args);//目标类的方法调用,与结果获取
System.out.println("login cost time : " + (System.currentTimeMillis() - t1));
return result;
}
}
客户端代码:
JdkDynamicProxy proxy = new JdkDynamicProxy(new ServiceImpl());Service jdkService = proxy.getProxy();jdkService.login("", "");
InvocationHandler 接口的源码,是被代理实例的处理程序实现,代理实例的方法调用会被关联到 invoke 方法
public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;}
代理实例通过 Proxy 类的静态工厂方法 newProxyInstance 创建
@CallerSensitivepublic static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException{ Objects.requireNonNull(h); final Class<?>[] intfs = interfaces.clone();//复制接口的Class对象数组 //校验权限 final SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } //调用本地方法根据类加载器和Class对象数组,获取被代理对象的Class的对象 Class<?> cl = getProxyClass0(loader, intfs); try { if (sm != null) { checkNewProxyPermission(Reflection.getCallerClass(), cl); } //获取构造方法对象 final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (!Modifier.isPublic(cl.getModifiers())) {//非public修改可见权限 AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { cons.setAccessible(true); return null; } }); } return cons.newInstance(new Object[]{h});//创建被代理对象实例 } catch (IllegalAccessException|InstantiationException e) { throw new InternalError(e.toString(), e); } catch (InvocationTargetException e) { Throwable t = e.getCause(); if (t instanceof RuntimeException) { throw (RuntimeException) t; } else { throw new InternalError(t.toString(), t); } } catch (NoSuchMethodException e) { throw new InternalError(e.toString(), e); }}
案例二
使用 Cglib 类库完成动态代理,不要求被代理类必须实现接口
package com.xiongjun.proxy.dynamicproxy;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* 使用 cglib 类库完成动态代理
*
* @author ConstXiong
*/
public class CglibProxy implements MethodInterceptor {
private CglibProxy() {
}
//单例模式获取代理类对象
private static CglibProxy proxy = new CglibProxy();
public static CglibProxy getInstance() {
return proxy;
}
/**
* 获取被代理后的目标类
* @param clazz 目标类
* @return
*/
@SuppressWarnings("unchecked")
public <T> T getProxy(Class<T> clazz) {
return (T) Enhancer.create(clazz, this);
}
/**
* 代理执行目标类方法
*/
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
Object result = null;
long t1 = System.currentTimeMillis();
result = proxy.invokeSuper(obj, args);//目标类的方法调用,与结果获取
System.out.println("login cost time : " + (System.currentTimeMillis() - t1));
return result;
}
}
客户端代码:
Service cglibService = CglibProxy.getInstance().getProxy(ServiceImpl.class);cglibService.login("", "");
Cglib 借助 Enhancer 创建被代理对象实例,Enhancer 底层是借助 ASM 工具生成字节码,实例化对象
/** * Helper method to create an intercepted object. * For finer control over the generated instance, use a new instance of <code>Enhancer</code> * instead of this static method. * @param type class to extend or interface to implement * @param callback the callback to use for all methods */public static Object create(Class type, Callback callback) { Enhancer e = new Enhancer(); e.setSuperclass(type); e.setCallback(callback); return e.create();}
案例三
使用 Spring aop 中的 ProxyFactory 完成环绕代理
import java.util.Random; import org.aopalliance.intercept.MethodInterceptor;import org.aopalliance.intercept.MethodInvocation; /** * 使用 spring aop 完成环绕代理 * @author ConstXiong */public class ServiceAroundAdvice implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { Object result = null; long start = System.currentTimeMillis();//计时开始 result = invocation.proceed();//目标类的方法调用,与结果获取 long end = System.currentTimeMillis();//计时结束 System.out.println("耗时:" + (end - start) + "毫秒");//打印耗时 return result; } }
客户端代码:
ProxyFactory proxyFactory = new ProxyFactory(); //创建代理工厂类proxyFactory.setTarget(new ServiceImpl()); //设置被代理类proxyFactory.addAdvice(new ServiceAroundAdvice()); //添加增强器Service service = (Service) proxyFactory.getProxy(); //获取代理类service.login("ConstXiong", "123456");
Spring aop 创建代理对象实例的源码逻辑在这里,可以看出它根据情况使用了 JDK 动态代理和 Cglib 动态代理
@Overridepublic AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class<?> targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation."); } if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } return new ObjenesisCglibAopProxy(config); } else { return new JdkDynamicAopProxy(config); }}
脑图:
https://processon.com/view/link/5ef8915be0b34d4dba5a959d