当前位置: 首页 > news >正文

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);}}@Nullablepublic BeanDefinition parseCustomElement(Element ele) {return parseCustomElement(ele, null);}@Nullablepublic BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {// 获取对应的命名空间String namespaceUri = getNamespaceURI(ele);if (namespaceUri == null) {return null;}// 根据命名空间找到对应的NamespaceHandlerspringNamespaceHandler 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@Nullablepublic 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信息的。

@Overrideprotected 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@Overridepublic MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {List<MethodInterceptor> interceptors = new ArrayList<>(3);// 从Advisor中获取 AdviceAdvice advice = advisor.getAdvice();if (advice instanceof MethodInterceptor) {interceptors.add((MethodInterceptor) advice);}for (AdvisorAdapter adapter : this.adapters) {if (adapter.supportsAdvice(advice)) {// 转换为对应的 MethodInterceptor类型// AfterReturningAdviceInterceptor MethodBeforeAdviceInterceptor  ThrowsAdviceInterceptorinterceptors.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方法。

	@Overrideprotected 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就会去解析并且创建出来对应的对象。

 

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

@Nullableprivate 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类型不为nullif (beanType != null) {//从父工厂中获取引用的Bean类型对应的Bean对象bean = parent.getBean(beanType);}else {//否则,使用引用的Bean名,从父工厂中获取对应的Bean对像bean = parent.getBean(String.valueOf(doEvaluate(ref.getBeanName())));}}else {//定义一个用于存储解析出来的Bean名的变量String resolvedName;//如果beanType不为nullif (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置为nullbean = 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*/@Overridepublic Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {if (bean != null) {// 获取当前bean的key:如果beanName不为空,则以beanName为key,如果为FactoryBean类型,// 前面还会添加&符号,如果beanName为空,则以当前bean对应的class为keyObject cacheKey = getCacheKey(bean.getClass(), beanName);// 判断当前bean是否正在被代理,如果正在被代理则不进行封装if (this.earlyProxyReferences.remove(cacheKey) != bean) {// 如果它需要被代理,则需要封装指定的beanreturn 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@Nullableprotected 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) {// 将当前系统中所有的切面类的切面逻辑进行封装,从而得到目标AdvisorList<Advisor> candidateAdvisors = findCandidateAdvisors();// 对获取到的所有Advisor进行判断,看其切面定义是否可以应用到当前bean,从而得到最终需要应用的AdvisorList<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.*/@Overrideprotected 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 requiredif (!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对象,继续往下跟。

	@Overridepublic 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),有可能返回nullif (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对象创建出来。 

http://www.lryc.cn/news/421126.html

相关文章:

  • win11安装docker报错记录
  • 【vulnhub】CLAMP 1.0.1靶机
  • GPS跟踪环路MATLAB之——数字锁相环
  • docker开发环境搭建-关于数据库的IP是什么
  • loginApi
  • 【RAG检索增强生成】Ollama+AnythingLLM本地搭建RAG大模型私有知识库
  • 【wiki知识库】08.添加用户登录功能--前端Vue部分修改
  • 写给非机器学习人员的 embedding 入门
  • Oracle【plsql编写九九乘法表】
  • ansible安装K8s
  • restful传值
  • Qt自定义TreeWidget,实现展开折叠按钮在右侧,且一条竖直线上对齐
  • 硅步千里:如何入行?——之入行成为软件开发者
  • Sandbox: rsync.samba(80134) deny(1) file-write-create
  • lvs的dr模式综合实践
  • 什么是自然语言处理
  • 快速理解互联网中的常用名词
  • 统计接口调用耗时_黑白名单配置
  • 树莓派4 AV没有视频输出
  • 短信群发平台:解决短信验证码接收问题的5大策略
  • WebSocket 初体验:构建实时通信应用
  • LISA: Reasoning Segmentation via Large Language Model
  • 企业发展与数字化转型:创新驱动未来增长的关键策略
  • 如何选择适合自己的编程语言,为什么R是非计算机专业数据分析的最佳选择,五大点告诉你
  • 【经验分享】数据结构——求树的叶子结点个数计算方法
  • 第十一章:图论part04 110.字符串接龙 105.有向图的完全可达性 106.岛屿的周长(补)
  • Linux中安装MYSQL数据库
  • Vue前端服务加密后端服务解密--AES算法实现
  • matlab实现文字识别
  • Leetcode - 周赛409