代理(Proxy)是什么?为什么要使用代理模式?Spring与Dubbo如何运用代理模式的? 您所在的位置:网站首页 用代理访问是什么意思 代理(Proxy)是什么?为什么要使用代理模式?Spring与Dubbo如何运用代理模式的?

代理(Proxy)是什么?为什么要使用代理模式?Spring与Dubbo如何运用代理模式的?

2024-06-16 09:01| 来源: 网络整理| 查看: 265

代理是什么

代理模式,就是为其他的对象提供一种代理,以控制对这个对象的访问。Proxy代理对象与被代理对象对于调用方来说,完全一致,并且Proxy代理对调用方隐藏了被代理对象的实现细节。流程如下:

为什么要使用代理模式

没错,代理模式就是这么简单,可以这么理解,Proxy代理对象向调用方统一了对被代理对象的所有方法。有时,在调用被代理对象的正在执行的方法前,可能需要增加参数的校验逻辑,或者打印日志的逻辑;在执行完方法后,可能需要统计执行的时间,触发结束的事件等等逻辑。此时,如果在Proxy代理对象里动态地添加此类逻辑,就避免了在委托对象中硬编码。此时的执行流程1如下:

如果,此时,委托对象的执行逻辑是第三方服务提供的RPC服务或者HTTP服务, 其执行流程2如下:

Spring与Dubbo如何运用的代理模式

是不是以上两个执行流程很熟悉?是的,Spring中AOP的实现就类似于流程1,在Spring中使用JDK和Cglib两种动态代理方式来实现了对被代理对象的切面逻辑的动态扩展。Dubbo远程服务调用类似于流程2,被代理对象的实际实现逻辑在远程的服务提供方,客户端与服务端通过TCP协议进行传输,在Dubbo中远程服务的调用通过JDK和Javassist两种动态代理方式进行动态代理。以下就以JDK动态代理方式来介绍AOP的实现,以及Dubbo远程服务的调用。

JDK的动态代理的原理可以参考Java JDK 动态代理(AOP)使用及实现原理分析。简单理解,就是JDK的动态代理通过Proxy对象和InvocationHandler接口来实现。Proxy类用于动态生成指定接口(interface)实现类的字节码。然后,加载为对应的Class类,利用反射机制生成代理类的实例对象;通过InvocationHandler扩展被代理对象的业务逻辑,InvocationHandler定义方法调用逻辑处理,其接口定义如下:

public interface InvocationHandler { /** * 方法调用处理 proxy为代理的对象,method为方法反射类,args为调用方法的参数 */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }

Proxy类部分的源码如下:

/** * 生成代理对象 */ // Proxy.class public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) throws IllegalArgumentException { Objects.requireNonNull(h); final Class[] intfs = interfaces.clone(); final SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } /* * 生成代理的对象的Class对象 */ Class cl = getProxyClass0(loader, intfs); /* * Invoke its constructor with the designated invocation handler. */ try { if (sm != null) { checkNewProxyPermission(Reflection.getCallerClass(), cl); } final Constructor cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (!Modifier.isPublic(cl.getModifiers())) { AccessController.doPrivileged(new PrivilegedAction() { public Void run() { cons.setAccessible(true); return null; } }); } // 根据InvocationHandler生成代理对象 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); } }

Spring中AOP的实现

在Spring中基于AspectJ与JDK动态代理共同实现了Spring的AOP。AspectJ用于指定需要被横切的具体位置,以及具体逻辑。使用JDK动态代理技术把AspectJ增强的逻辑整合到给定接口的动态代理生成的实现类,以实现了切面逻辑的整合。在Spring中,动态生成代理对象的逻辑,主要依靠ProxyFactoryBean类与JdkDynamicAopProxy类实现。ProxyFactoryBean实现了FactoryBean接口,用于获取Spring的bean对象,生成代理对象的逻辑在其getObject方法实现,ProxyFactoryBean的部分源码如下:

