Spring源码解析(31)之事务配置文件解析以及核心对象创建过程

一、前言

        首先我们先准备一下spring 事务的配置文件,具体内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
    <context:property-placeholder location="classpath:dbconfig.properties"></context:property-placeholder>
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="driverClassName" value="${jdbc.driverClassName}"></property>
    </bean>
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" >
        <constructor-arg name="dataSource" ref="dataSource"></constructor-arg>
    </bean>
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <bean id="bookService" class="com.mashibing.tx.xml.service.BookService">
        <property name="bookDao" ref="bookDao"></property>
    </bean>
    <bean id="bookDao" class="com.mashibing.tx.xml.dao.BookDao">
        <property name="jdbcTemplate" ref="jdbcTemplate"></property>
    </bean>
    <aop:config>
        <aop:pointcut id="txPoint" expression="execution(* com.mashibing.tx.xml.*.*.*(..))"/>
        <aop:advisor advice-ref="myAdvice" pointcut-ref="txPoint"></aop:advisor>
    </aop:config>
    <tx:advice id="myAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="checkout" propagation="REQUIRED" />
            <tx:method name="updateStock" propagation="REQUIRES_NEW" />
        </tx:attributes>
    </tx:advice>
</beans>

        然后是我们对应的启动类,代码如下:

    public static void main(String[] args) throws SQLException {
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"d:\\code");
        ApplicationContext context = new ClassPathXmlApplicationContext("tx.xml");
        BookService bookService = context.getBean("bookService", BookService.class);
        bookService.checkout("zhangsan",1);
    }

二、源码分析 

        在启动spring容器之前首先会去解析我们的配置文件,在之前介绍过解析配置文件是通过一系列重载的loadBeanDefinitionsf方法,最后就会通过调用对应parser对象解析配置文件。核心代码如下:

	protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
		if (delegate.isDefaultNamespace(root)) {
			NodeList nl = root.getChildNodes();
			for (int i = 0; i < nl.getLength(); i++) {
				Node node = nl.item(i);
				if (node instanceof Element) {
					Element ele = (Element) node;
					if (delegate.isDefaultNamespace(ele)) {
						parseDefaultElement(ele, delegate);
					}
					else {
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		else {
			delegate.parseCustomElement(root);
		}
	}

	@Nullable
	public BeanDefinition parseCustomElement(Element ele) {
		return parseCustomElement(ele, null);
	}
	@Nullable
	public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
		// 获取对应的命名空间
		String namespaceUri = getNamespaceURI(ele);
		if (namespaceUri == null) {
			return null;
		}
		// 根据命名空间找到对应的NamespaceHandlerspring
		NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
		if (handler == null) {
			error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
			return null;
		}
		// 调用自定义的NamespaceHandler进行解析
		return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
	}

        然后就会按照我们配置文件的解析顺序,首先就会解析aop-poincut标签

        我们看下他是如何去解析aop-pointcut标签的。

/**
	 * 解析切入点
	 *
	 * Parses the supplied {@code <pointcut>} and registers the resulting
	 * Pointcut with the BeanDefinitionRegistry.
	 */
	private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) {
		// 切入点的唯一标识
		String id = pointcutElement.getAttribute(ID);
		// 获取切入点的表达式
		String expression = pointcutElement.getAttribute(EXPRESSION);

		AbstractBeanDefinition pointcutDefinition = null;

		try {
			// 采用栈保存切入点
			this.parseState.push(new PointcutEntry(id));
			// 创建切入点bean对象
			// beanClass为AspectJExpressionPointcut.class。并且设置属性expression到该beanClass中
			pointcutDefinition = createPointcutDefinition(expression);
			pointcutDefinition.setSource(parserContext.extractSource(pointcutElement));

			String pointcutBeanName = id;
			if (StringUtils.hasText(pointcutBeanName)) {
				// 注册bean对象
				parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition);
			}
			else {
				pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition);
			}

			parserContext.registerComponent(
					new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression));
		}
		finally {
			// 创建后移除
			this.parseState.pop();
		}

		return pointcutDefinition;
	}

        然后继续往下跟createPointcutDefinition。

	/**
	 * Creates a {@link BeanDefinition} for the {@link AspectJExpressionPointcut} class using
	 * the supplied pointcut expression.
	 */
	protected AbstractBeanDefinition createPointcutDefinition(String expression) {
		RootBeanDefinition beanDefinition = new RootBeanDefinition(AspectJExpressionPointcut.class);
		beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
		beanDefinition.setSynthetic(true);
		beanDefinition.getPropertyValues().add(EXPRESSION, expression);
		return beanDefinition;
	}

        这里就会设置一个AspectJExpressionPointCut对象,继续往下跟。

        此时就会往容器中注入了一个AspectJExpressionPointCut的BeanDefinition信息。继续解析下一个标签。

        此时就会解析到advisor对象,还记得之前aop中是如果解析advisor对象的吗?aop是advisor对象里面包着一层advice对象,而advice对象分为AspectJMethodBeforAdvice,AspectJAfterAdvice、AspectJAfterReturingAdvice、AspectJAroundAdvice、AspectJAfterThrowingAdvice。而事务这里这里有所不一样,我们继续往下跟。

