源码分析一下spring的scoped-proxy(一)

·  阅读 1037
源码分析一下spring的scoped-proxy(一)

我们在上一篇文章中为大家介绍了如何使用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’,这样我们回顾一下文章开头的AopNamespaceHandlerinit()方法刚好注入了一个key为"scoped-proxy"的 ScopedProxyBeanDefinitionDecorator,实际上就是调用了ScopedProxyBeanDefinitionDecoratordecorate(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"),实际上已经再获取ScopedProxyFactoryBeangetObject()方法了

我们再来看看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

附录

分类:
阅读
标签:
收藏成功!
已添加到「」, 点击更改