代理是什么
代理模式,就是为其他的对象提供一种代理,以控制对这个对象的访问。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<Void>() {
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<Object>, 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<Object> 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> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
// 使用Proxy 类生成指定接口interfaces的代理类
return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), interfaces, new InvokerInvocationHandler(invoker));
}
@Override
public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
return new AbstractProxyInvoker<T>(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();
}
}