/**
	 * 解析advisor顾问类
	 *
	 * Parses the supplied {@code <advisor>} element and registers the resulting
	 * {@link org.springframework.aop.Advisor} and any resulting {@link org.springframework.aop.Pointcut}
	 * with the supplied {@link BeanDefinitionRegistry}.
	 */
	private void parseAdvisor(Element advisorElement, ParserContext parserContext) {
		// 解析<aop:advisor>节点,最终创建的beanClass为`DefaultBeanFactoryPointcutAdvisor`
		// 另外advice-ref属性必须定义,其与内部属性adviceBeanName对应
		AbstractBeanDefinition advisorDef = createAdvisorBeanDefinition(advisorElement, parserContext);
		String id = advisorElement.getAttribute(ID);

		try {
			// 注册到bean工厂
			this.parseState.push(new AdvisorEntry(id));
			String advisorBeanName = id;
			if (StringUtils.hasText(advisorBeanName)) {
				parserContext.getRegistry().registerBeanDefinition(advisorBeanName, advisorDef);
			}
			else {
				advisorBeanName = parserContext.getReaderContext().registerWithGeneratedName(advisorDef);
			}

			// 解析point-cut属性并赋值到DefaultBeanFactoryPointcutAdvisor#pointcut内部属性
			Object pointcut = parsePointcutProperty(advisorElement, parserContext);
			if (pointcut instanceof BeanDefinition) {
				advisorDef.getPropertyValues().add(POINTCUT, pointcut);
				parserContext.registerComponent(
						new AdvisorComponentDefinition(advisorBeanName, advisorDef, (BeanDefinition) pointcut));
			}
			else if (pointcut instanceof String) {
				advisorDef.getPropertyValues().add(POINTCUT, new RuntimeBeanReference((String) pointcut));
				parserContext.registerComponent(
						new AdvisorComponentDefinition(advisorBeanName, advisorDef));
			}
		}
		finally {
			this.parseState.pop();
		}
	}

        继续往下跟createAdvisorBeanDefinition看他是如何创建advisor对象的。