/** * 在spring中生成AOP代理的bean对象 */ public class ProxyFactoryBean extends ProxyCreatorSupport implements FactoryBean, BeanClassLoaderAware, BeanFactoryAware { /** * 通过继承FactoryBean生成spring bean对象 */ @Override @Nullable public Object getObject() throws BeansException { initializeAdvisorChain(); if (isSingleton()) { return getSingletonInstance(); } else { if (this.targetName == null) { logger.info("Using non-singleton proxies with singleton targets is often undesirable. " + "Enable prototype proxies by setting the 'targetName' property."); } // 生成代理对象实例 return newPrototypeInstance(); } } /** * 生成对象实例 */ private synchronized Object newPrototypeInstance() { ProxyCreatorSupport copy = new ProxyCreatorSupport(getAopProxyFactory()); TargetSource targetSource = freshTargetSource(); copy.copyConfigurationFrom(this, targetSource, freshAdvisorChain()); if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) { Class targetClass = targetSource.getTargetClass(); if (targetClass != null) { copy.setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader)); } } copy.setFrozen(this.freezeProxy); // 获取代理对象 return getProxy(copy.createAopProxy()); } /** * 通过AopProxy 生成代理对象 */ protected Object getProxy(AopProxy aopProxy) { return aopProxy.getProxy(this.proxyClassLoader); } }

JdkDynamicAopProxy实现了AopProxy接口,用于生成代理对象。也实现了InvocationHandler接口,定义了对代理对象业务的扩展,其源码如下:

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable { /** * 获取代理对象 */ @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); // 调用Proxy的静态方法newProxyInstance 生成代理对象 return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); } /** * 扩展被代理访问的业务逻辑 */ @Override @Nullable public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object oldProxy = null; boolean setProxyContext = false; TargetSource targetSource = this.advised.targetSource; Object target = null; try { if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) { // The target does not implement the equals(Object) method itself. return equals(args[0]); } else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) { // The target does not implement the hashCode() method itself. return hashCode(); } else if (method.getDeclaringClass() == DecoratingProxy.class) { // There is only getDecoratedClass() declared -> dispatch to proxy config. return AopProxyUtils.ultimateTargetClass(this.advised); } else if (!this.advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) { // Service invocations on ProxyConfig with the proxy config... return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args); } Object retVal; if (this.advised.exposeProxy) { // Make invocation available if necessary. oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } target = targetSource.getTarget(); Class targetClass = (target != null ? target.getClass() : null); // 获取拦截器 List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); if (chain.isEmpty()) { Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); } else { // 结合拦截器chain生成的invocation MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); // Proceed to the joinpoint through the interceptor chain. retVal = invocation.proceed(); } // Massage return value if necessary. Class returnType = method.getReturnType(); if (retVal != null && retVal == target && returnType != Object.class && returnType.isInstance(proxy) && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { retVal = proxy; } else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) { throw new AopInvocationException( "Null return value from advice does not match primitive return type for: " + method); } return retVal; } finally { if (target != null && !targetSource.isStatic()) { // Must have come from TargetSource. targetSource.releaseTarget(target); } if (setProxyContext) { // Restore old proxy. AopContext.setCurrentProxy(oldProxy); } } } }

Dubbo基于JDK动态代理的服务调用

在Dubbo远程服务的调用过程中,默认情况下,使用Netty与服务提供方进行通信,定义DubboInvoker使用服务通信的客户端发起远程调用。在使用JDK动态代理时,在JdkProxyFactory中实现ProxyFactory接口,使用JDK的Proxy代理类,生成代理对象DubboInvoker,其的源码如下:

public class JdkProxyFactory extends AbstractProxyFactory { @Override @SuppressWarnings("unchecked") public T getProxy(Invoker invoker, Class[] interfaces) { // 使用Proxy 类生成指定接口interfaces的代理类 return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), interfaces, new InvokerInvocationHandler(invoker)); } @Override public Invoker getInvoker(T proxy, Class type, URL url) { return new AbstractProxyInvoker(proxy, type, url) { @Override protected Object doInvoke(T proxy, String methodName, Class[] parameterTypes, Object[] arguments) throws Throwable { Method method = proxy.getClass().getMethod(methodName, parameterTypes); // 生成远程调用的Invoker return method.invoke(proxy, arguments); } }; } }

使用InvokerInvocationHandler定义远程服务调用参数RpcInvocation的封装,已经具体方法的执行逻辑,其源码如下:

public class InvokerInvocationHandler implements InvocationHandler { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getDeclaringClass() == Object.class) { return method.invoke(invoker, args); } String methodName = method.getName(); Class[] parameterTypes = method.getParameterTypes(); if (parameterTypes.length == 0) { if ("toString".equals(methodName)) { return invoker.toString(); } else if ("$destroy".equals(methodName)) { invoker.destroy(); return null; } else if ("hashCode".equals(methodName)) { return invoker.hashCode(); } } else if (parameterTypes.length == 1 && "equals".equals(methodName)) { return invoker.equals(args[0]); } // 封装远程调用参数RpcInvocation RpcInvocation rpcInvocation = new RpcInvocation(method, invoker.getInterface().getName(), args); String serviceKey = invoker.getUrl().getServiceKey(); rpcInvocation.setTargetServiceUniqueName(serviceKey); if (consumerModel != null) { rpcInvocation.put(Constants.CONSUMER_MODEL, consumerModel); rpcInvocation.put(Constants.METHOD_MODEL, consumerModel.getMethodModel(method)); } // 执行被代理的业务方法 return invoker.invoke(rpcInvocation).recreate(); } }

 



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有