我们在上一篇文章中为大家介绍了如何使用scoped-proxy解决singleton依赖prototype的问题,及spring的一些表现(实际是singleton依赖了prototype的proxy,在protytype的每次方法调用时,proxy会为我们生成一个真正的protytpe实例)。
文章地址(Spring中的享元设计模式):juejin.cn/post/686752…
文章地址(关于Sping singleton依赖prototype):juejin.cn/post/686789…
今天我们来看看spring是如何做到这些的(关键代码添加了中文注释)?
1.注册ScopedProxyBeanDefinitionDecorator对象
<bean id="singletonReferencePrototype" class="com.cafebabe.spring.bean.SingletonReferencePrototype">
<property name="myTestBean" ref="myTestBean"></property>
</bean>
<bean id="myTestBean" class="com.cafebabe.spring.bean.MyTestBean" scope="prototype">
<property name="userId" value="1"></property>
<property name="age" value="18"></property>
<property name="userName" value="akun" ></property>
<!--告诉spring生成该类的时候使用 scoped-proxy -->
<aop:scoped-proxy></aop:scoped-proxy>
</bean>
首先我们只是在myTestBean的xml声明里面只是加了一句<aop:scoped-proxy/>,spring就开始为我们的需要而服务了,我们就来看看这一句。
熟悉spring的同学应该知道spring再解析<aop>标签时使用的是aop的namespace处理器,此段内容不再赘述,即读取到<aop>时使用的是AopNamespaceHandler来处理的,我们看下他的init()方法
@Override
public void init() {
// In 2.0 XSD as well as in 2.5+ XSDs
registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
//向该nameSpacehandler装饰器中注入ScopedProxy声明的装饰器,实际上是放入到Map中,key为"scoped-proxy",value是ScopedProxyBeanDefinitionDecorator对象
registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
// Only in 2.0 XSD: moved to context namespace in 2.5+
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}
其中这行代码registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator()); 向nameSpacehandler装饰器中注入ScopedProxy声明的装饰器(目前只是注入)。
2.装饰解析好的BeanDefinition
我们再来看向spring容器注入BeanDefinition的代码:
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//从xml元素中解析bean的各种属性声明
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
//如果需要的话,装饰解析而来的BeanDefinition对象
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
//将解析好的bean声明(如果需要装饰的,则使用装饰后的bean声明持有者)注册到beanFactory中
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
我们看到了decorateBeanDefinitionIfRequired()方法,并传入了Element(当前解析的xml节点)和BeanDefinitionHolder对象,我们继续跟踪代码找到了BeanDefinitionParserDelegate(bean声明解析器的委托者)的decorateBeanDefinitionIfRequired()方法
/**
* Decorate the given bean definition through a namespace handler, if applicable.
* @param ele the current element
* @param originalDef the current bean definition
* @param containingBd the containing bean definition (if any)
* @return the decorated bean definition
*/
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(
Element ele, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {
BeanDefinitionHolder finalDefinition = originalDef;
// Decorate based on custom attributes first.
//首先查看自定义属性,即我们的Xml中定义的id="myTestBean" class="com.cafebabe.spring.bean.MyTestBean" scope="prototype"
NamedNodeMap attributes = ele.getAttributes();
for (int i = 0; i < attributes.getLength(); i++) {
Node node = attributes.item(i);
finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
}
// Decorate based on custom nested elements.
//装饰子节点即<property name="userName" value="akun" ></property><aop:scoped-proxy></aop:scoped-proxy>等子节点
NodeList children = ele.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node node = children.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
}
}
return finalDefinition;
}
接着找decorateIfRequired方法,
public BeanDefinitionHolder decorateIfRequired(
Node node, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {
//从节点中得到相应节点的nameSpace
String namespaceUri = getNamespaceURI(node);
//如果namespaceUri不为空且不是默认的namespace(默认namespace是http://www.springframework.org/schema/beans)
if (namespaceUri != null && !isDefaultNamespace(namespaceUri)) {
//获取NamespaceHandlerResolver,实际上获取到的是就是文章开头说的AopNamespaceHandler
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler != null) {
BeanDefinitionHolder decorated =
handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
if (decorated != null) {
return decorated;
}
}
else if (namespaceUri.startsWith("http://www.springframework.org/")) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);
}
else {
// A custom namespace, not to be handled by Spring - maybe "xml:...".
if (logger.isDebugEnabled()) {
logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");
}
}
}
return originalDef;
}
获取到NamespaceHandler 之后就调用了该handler的decorated装饰方法:
public BeanDefinitionHolder decorate(
Node node, BeanDefinitionHolder definition, ParserContext parserContext) {
//根据节点名称获取装饰器,就是<aop:scoped-proxy></aop:scoped-proxy>中的‘scoped-proxy’
BeanDefinitionDecorator decorator = findDecoratorForNode(node, parserContext);
return (decorator != null ? decorator.decorate(node, definition, parserContext) : null);
}
首先根据节点名称获取装饰器,就是aop:scoped-proxy</aop:scoped-proxy>中的‘scoped-proxy’,这样我们回顾一下文章开头的AopNamespaceHandler的init()方法刚好注入了一个key为"scoped-proxy"的
ScopedProxyBeanDefinitionDecorator,实际上就是调用了ScopedProxyBeanDefinitionDecorator的decorate(node, definition, parserContext)方法。
@Override
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) {
//是否使用Class代理即使用CGlib生成代理
boolean proxyTargetClass = true;
if (node instanceof Element) {
Element ele = (Element) node;
//如果xml中表明了该属性,则使用表明的的该属性
if (ele.hasAttribute(PROXY_TARGET_CLASS)) {
proxyTargetClass = Boolean.valueOf(ele.getAttribute(PROXY_TARGET_CLASS));
}
}
// Register the original bean definition as it will be referenced by the scoped proxy
// and is relevant for tooling (validation, navigation).
//创建了ScopedProxy代理类的bean声明持有者
BeanDefinitionHolder holder = ScopedProxyUtils.createScopedProxy(definition, parserContext.getRegistry(), proxyTargetClass);
String targetBeanName = ScopedProxyUtils.getTargetBeanName(definition.getBeanName());
parserContext.getReaderContext().fireComponentRegistered(
new BeanComponentDefinition(definition.getBeanDefinition(), targetBeanName));
return holder;
}
该代码使用ScopedProxyUtils创建了一个BeanDefinitionHolder,并将该BeanDefinitionHolder返回,再注册到beanFactory中。
3.生成代理的bean声明及持有者
我们再来看看ScopedProxyUtils是如何生成代理对象的
public static BeanDefinitionHolder createScopedProxy(BeanDefinitionHolder definition,
BeanDefinitionRegistry registry, boolean proxyTargetClass) {
//获取原始bean的beanName即‘myTestBean’
String originalBeanName = definition.getBeanName();
//目标bean的bean声明
BeanDefinition targetDefinition = definition.getBeanDefinition();
//从原始beanName生成目标beanName 为“scopedTarget.myTestBean”
String targetBeanName = getTargetBeanName(originalBeanName);
// Create a scoped proxy definition for the original bean name,
// "hiding" the target bean in an internal target definition.
//创建一个新的RootBeanDefinitiond的代理bean声明proxyDefinition,使用ScopedProxyFactoryBean的Class
RootBeanDefinition proxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class);
//设置proxyDefinition的装饰的bean声明为原来的myTestBean声明及其他一些属性;
proxyDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, targetBeanName));
proxyDefinition.setOriginatingBeanDefinition(targetDefinition);
proxyDefinition.setSource(definition.getSource());
proxyDefinition.setRole(targetDefinition.getRole());
//proxyDefinition中的有一个String属性targetBeanName,定义为"scopedTarget.myTestBean"
proxyDefinition.getPropertyValues().add("targetBeanName", targetBeanName);
if (proxyTargetClass) {
targetDefinition.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
// ScopedProxyFactoryBean's "proxyTargetClass" default is TRUE, so we don't need to set it explicitly here.
}
else {
proxyDefinition.getPropertyValues().add("proxyTargetClass", Boolean.FALSE);
}
// Copy autowire settings from original bean definition.
proxyDefinition.setAutowireCandidate(targetDefinition.isAutowireCandidate());
proxyDefinition.setPrimary(targetDefinition.isPrimary());
if (targetDefinition instanceof AbstractBeanDefinition) {
proxyDefinition.copyQualifiersFrom((AbstractBeanDefinition) targetDefinition);
}
// The target bean should be ignored in favor of the scoped proxy.
targetDefinition.setAutowireCandidate(false);
targetDefinition.setPrimary(false);
// Register the target bean as separate bean in the factory.
//向beanFactory中注册名为“scopedTarget.myTestBean”实际上是myTestBean的声明。
registry.registerBeanDefinition(targetBeanName, targetDefinition);
// Return the scoped proxy definition as primary bean definition
// (potentially an inner bean).
//返回一个代理声明的持有者,该代理的实际对象已经是ScopedProxyFactoryBean了
return new BeanDefinitionHolder(proxyDefinition, originalBeanName, definition.getAliases());
}
从代码中我们大概知道了装饰器返回了一个名为"myTestBean"实际行已经是ScopedProxyFactoryBean的代理bean声明了,这个时候spring再调用getBean("myTestBean"),实际上已经再获取ScopedProxyFactoryBean的getObject()方法了
我们再来看看ScopedProxyFactoryBean对象的结构和方法
/**继承自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;
}
}
其实代码读到这里的时候,就差不多猜出来了,spring为我们生成一个代理对象,该代理对象是单例的,但是在每次方法调用时,该单例代理对象在每次方法调用时,实际上会从beanFactory中获取一个prototype的真实被代理对象,再执行被代理对象的方法。
大致流程可以看附录中的图片,也可以到去看processon中看
链接:www.processon.com/view/link/5…
密码:cafebabe