/**
	 * Create a {@link RootBeanDefinition} for the advisor described in the supplied. Does <strong>not</strong>
	 * parse any associated '{@code pointcut}' or '{@code pointcut-ref}' attributes.
	 */
	private AbstractBeanDefinition createAdvisorBeanDefinition(Element advisorElement, ParserContext parserContext) {
		RootBeanDefinition advisorDefinition = new RootBeanDefinition(DefaultBeanFactoryPointcutAdvisor.class);
		advisorDefinition.setSource(parserContext.extractSource(advisorElement));

		String adviceRef = advisorElement.getAttribute(ADVICE_REF);
		if (!StringUtils.hasText(adviceRef)) {
			parserContext.getReaderContext().error(
					"'advice-ref' attribute contains empty value.", advisorElement, this.parseState.snapshot());
		}
		else {
			advisorDefinition.getPropertyValues().add(
					ADVICE_BEAN_NAME, new RuntimeBeanNameReference(adviceRef));
		}

		if (advisorElement.hasAttribute(ORDER_PROPERTY)) {
			advisorDefinition.getPropertyValues().add(
					ORDER_PROPERTY, advisorElement.getAttribute(ORDER_PROPERTY));
		}

		return advisorDefinition;
	}

        这里看到他注入的是DefaultBeanFactoryPointcutAdvisor对象,然后就会设置一系列属性,包括advice-ref等。

        到此,我们的aop:pointcut以及aop:advisor标签已经解析完毕,总结一下,他就是生成了AspectJExpressionPointcut以及DefaultBeanFactoryPointcutAdvisor两个BeanDefination。

        接下来就是解析对应的tx标签。

        就会在AbstractBeanDefinitionParser解析对应的tx标签。为啥会在在这里去解析,可以去看一下之前xml配置文件解析去查看是如何去查找对应的parser对象的。

         我们继续往下看具体的解析逻辑。

@Override
	@Nullable
	public final BeanDefinition parse(Element element, ParserContext parserContext) {
		AbstractBeanDefinition definition = parseInternal(element, parserContext);
		if (definition != null && !parserContext.isNested()) {
			try {
				String id = resolveId(element, definition, parserContext);
				if (!StringUtils.hasText(id)) {
					parserContext.getReaderContext().error(
							"Id is required for element '" + parserContext.getDelegate().getLocalName(element)
									+ "' when used as a top-level tag", element);
				}
				String[] aliases = null;
				if (shouldParseNameAsAliases()) {
					String name = element.getAttribute(NAME_ATTRIBUTE);
					if (StringUtils.hasLength(name)) {
						aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));
					}
				}
				// 将AbstractBeanDefinition转换为BeanDefinitionHolder并注册
				BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
				registerBeanDefinition(holder, parserContext.getRegistry());
				if (shouldFireEvents()) {
					// 通知监听器进行处理
					BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder);
					postProcessComponentDefinition(componentDefinition);
					parserContext.registerComponent(componentDefinition);
				}
			}
			catch (BeanDefinitionStoreException ex) {
				String msg = ex.getMessage();
				parserContext.getReaderContext().error((msg != null ? msg : ex.toString()), element);
				return null;
			}
		}
		return definition;
	}

         往下跟parseInternal看他是如何生成BeanDefinition信息的。

