内容简介:代理是指一个包装了真实访问对象的类,以便控制对真实类的访问访问流程如下此时RealSubject作为代理对象的一个属性字段,在运行之前就会生成RealSubject的字节码文件,这种方式也称作静态代理
代理是指一个包装了真实访问对象的类,以便控制对真实类的访问
访问流程如下
public interface SubjectInterface { void hi(); } public class RealSubject implements SubjectInterface { @Override public void hi() { System.out.print("hi"); } } public class SubjectProxy implements SubjectInterface{ private RealSubject r; public SubjectProxy() { r=new RealSubject(); } @Override public void hi() { System.out.println("proxy"); r.hi(); } } public class Client { public static void main(String[] args) { SubjectInterface subject = new SubjectProxy(); subject.hi(); } } 复制代码
此时RealSubject作为代理对象的一个属性字段,在运行之前就会生成RealSubject的字节码文件,这种方式也称作静态代理
动态代理
被代理的类在运行时动态生成的,编译的时候并没有生成RealSubject
使用JDK实现动态代理
jdk实现动态代理必须有实现接口InvocationHandler的处理类,用于执行被代理类的方法
public class SubjectInvocationHandler implements InvocationHandler { private Object myproxy; public SubjectInvocationHandler(Object proxy) { this.myproxy = proxy; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("invocation handler"); method.invoke(myproxy,args); return null; } } 复制代码
客户端通过使用 java.lang.reflect.Proxy
自行创建代理,然后调用目标方法即可
public class Client { public static void main(String[] args) { //classloader会被用来验证是否可以加载传入的接口, SubjectInterface proxy = (SubjectInterface) Proxy.newProxyInstance(SubjectInterface.class.getClassLoader() , new Class[]{SubjectInterface.class} , new SubjectInvocationHandler(new RealSubject())); proxy.hi(); } 复制代码
访问流程如下
生成代理proxy class阶段
代理对象会在内部缓存,如果没有缓存则会由 ProxyClassFactory
新生成。
首先会做接口校验,比如是否可以从提供的classLoader获取接口
Class<?> interfaceClass = null; try { interfaceClass = Class.forName(intf.getName(), false, loader); } catch (ClassNotFoundException e) { } if (interfaceClass != intf) { throw new IllegalArgumentException( intf + " is not visible from class loader"); } 复制代码
验证完毕后,会读取接口的class文件使用的是 ProxyGenerator.generateProxyClass
,可以看到它会对整个的class文件的字节做读取
private byte[] generateClassFile() { ... dout.writeInt(0xCAFEBABE); ... } 复制代码
最后调用native方法生成代理对象,并存入缓存
获取proxy的构造函数
构造函数指定的参数就是InvocationHandler
创建实例
调用构造函数,传入自定义的invocationHandler,自此生成了一个proxy实例,且实例本身会实现传入的接口,代码实例生成的对象如下所示
public final class $Proxy0 extends Proxy implements SubjectInterface { ... public final void hi() throws { try { //这里的h即Proxy中的InvocationHandler,也就是用户自定义的InvocationHanlder //这个this对象代表的也就是 $Proxy0 本身 super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } ... } 复制代码
使用CGlib动态代理
引入CGlib之后,执行如下代码即可
public class Client { public static void main(String[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(RealSubject.class); enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("cglib:"+method.getName()); methodProxy.invokeSuper(o, objects); return o; } }); RealSubject realSubject = (RealSubject)enhancer.create(); realSubject.hi(); } } 复制代码
动态代理在spring aop中的运用
spring中默认使用 DefaultAopProxyFactory
public 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)) { //对于接口使用的是JDK return new JdkDynamicAopProxy(config); } //其余使用Cglib作为动态代理的实现 return new ObjenesisCglibAopProxy(config); } else { return new JdkDynamicAopProxy(config); } } 复制代码
JdkDynamicAopProxy
它实现了InvocationHandler和AopProxy。AopProxy主要是负责提供getProxy,实现为
@Override public Object getProxy() { return getProxy(ClassUtils.getDefaultClassLoader()); } @Override public Object getProxy(@Nullable ClassLoader classLoader) { if (logger.isTraceEnabled()) { logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource()); } Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true); findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); } 复制代码
当有需要执行的方法的时候,则是执行invoke
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { ... invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); // Proceed to the joinpoint through the interceptor chain. retVal = invocation.proceed(); ... } public Object proceed() throws Throwable { ... if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) { //这里会执行AfterReturningAdviceInterceptor、AspectJAfterThrowingAdvice等等方法 return dm.interceptor.invoke(this); } ... } 复制代码
CglibAopProxy
它实现了AopProxy,核心的生成代理的方式如下
public Object getProxy(@Nullable ClassLoader classLoader) { ... Enhancer enhancer = createEnhancer(); if (classLoader != null) { enhancer.setClassLoader(classLoader); if (classLoader instanceof SmartClassLoader && ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) { enhancer.setUseCache(false); } } enhancer.setSuperclass(proxySuperClass); enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised)); enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE); enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader)); Callback[] callbacks = getCallbacks(rootClass); Class<?>[] types = new Class<?>[callbacks.length]; for (int x = 0; x < types.length; x++) { types[x] = callbacks[x].getClass(); } // fixedInterceptorMap only populated at this point, after getCallbacks call above enhancer.setCallbackFilter(new ProxyCallbackFilter( this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset)); enhancer.setCallbackTypes(types); // Generate the proxy class and create a proxy instance. return createProxyClassAndInstance(enhancer, callbacks); ... } private Callback[] getCallbacks(Class<?> rootClass) throws Exception { ... Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised); ... Callback[] mainCallbacks = new Callback[] { aopInterceptor, // for normal advice targetInterceptor, // invoke target without considering advice, if optimized new SerializableNoOp(), // no override for methods mapped to this targetDispatcher, this.advisedDispatcher, new EqualsInterceptor(this.advised), new HashCodeInterceptor(this.advised) }; ... else { callbacks = mainCallbacks; } ... } 复制代码
以DynamicAdvisedInterceptor为例,它就实现了MethodInterceptor
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { ... //同样在此处去运行具体的Advice retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(); ... } 复制代码
通常可以使用Proxy的情况
- 虚代理:根据需要创建开销很大的对象,只有用到时才创建
- 保护代理:控制对原始对象的访问
- 智能指引:在访问对象时附加了一些操作,比如对象没有引用时释放它
- 远程代理:为一个对象在不同的地址空间提供局部代表
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
JavaScript DOM编程艺术 (第2版)
[英] Jeremy Keith、[加] Jeffrey Sambells / 杨涛、王建桥、杨晓云 等 / 人民邮电出版社 / 2011-4 / 49.00元
JavaScript是Web开发中最重要的一门语言,它强大而优美。无论是桌面开发,还是移动应用。JavaScript都是必须掌握的技术。W3C的DOM标准是开发Web应用的基石。已经得到所有现代浏览器的支持,这使得跨平台Web开发成了一件轻松惬意的事。 本书是超级畅销书的升级版,由倡导Web标准的领军人物执笔,揭示了前端开发的真谛,是学习JavaScript和DOM开发的必读之作。 本......一起来看看 《JavaScript DOM编程艺术 (第2版)》 这本书的介绍吧!