今天在看spring plugin的源码时候遇到了这个TargetSource。具体代码:
public OrderAwarePluginRegistry<T, S> getObject() {
return OrderAwarePluginRegistry.create(getBeans());
}
在getBeans()里代码如下:
protected List<T> getBeans() {
ProxyFactory factory = new ProxyFactory(List.class, targetSource);
return (List<T>) factory.getProxy();
}
getBeans()里面的方法,很明显,是想创建代理对象,在这里的场景目标对象是业务端实现了spring plugin插件的一系列具体实现。开始很难理解的的是这一句? new ProxyFactory(List.class, targetSource);为什么是targetSource,要对目标产生代理,拿到所有的目标对象不就好了吗,也就是一系列的插件,而且还有一个地方不能理解的是:我们知道动态代理分为jdk代理和cglib代理,这里明显是jdk代理,jdk代理需要目标类实现一个多个接口,问题来了,我们的plugin并没有实现List接口,在这里为什么能被代理呢?
先看看tagetSource是什么?
TargetSource是一个接口,其定义了四个方法
- Class<?> getTargetClass();
- boolean isStatic();
- Object getTarget() throws Exception;
- void releaseTarget(Object target) throws Exception;
具体看下源码到底是怎么获取代理的?
ProxyFactory继承了ProxyCreatorSupport,ProxyCreatorSupport继承了AdvisedSupport
//new ProxyFactory(List.class, targetSource)最终会调用AdvisedSupport的setTargetSource 【代码1】
ProxyFactory factory = new ProxyFactory(List.class, targetSource);
public void setTargetSource(@Nullable TargetSource targetSource) {
this.targetSource = (targetSource != null ? targetSource : EMPTY_TARGET_SOURCE);
}
【代码1】
没有我们想要的TargetSource相关代码,接下来看 factory.getProxy();方法【代码2】,getProxy()方法分为两步,我们瞎看createAopProxy()第一步。
public Object getProxy() {
return createAopProxy().getProxy();
}
【代码2】
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
// getAopProxyFactory() 获取AopProxyFactory,这里是默认的DefaultAopProxyFactory,核心逻辑在createAopProxy里【代码3】
createAopProxy方法决定了使用jdk代理还是cglib代理,在我的场景下,走的jdk代理,看一下new JdkDynamicAopProxy(config);方法做了什么
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)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
【代码3】
JdkDynamicAopProxy就做了一件事,把config set给advised(AdvisedSupport的实例)
public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
Assert.notNull(config, "AdvisedSupport must not be null");
if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
throw new AopConfigException("No advisors and no TargetSource specified");
}
this.advised = config;
}
new 完JdkDynamicAopProxy,【代码2】中的createAopProxy()第一步才真正返回,整个流程有点长,接着调用getProxy方法,然后我们看看JdkDynamicAopProxy的getProxy是怎么实现的?【代码4】
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);
}
【代码4】
jdk创建代理我们知道是需要类加载器的,接口,classLoader就是类加载器,proxiedInterfaces就是接口,由于JdkDynamicAopProxy实现了jdk的InvocationHandler接口,所以Proxy.newProxyInstance这里可以直接传递this指针,不同与我们之前写过的jdk创建代理对象的demo(不了解这个的可以baidu一下,估计百度的代码都是千篇一律的),这里我们好像并没有用到目标对象啊,照例说我们代理的是目标对象(在此场景是Plugin的实现),其实目标对象被包装到了TargetSource里面,而TargetSource又被包装到了advised,这样是可以的,虽然advised没有实现List接口但依旧是可以被代理的,之前我们经常在网上或者那里看到的一句话是“**JDK代理必须基于接口,目标对象必须要实现一个以上的接口”,放在这里看,这句话就不太合适了,其实jdk代理的本质,在代理对象身上调用的方法,都会先调用到InvocationHandler的invoke方法,因此只要在invoke方法里能够拿到目标对象就是可以调用目标方法,并且在调用目标方法之前执行我们织入的逻辑。**说了这么多,看下spring是怎么做的,因此需要看JdkDynamicAopProxy的incoke方法【代码5】
为了缩短篇幅,我省略了部分代码,可以看到先从advised获取到被包装的targetSource,然后再调用targetSource.getTarget获取到整整的目标对象,也就是我们想要被代理的对象,最后再利用反射调用目标对象的目标方法。在我分析的这个场景中,targetSource是org.springframework.plugin.core.support.AbstractTypeAwareSupport.BeansOfTypeTargetSource这一个类,大家也可以查看TargetSource的其它类实现的,例如spring单例模式目标对象是怎么被代理的,查看你这个类SingletonTargetSource,类似的可以看下多例模式下又是怎么被代理的。
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;
Object retVal;
.........
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
if (chain.isEmpty()) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed();
}
return retVal;
}
}
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);
}
如果你看懂了我说的,那么你应该也能看懂下面的代码,或许下面的代码能帮你更好的理解上面的源码分析的。
public class LocalTest {
@Data
// 目标对象,并未实现List接口
static class MyTarget {
private static List<String> words = Lists.newArrayList("hello", "young man");
}
static class MyInvocation implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] arguments) throws Throwable {
return method.invoke(MyTarget.words, arguments);
}
}
public static void main(String[] args) throws InterruptedException {
Object proxyInstance = Proxy
.newProxyInstance(MyTarget.class.getClassLoader(), new Class[] { List.class }, new MyInvocation());
List list = (List) proxyInstance;
System.out.println(list); // [hello, young man]
}
}
总结:spring创建代理对象并不是直接对目标对象进项代理,而是先把目标对象包装成TargetSource,targetSource会被转换成Advised,这个是真正的被代理的类,只不过在invoke方法执行的时候,会从targetSource中取出真正的目标对象,然后调用目标对象身上的方法。