@Override
	protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
		BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
		String parentName = getParentName(element);
		if (parentName != null) {
			builder.getRawBeanDefinition().setParentName(parentName);
		}
		// 获取自定义标签中的class,此时会调用自定义解析器
		Class<?> beanClass = getBeanClass(element);
		if (beanClass != null) {
			builder.getRawBeanDefinition().setBeanClass(beanClass);
		}
		else {
			// 若子类没有重写getBeanClass方法则尝试检查子类是否重写getBeanClassName方法
			String beanClassName = getBeanClassName(element);
			if (beanClassName != null) {
				builder.getRawBeanDefinition().setBeanClassName(beanClassName);
			}
		}
		builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));
		BeanDefinition containingBd = parserContext.getContainingBeanDefinition();
		if (containingBd != null) {
			// Inner bean definition must receive same scope as containing bean.
			// 若存在父类则使用父类的scope属性
			builder.setScope(containingBd.getScope());
		}
		if (parserContext.isDefaultLazyInit()) {
			// Default-lazy-init applies to custom bean definitions as well.
			// 配置延迟加载
			builder.setLazyInit(true);
		}
		// 调用子类重写的doParse方法进行解析
		doParse(element, parserContext, builder);
		return builder.getBeanDefinition();
	}

        然后去看下对应的getClass方法。

        可以看到 他给我们返回的是一个TransactionInterceptor对象,我们来看下这个是个啥东西?

        还记得我们之前在讲aop的时候,我们要实现一个拦截器,要么就是就是实现对应的MethodInterceptor接口,要么是通过适配器来返回对应的Interceptor。而AOP也是这样子,MethodBefore跟AfterReturing是没有实现MethodInterceptor而是通过适配器来获取的。

        对应的源码位置为:DynamicAdvisedInterceptor通过对应的advisor获取对应的Interceptor的时候去获取的。

	// 将 Advisor转换为 MethodInterceptor
	@Override
	public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
		List<MethodInterceptor> interceptors = new ArrayList<>(3);
		// 从Advisor中获取 Advice
		Advice advice = advisor.getAdvice();
		if (advice instanceof MethodInterceptor) {
			interceptors.add((MethodInterceptor) advice);
		}
		for (AdvisorAdapter adapter : this.adapters) {
			if (adapter.supportsAdvice(advice)) {
				// 转换为对应的 MethodInterceptor类型
				// AfterReturningAdviceInterceptor MethodBeforeAdviceInterceptor  ThrowsAdviceInterceptor
				interceptors.add(adapter.getInterceptor(advisor));
			}
		}
		if (interceptors.isEmpty()) {
			throw new UnknownAdviceTypeException(advisor.getAdvice());
		}
		return interceptors.toArray(new MethodInterceptor[0]);
	}

        而我们知道AOP是基于IOC的一个拓展,而事务又是基于AOP的一个拓展,所以这个TransactionInterceptor他直接实现了对应的MethodIntercetor接口,他就能够实现拦截器功能,然后在对应的invoke方法实现对应的控制事务的方法,这个后续会看到,我们先继续往下看他对应的核心对象生成。

        然后我们继续接着往下看对应doParse方法。

	@Override
	protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
		builder.addPropertyReference("transactionManager", TxNamespaceHandler.getTransactionManagerName(element));

		List<Element> txAttributes = DomUtils.getChildElementsByTagName(element, ATTRIBUTES_ELEMENT);
		if (txAttributes.size() > 1) {
			parserContext.getReaderContext().error(
					"Element <attributes> is allowed at most once inside element <advice>", element);
		}
		else if (txAttributes.size() == 1) {
			// Using attributes source.
			Element attributeSourceElement = txAttributes.get(0);
			RootBeanDefinition attributeSourceDefinition = parseAttributeSource(attributeSourceElement, parserContext);
			builder.addPropertyValue("transactionAttributeSource", attributeSourceDefinition);
		}
		else {
			// Assume annotations source.
			builder.addPropertyValue("transactionAttributeSource",
					new RootBeanDefinition("org.springframework.transaction.annotation.AnnotationTransactionAttributeSource"));
		}
	}

        这里就会接着去解析对应的<tx:attributes>标签。

