文章开始
上篇文章,介绍了spring使用装饰器解决singleton依赖prototype的问题,最终spring再创建singleton实例的时候,实际上为该singleton生成了一个代理ScopedProxyFactoryBean的代理对象,今天我们看看ScopedProxyFactoryBean生成代理对象的源码。
-
上篇文章链接:源码分析一下spring的scoped-proxy(一)
-
动态代理文章链接 代理模式和动态代理
ScopedProxyFactoryBean在setBeanFactory时会实例化好代理对象
先贴代码
/**继承自ProxyConfig代理配置类,
实现了BeanFactoryAware接口(spring获取该对象实例时会调用该接口的getObject()),
*实现了shiBeanFactoryAware,spring注入当前的beanFactory对象
*
*/
public class ScopedProxyFactoryBean extends ProxyConfig
implements FactoryBean<Object>, BeanFactoryAware, AopInfrastructureBean {
/** The TargetSource that manages scoping. */
//定义一个新的SimpleBeanTargetSource对象,该对象包含beanFactory和targetBeanName对象。
//实际上代理在调用MyTestBean的任意方法时,会从该对象的的beanFactory中重新获取targetBeanName的对象,即我们的scope为prototype的MyTestBean实例。这样就保证了每一次使用时都是一个新的MyTestBean实例
private final SimpleBeanTargetSource scopedTargetSource = new SimpleBeanTargetSource();
/** The name of the target bean. */
@Nullable
//再注册该bean声明时,添加了该属性的值,这里为“scopedTarget.myTestBean”
private String targetBeanName;
/** The cached singleton proxy. */
@Nullable
//最终的生成的代理对象
private Object proxy;
/**
* Create a new ScopedProxyFactoryBean instance.
*/
public ScopedProxyFactoryBean() {
setProxyTargetClass(true);
}
/**
* Set the name of the bean that is to be scoped.
*/
//注入targetBeanName,这里为“scopedTarget.myTestBean”
public void setTargetBeanName(String targetBeanName) {
this.targetBeanName = targetBeanName;
this.scopedTargetSource.setTargetBeanName(targetBeanName);
}
@Override
//实现了BeanFactoryAware接口,spring会将beanFactory注入进来
public void setBeanFactory(BeanFactory beanFactory) {
if (!(beanFactory instanceof ConfigurableBeanFactory)) {
throw new IllegalStateException("Not running in a ConfigurableBeanFactory: " + beanFactory);
}
ConfigurableBeanFactory cbf = (ConfigurableBeanFactory) beanFactory;
//scopedTargetSource注入beanFactory
this.scopedTargetSource.setBeanFactory(beanFactory);
//新建一个代理工厂
ProxyFactory pf = new ProxyFactory();
pf.copyFrom(this);
//代理工厂设置初始化好的目标对象
pf.setTargetSource(this.scopedTargetSource);
Assert.notNull(this.targetBeanName, "Property 'targetBeanName' is required");
Class<?> beanType = beanFactory.getType(this.targetBeanName);
if (beanType == null) {
throw new IllegalStateException("Cannot create scoped proxy for bean '" + this.targetBeanName +
"': Target type could not be determined at the time of proxy creation.");
}
if (!isProxyTargetClass() || beanType.isInterface() || Modifier.isPrivate(beanType.getModifiers())) {
pf.setInterfaces(ClassUtils.getAllInterfacesForClass(beanType, cbf.getBeanClassLoader()));
}
// Add an introduction that implements only the methods on ScopedObject.
ScopedObject scopedObject = new DefaultScopedObject(cbf, this.scopedTargetSource.getTargetBeanName());
//代理工厂设置Advice通知
pf.addAdvice(new DelegatingIntroductionInterceptor(scopedObject));
// Add the AopInfrastructureBean marker to indicate that the scoped proxy
// itself is not subject to auto-proxying! Only its target bean is.
//添加接口
pf.addInterface(AopInfrastructureBean.class);
//生成代理对象
this.proxy = pf.getProxy(cbf.getBeanClassLoader());
}
@Override
//实现了FactoryBean接口,spring获取该对象实例时会调用该接口的getObject()
//这里将代理对象proxy对象返回
public Object getObject() {
if (this.proxy == null) {
throw new FactoryBeanNotInitializedException();
}
return this.proxy;
}
@Override
public Class<?> getObjectType() {
if (this.proxy != null) {
return this.proxy.getClass();
}
return this.scopedTargetSource.getTargetClass();
}
@Override
public boolean isSingleton() {
return true;
}
}
ScopedProxyFactoryBean 生成代理对象时new了一个ProxyFactory对象,再对该对象进行属性以及目标对象的一些设置。 (这里利用了spring的BeanFactoryAware接口,获取ScopedProxyFactoryBean的实例时spring实例时会调用setBeanFactory()方法)
其中有两行代码需要先关注下
//代理工厂设置初始化好的目标对象
pf.setTargetSource(this.scopedTargetSource);
...
//代理工厂设置Advice通知
pf.addAdvice(new DelegatingIntroductionInterceptor(scopedObject));
使用CGlib生成动态代理对象
我们再追一下this.proxy = pf.getProxy(cbf.getBeanClassLoader())方法,由于我们这里的myTestBean并没有实现接口,这里spring会自动使用Cglib生成代理
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
...
try {
Class<?> rootClass = this.advised.getTargetClass();
...
// Configure CGLIB Enhancer...
Enhancer enhancer = createEnhancer();
...
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);
}
catch (CodeGenerationException | IllegalArgumentException ex) {
throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
": Common causes of this problem include using a final class or a non-visible class",
ex);
}
catch (Throwable ex) {
// TargetSource.getTarget() failed
throw new AopConfigException("Unexpected AOP exception", ex);
}
}
如果熟悉Cglib的同学,对于Enhancer类应该并不陌生,这里不再赘述,也可查看代理模式和动态代理,
Cglib重要的就是回调函数的获取,我们再来看一看这一行重要的代码
Callback[] callbacks = getCallbacks(rootClass);
private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
// Parameters used for optimization choices...
boolean exposeProxy = this.advised.isExposeProxy();
boolean isFrozen = this.advised.isFrozen();
boolean isStatic = this.advised.getTargetSource().isStatic();
// Choose an "aop" interceptor (used for AOP calls).
//将advised对象(这里其实就是我们的ProxyFactory对象)构造器注入,生成一个DynamicAdvisedInterceptor方法拦截器
Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
....
}
我们再查看该DynamicAdvisedInterceptor的intercept方法
@Override
@Nullable
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Object target = null;
//目标资源类
TargetSource targetSource = this.advised.getTargetSource();
try {
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...
//从目标资源来内来获取目标对象
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// Check whether we only have one InvokerInterceptor: that is,
// no real advice, but just reflective invocation of the target.
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
// We can skip creating a MethodInvocation: just invoke the target directly.
// Note that the final invoker must be an InvokerInterceptor, so we know
// it does nothing but a reflective operation on the target, and no hot
// swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
}
else {
// We need to create a method invocation...
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
重点代码在这里:
//目标资源类
TargetSource targetSource = this.advised.getTargetSource();
...
//从目标资源类里面获取目标对象
target = targetSource.getTarget();
...
利用反射执行目标方法。
advised对象其实就是我们文章开头说的ScopedProxyFactoryBean对象 setBeanFactory时new 的 BeanFactory对象,该bf对象的scopedTargetSource属性中targetName 和 beanFactory都已经设置过了。
此时我们再调用getTarget()方法获取目标对象时,相当于从当前BeanFactory再获取一次名为targetName的实例,我们这里名为‘scopedTarget.myTestBean’。由于该实例是prototype的,
所以每次调用方法时,相当于从spring容器中重新获取一个'Scoped'目标对象,然后由目标对象执行目标方法。
先简单写点ε=(´ο`*)))