private RootBeanDefinition parseAttributeSource(Element attrEle, ParserContext parserContext) {
		List<Element> methods = DomUtils.getChildElementsByTagName(attrEle, METHOD_ELEMENT);
		ManagedMap<TypedStringValue, RuleBasedTransactionAttribute> transactionAttributeMap =
				new ManagedMap<>(methods.size());
		transactionAttributeMap.setSource(parserContext.extractSource(attrEle));

		for (Element methodEle : methods) {
			String name = methodEle.getAttribute(METHOD_NAME_ATTRIBUTE);
			TypedStringValue nameHolder = new TypedStringValue(name);
			nameHolder.setSource(parserContext.extractSource(methodEle));

			RuleBasedTransactionAttribute attribute = new RuleBasedTransactionAttribute();
			String propagation = methodEle.getAttribute(PROPAGATION_ATTRIBUTE);
			String isolation = methodEle.getAttribute(ISOLATION_ATTRIBUTE);
			String timeout = methodEle.getAttribute(TIMEOUT_ATTRIBUTE);
			String readOnly = methodEle.getAttribute(READ_ONLY_ATTRIBUTE);
			if (StringUtils.hasText(propagation)) {
				attribute.setPropagationBehaviorName(RuleBasedTransactionAttribute.PREFIX_PROPAGATION + propagation);
			}
			if (StringUtils.hasText(isolation)) {
				attribute.setIsolationLevelName(RuleBasedTransactionAttribute.PREFIX_ISOLATION + isolation);
			}
			if (StringUtils.hasText(timeout)) {
				try {
					attribute.setTimeout(Integer.parseInt(timeout));
				}
				catch (NumberFormatException ex) {
					parserContext.getReaderContext().error("Timeout must be an integer value: [" + timeout + "]", methodEle);
				}
			}
			if (StringUtils.hasText(readOnly)) {
				attribute.setReadOnly(Boolean.parseBoolean(methodEle.getAttribute(READ_ONLY_ATTRIBUTE)));
			}

			List<RollbackRuleAttribute> rollbackRules = new ArrayList<>(1);
			if (methodEle.hasAttribute(ROLLBACK_FOR_ATTRIBUTE)) {
				String rollbackForValue = methodEle.getAttribute(ROLLBACK_FOR_ATTRIBUTE);
				addRollbackRuleAttributesTo(rollbackRules, rollbackForValue);
			}
			if (methodEle.hasAttribute(NO_ROLLBACK_FOR_ATTRIBUTE)) {
				String noRollbackForValue = methodEle.getAttribute(NO_ROLLBACK_FOR_ATTRIBUTE);
				addNoRollbackRuleAttributesTo(rollbackRules, noRollbackForValue);
			}
			attribute.setRollbackRules(rollbackRules);

			transactionAttributeMap.put(nameHolder, attribute);
		}

		RootBeanDefinition attributeSourceDefinition = new RootBeanDefinition(NameMatchTransactionAttributeSource.class);
		attributeSourceDefinition.setSource(parserContext.extractSource(attrEle));
		attributeSourceDefinition.getPropertyValues().add("nameMap", transactionAttributeMap);
		return attributeSourceDefinition;
	}

         可以看到这里就是解析对应的method标签,并且设置对应的隔离级别,传播属性,只读,回滚等属性,最后会把这些method放在一个NameMatchTransactionAttributeSource对象中。

        看到这里可以看到,目前就往容器放入了这些BeanDefinition。

         有了这些BeanDefinition之后,接下来就是创建对应bean对象。

         接下来就会根据对应的顺序来创建对应的bean。

        此时我们来看下对应的一级缓存中已经存在了哪些对象。 

        之前我们知道第一个创建bean对象的时候,会在AspectJAwareAutoProxyCreator的before方法之前去创建对应的advisor对象,我们直接断点到那里。

         然后就会在shouldSkip中去获取的advisor然后并且创建这个advisor。

         这里就获取得到我们直接解析配置文件放入的DefaultBeanFactoryPointcutAdvisor对象。

        然后就会去创建这个advisor。

        在创建这个advisor的时候,就会属性注入的时候就创建他对应的需要的两个属性,一个是pointcut对象一个是advice对象。

        第一个循环就会去创建对应的advice对象,然后第二个就回去创建对应pointcut对象。我们这里跳过。此时我们去看一下一级缓存里面已经创建好的对象有哪些。

        此时创建advisor需要提前创建以下对象。

        首先就会去解析第一个属性advice。

        可以看到,我们的adviceName还没有去创建,只是返回了一个引用名称。

 

        然后就会去解析第二个属性,pointcut对象。

        txpoint就会去解析并且创建出来对应的对象。

 

        以下是解析代码,我们继续往下跟。

@Nullable
	private Object resolveReference(Object argName, RuntimeBeanReference ref) {
		try {
			//定义用于一个存储bean对象的变量
			Object bean;
			//获取另一个Bean引用的Bean类型
			Class<?> beanType = ref.getBeanType();
			//如果引用来自父工厂
			if (ref.isToParent()) {
				//获取父工厂
				BeanFactory parent = this.beanFactory.getParentBeanFactory();
				//如果没有父工厂
				if (parent == null) {
					//抛出Bean创建异常:无法解析对bean的引用 ref 在父工厂中:没有可以的父工厂
					throw new BeanCreationException(
							this.beanDefinition.getResourceDescription(), this.beanName,
							"Cannot resolve reference to bean " + ref +
									" in parent factory: no parent factory available");
				}
				//如果引用的Bean类型不为null
				if (beanType != null) {
					//从父工厂中获取引用的Bean类型对应的Bean对象
					bean = parent.getBean(beanType);
				}
				else {
					//否则,使用引用的Bean名,从父工厂中获取对应的Bean对像
					bean = parent.getBean(String.valueOf(doEvaluate(ref.getBeanName())));
				}
			}
			else {
				//定义一个用于存储解析出来的Bean名的变量
				String resolvedName;
				//如果beanType不为null
				if (beanType != null) {
					//解析与beanType唯一匹配的bean实例,包括其bean名
					NamedBeanHolder<?> namedBean = this.beanFactory.resolveNamedBean(beanType);
					//让bean引用nameBean所封装的Bean对象
					bean = namedBean.getBeanInstance();
					//让resolvedName引用nameBean所封装的Bean名
					resolvedName = namedBean.getBeanName();
				}
				else {
					//让resolvedName引用ref所包装的Bean名
					resolvedName = String.valueOf(doEvaluate(ref.getBeanName()));
					//获取resolvedName的Bean对象
					bean = this.beanFactory.getBean(resolvedName);
				}
				//注册beanName与dependentBeanNamed的依赖关系到Bean工厂
				this.beanFactory.registerDependentBean(resolvedName, this.beanName);
			}
			//如果Bean对象是NullBean实例
			if (bean instanceof NullBean) {
				//将bean置为null
				bean = null;
			}
			//返回解析出来对应ref所封装的Bean元信息(即Bean名,Bean类型)的Bean对象
			return bean;
		}
		//捕捉Bean包和子包中引发的所有异常
		catch (BeansException ex) {
			throw new BeanCreationException(
					this.beanDefinition.getResourceDescription(), this.beanName,
					"Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex);
		}
	}

        此时我们的一级缓存里面只有这些对象,然后继续调用对呀的getBean。

        以上可以看到到解析adviceName的时候就只是返回了一个refName并没有去创建,而advisor则创建了出来,那advice是什么时候创建呢?

        我们再来重温一下,他是如何生成代理对象的。

	/**
	 * 此处是真正创建aop代理的地方,在实例化之后,初始化之后就行处理
	 * 首先查看是否在earlyProxyReferences里存在,如果有就说明处理过了,不存在就考虑是否要包装,也就是代理
	 *
	 * Create a proxy with the configured interceptors if the bean is
	 * identified as one to proxy by the subclass.
	 * @see #getAdvicesAndAdvisorsForBean
	 */
	@Override
	public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
		if (bean != null) {
			// 获取当前bean的key:如果beanName不为空,则以beanName为key,如果为FactoryBean类型,
			// 前面还会添加&符号,如果beanName为空,则以当前bean对应的class为key
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			// 判断当前bean是否正在被代理,如果正在被代理则不进行封装
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
				// 如果它需要被代理,则需要封装指定的bean
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}

        然后知道合适的advisor对象,我们继续往里面看他是如何去找的。

	/**
	 * 检查前面切面解析是否有通知器advisors创建,有就返回,没有就是null
	 * @param beanClass the class of the bean to advise
	 * @param beanName the name of the bean
	 * @param targetSource
	 * @return
	 */
	@Override
	@Nullable
	protected Object[] getAdvicesAndAdvisorsForBean(
			Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {

		// 找合适的增强器对象
		List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
		// 若为空表示没找到
		if (advisors.isEmpty()) {
			return DO_NOT_PROXY;
		}
		return advisors.toArray();
	}

	protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
		// 将当前系统中所有的切面类的切面逻辑进行封装,从而得到目标Advisor
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		// 对获取到的所有Advisor进行判断,看其切面定义是否可以应用到当前bean,从而得到最终需要应用的Advisor
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
		// 提供的hook方法,用于对目标Advisor进行扩展
		extendAdvisors(eligibleAdvisors);
		if (!eligibleAdvisors.isEmpty()) {
			// 对需要代理的Advisor按照一定的规则进行排序
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}
		return eligibleAdvisors;
	}

        我们知道他找到对应的advisor集合对象之后,会在extendAdvisors中添加一个exposeInvocationInterceptor对象,我们继续往里面看。

	/**
	 * Add an {@link ExposeInvocationInterceptor} to the beginning of the advice chain.
	 * <p>This additional advice is needed when using AspectJ pointcut expressions
	 * and when using AspectJ-style advice.
	 */
	@Override
	protected void extendAdvisors(List<Advisor> candidateAdvisors) {
		AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
	}

	public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) {
		// Don't add advisors to an empty list; may indicate that proxying is just not required
		if (!advisors.isEmpty()) {
			boolean foundAspectJAdvice = false;
			for (Advisor advisor : advisors) {
				// Be careful not to get the Advice without a guard, as this might eagerly
				// instantiate a non-singleton AspectJ aspect...
				if (isAspectJAdvice(advisor)) {
					foundAspectJAdvice = true;
					break;
				}
			}
			if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
				advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
				return true;
			}
		}
		return false;
	}

        这里就会循环传入的advisor对象,我们继续跟一下 isAspectJAdvice方法。

	/**
	 * Determine whether the given Advisor contains an AspectJ advice.
	 * @param advisor the Advisor to check
	 */
	private static boolean isAspectJAdvice(Advisor advisor) {
		return (advisor instanceof InstantiationModelAwarePointcutAdvisor ||
				advisor.getAdvice() instanceof AbstractAspectJAdvice ||
				(advisor instanceof PointcutAdvisor &&
						((PointcutAdvisor) advisor).getPointcut() instanceof AspectJExpressionPointcut));
	}

        然后就会去获取advice对象,继续往下跟。

	@Override
	public Advice getAdvice() {
		Advice advice = this.advice;
		// 非Spring环境一般手动set进来,所以就直接返回吧
		if (advice != null) {
			return advice;
		}

		Assert.state(this.adviceBeanName != null, "'adviceBeanName' must be specified");
		Assert.state(this.beanFactory != null, "BeanFactory must be set to resolve 'adviceBeanName'");

		// 若bean是单例的,那就没什么好说的,直接去工厂里拿出来就完事了(Advice.class),有可能返回null
		if (this.beanFactory.isSingleton(this.adviceBeanName)) {
			// Rely on singleton semantics provided by the factory.
			advice = this.beanFactory.getBean(this.adviceBeanName, Advice.class);
			this.advice = advice;
			return advice;
		}
		// 若是多例的,就加锁,然后调用getBean()给他生成一个新的实例即可
		else {
			// No singleton guarantees from the factory -> let's lock locally but
			// reuse the factory's singleton lock, just in case a lazy dependency
			// of our advice bean happens to trigger the singleton lock implicitly...
			synchronized (this.adviceMonitor) {
				advice = this.advice;
				if (advice == null) {
					advice = this.beanFactory.getBean(this.adviceBeanName, Advice.class);
					this.advice = advice;
				}
				return advice;
			}
		}

        可以看得到这里就会调用对应的getBean方法,把我们刚刚没创建的advice对象创建出来。 

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值