Spring AOP源码篇三之 xml配置

简单代码示例, 了解Spring AOP基于xml的基本用法

xml配置:

<?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:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"><bean id="aopAdvice" class="org.spring.aop.parse.advice.AopAdvice"></bean><!-- 第一种配置方式 --><aop:config proxy-target-class="false"><aop:aspect ref="aopAdvice"><aop:pointcut expression="execution(* org.spring.aop.parse.service..*.*(..))" id="callAt"/><aop:around method="around" pointcut-ref="callAt"/><aop:before method="before" pointcut="execution(* org.spring.aop.parse.service..*.*(..))"/><aop:after method="after" pointcut="execution(* org.spring.aop.parse.service..*.*(..))"/></aop:aspect></aop:config><!--<aop:config proxy-target-class="true"><aop:pointcut id="callAt" expression="execution(* org.spring.aop.service..*.*(..))"></aop:pointcut></aop:config>--><!-- 第二种配置方式 --><bean id="logAdvice" class="org.spring.aop.parse.advice.LogAdvice"></bean><aop:config proxy-target-class="false"><!--<aop:pointcut id="callAt" expression="execution(* org.spring.aop.service..*.*(..))"></aop:pointcut>--><aop:advisor id="logAdvisor" advice-ref="logAdvice" pointcut="execution(* org.spring.aop.parse.service..*.*(..))"></aop:advisor><!--<aop:advisor id="logAdvisor" advice-ref="logAdvice" pointcut-ref="callAt"></aop:advisor>--></aop:config><!-- 第三种引介增强 --><!--<bean id="addService" class="org.spring.aop.parse.advice.AddService"/>--><aop:config proxy-target-class="false"><aop:aspect ref="aopAdvice"><aop:declare-parents types-matching="org.spring.aop.parse.service.*" implement-interface="org.spring.aop.parse.advice.IAddService" default-impl="org.spring.aop.parse.advice.AddService"/><!--<aop:declare-parents types-matching="org.spring.aop.parse.service.*" implement-interface="org.spring.aop.parse.advice.IAddService" delegate-ref="addService"/>--></aop:aspect></aop:config><bean id="userService" class="org.spring.aop.parse.service.UserService"/>
</beans>

测试代码:

package org.spring.aop.parse;import org.spring.aop.parse.advice.IAddService;
import org.spring.aop.parse.service.IUserService;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class MainTest {public static void main(String[] args) {ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-config-aop.xml");applicationContext.start();Object objService = applicationContext.getBean("userService");IUserService userService = (IUserService)objService;userService.say();System.out.println("\n-------------对目标对象引介增强-----------------\n");IAddService addService = (IAddService)objService;addService.doSomething();applicationContext.stop();}
}

执行结果:

=======================开始从源码分析过程========================
从handler中找到标签对应的NamespaceHandler:AopNamespaceHandler
从AopNamespaceHandler中找到标签对应的BeanDefinitionParser:ConfigBeanDefinitionParser,ConfigBeanDefinitionParser就是源码第一个关键入口

ConfigBeanDefinitionParser:将xml配置准换为Advisor的BeanDefinition,在ApplicationContext的refresh()中自动调用,将BeanDefinition转为Advisor对象。
package org.springframework.aop.config;import java.util.ArrayList;
import java.util.List;import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;import org.springframework.aop.aspectj.AspectJAfterAdvice;
import org.springframework.aop.aspectj.AspectJAfterReturningAdvice;
import org.springframework.aop.aspectj.AspectJAfterThrowingAdvice;
import org.springframework.aop.aspectj.AspectJAroundAdvice;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.aspectj.AspectJMethodBeforeAdvice;
import org.springframework.aop.aspectj.AspectJPointcutAdvisor;
import org.springframework.aop.aspectj.DeclareParentsAdvisor;
import org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanReference;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.config.RuntimeBeanNameReference;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
import org.springframework.beans.factory.parsing.ParseState;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;public class ConfigBeanDefinitionParser implements BeanDefinitionParser {private static final String ASPECT = "aspect";private static final String EXPRESSION = "expression";private static final String ID = "id";private static final String POINTCUT = "pointcut";private static final String ADVICE_BEAN_NAME = "adviceBeanName";private static final String ADVISOR = "advisor";private static final String ADVICE_REF = "advice-ref";private static final String POINTCUT_REF = "pointcut-ref";private static final String REF = "ref";private static final String BEFORE = "before";private static final String DECLARE_PARENTS = "declare-parents";private static final String TYPE_PATTERN = "types-matching";private static final String DEFAULT_IMPL = "default-impl";private static final String DELEGATE_REF = "delegate-ref";private static final String IMPLEMENT_INTERFACE = "implement-interface";private static final String AFTER = "after";private static final String AFTER_RETURNING_ELEMENT = "after-returning";private static final String AFTER_THROWING_ELEMENT = "after-throwing";private static final String AROUND = "around";private static final String RETURNING = "returning";private static final String RETURNING_PROPERTY = "returningName";private static final String THROWING = "throwing";private static final String THROWING_PROPERTY = "throwingName";private static final String ARG_NAMES = "arg-names";private static final String ARG_NAMES_PROPERTY = "argumentNames";private static final String ASPECT_NAME_PROPERTY = "aspectName";private static final String DECLARATION_ORDER_PROPERTY = "declarationOrder";private static final String ORDER_PROPERTY = "order";private static final int METHOD_INDEX = 0;private static final int POINTCUT_INDEX = 1;private static final int ASPECT_INSTANCE_FACTORY_INDEX = 2;private ParseState parseState = new ParseState();/**<bean id="logBeforeAdvice" class="org.spring.aop.config.LogBeforeAdvice"></bean><aop:config proxy-target-class="true"><aop:advisor id="logBeforeAdvisor" advice-ref="logBeforeAdvice" pointcut="execution(* org.spring.aop.service..*.*(..))"></aop:advisor></aop:config>注意:<aop:advisor>生成的advisor的BeanDefinition的beanClass类型是:DefaultBeanFactoryPointcutAdvisor,对应构造函数是无参构造函数<aop:advisor>属性advice-ref对应的 advice bean 是自定义的,需要实现接口Advice<aop:config proxy-target-class="true"><aop:aspect ref="aopAdvice"><aop:pointcut expression="execution(* org.spring.aop.service..*.*(..))" id="callAt"/><aop:around method="around" pointcut-ref="callAt"/><aop:before method="before" pointcut="execution(* org.spring.aop.service..*.*(..))"/></aop:aspect></aop:config>注意:<aop:aspect>生成的advisor的BeanDefinition的beanClass类型是:AspectJPointcutAdvisor,对应构成函数AspectJPointcutAdvisor(AbstractAspectJAdvice advice)<aop:aspect>下的每个Advice都有自己的实现1、<aop:around>==》AspectJAroundAdvice2、<aop:before>==》AspectJMethodBeforeAdvice3、<aop:after>==》AspectJAfterAdvice4、<aop:after-returning>==》AspectJAfterReturningAdvice5、<aop:after-throwing>==》AspectJAfterThrowingAdvice上面Advice构造函数初始化时会匹配三参构造函数:AbstractAspectJAdvice(Method aspectJAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aspectInstanceFactory)AbstractAspectJAdvice是上面5个Advice的父类所有的PointCut生成的BeanDefinition的beanClass类型是:AspectJExpressionPointcut解析完成后会将生成的advisor的BeanDefinition注册到IOC容器如果pointcut是元素<aop:pointcut>生成的BeanDefinition会注册到IOC容器;如果pointcut是属性pointcut="execution(* org.spring.aop.service..*.*(..))"生成的BeanDefinition不会注册到IOC容器;*/@Overridepublic BeanDefinition parse(Element element, ParserContext parserContext) {CompositeComponentDefinition compositeDef =new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));parserContext.pushContainingComponent(compositeDef);/*** @see AspectJAwareAdvisorAutoProxyCreator* 创建BeanDefinition,对应的beanClass为AspectJAwareAdvisorAutoProxyCreator* 实现了后置处理器 SmartInstantiationAwareBeanPostProcessor、InstantiationAwareBeanPostProcessor、BeanPostProcessor*SmartInstantiationAwareBeanPostProcessor//AbstractAutoProxyCreator#predictBeanTypeClass<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException;//AbstractAutoProxyCreator#determineCandidateConstructors  直接返回nullConstructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException;//AbstractAutoProxyCreator#getEarlyBeanReferenceObject getEarlyBeanReference(Object bean, String beanName) throws BeansException;InstantiationAwareBeanPostProcessor//负责创建advisor,在每个bean创建前执行,关键入口//AbstractAutoProxyCreator#postProcessBeforeInstantiationObject postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException;//AbstractAutoProxyCreator#postProcessAfterInstantiation  直接返回trueboolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException;//AbstractAutoProxyCreator#postProcessPropertyValues 直接返回pvsPropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException;BeanPostProcessor//AbstractAutoProxyCreator#postProcessBeforeInitialization 直接返回beanObject postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;//负责创建aop相关工作,将advisor关联到bean,在每个bean创建并初始化完成后执行,关键入口//AbstractAutoProxyCreator#postProcessAfterInitializationObject postProcessAfterInitialization(Object bean, String beanName) throws BeansException;**/configureAutoProxyCreator(parserContext, element);List<Element> childElts = DomUtils.getChildElements(element);for (Element elt: childElts) {String localName = parserContext.getDelegate().getLocalName(elt);if (POINTCUT.equals(localName)) {parsePointcut(elt, parserContext);}else if (ADVISOR.equals(localName)) {parseAdvisor(elt, parserContext);}else if (ASPECT.equals(localName)) {parseAspect(elt, parserContext);}}parserContext.popAndRegisterContainingComponent();return null;}/*** 创建BeanDefinition,对应的beanClass为AspectJAwareAdvisorAutoProxyCreator* @see AspectJAwareAdvisorAutoProxyCreator** 实现了后置处理器 SmartInstantiationAwareBeanPostProcessor--实现-》InstantiationAwareBeanPostProcessor-实现--》BeanPostProcessor**/private void configureAutoProxyCreator(ParserContext parserContext, Element element) {AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element);}/*** 解析元素<aop:pointcut/>*<aop:config proxy-target-class="true"><aop:pointcut id="callAt" expression="execution(* org.spring.aop.service..*.*(..))"></aop:pointcut></aop:config>*  创建Pointcut BeanDefinition,beanClass为:AspectJExpressionPointcut* @see AspectJExpressionPointcut* 设置beanDefinition 属性 expression*/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));//创建Pointcut BeanDefinition,beanClass为:AspectJExpressionPointcutpointcutDefinition = createPointcutDefinition(expression);pointcutDefinition.setSource(parserContext.extractSource(pointcutElement));//设置Pointcut BeanDefinition的beanName为id,如果id为空,用beanClassName+递增数字String pointcutBeanName = id;if (StringUtils.hasText(pointcutBeanName)) {parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition);}else {pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition);}parserContext.registerComponent(new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression));}finally {this.parseState.pop();}return pointcutDefinition;}/*** 解析元素<aop:advisor/>*<bean id="logBeforeAdvice" class="org.spring.aop.config.LogBeforeAdvice"></bean><aop:config proxy-target-class="true"><aop:advisor id="logBeforeAdvisor" advice-ref="logBeforeAdvice" pointcut="execution(* org.spring.aop.service..*.*(..))"></aop:advisor></aop:config>*  创建Advisor对应的BeanDefinition,beanClass为:DefaultBeanFactoryPointcutAdvisor* @see DefaultBeanFactoryPointcutAdvisor* 设置beanDefinition 属性 expression*/private void parseAdvisor(Element advisorElement, ParserContext parserContext) {//创建Advisor对应的BeanDefinition,beanClass为:DefaultBeanFactoryPointcutAdvisorAbstractBeanDefinition advisorDef = createAdvisorBeanDefinition(advisorElement, parserContext);String id = advisorElement.getAttribute(ID);try {this.parseState.push(new AdvisorEntry(id));String advisorBeanName = id;if (StringUtils.hasText(advisorBeanName)) {parserContext.getRegistry().registerBeanDefinition(advisorBeanName, advisorDef);}else {advisorBeanName = parserContext.getReaderContext().registerWithGeneratedName(advisorDef);}//设置依赖的PointcutObject pointcut = parsePointcutProperty(advisorElement, parserContext);if (pointcut instanceof BeanDefinition) { //pointcut,属性值为BeanDefinition,后续填充属性时,做依赖bean处理advisorDef.getPropertyValues().add(POINTCUT, pointcut);parserContext.registerComponent(new AdvisorComponentDefinition(advisorBeanName, advisorDef, (BeanDefinition) pointcut));}else if (pointcut instanceof String) {//pointcut-ref,属性值为RuntimeBeanReference,后续填充属性时,做依赖bean处理advisorDef.getPropertyValues().add(POINTCUT, new RuntimeBeanReference((String) pointcut));parserContext.registerComponent(new AdvisorComponentDefinition(advisorBeanName, advisorDef));}}finally {this.parseState.pop();}}/*** 解析元素<aop:aspect/>*<bean id="aopAdvice" class="org.spring.aop.aspectj.AopAdvice"></bean><aop:config proxy-target-class="true"><aop:aspect ref="aopAdvice"><aop:pointcut expression="execution(* org.spring.aop.service..*.*(..))" id="callAt"/><aop:around method="around" pointcut-ref="callAt"/><aop:before method="before" pointcut="execution(* org.spring.aop.service..*.*(..))"/><aop:after method="before" pointcut="execution(* org.spring.aop.service..*.*(..))"/></aop:aspect></aop:config>***  创建Pointcut BeanDefinition,beanClass为:AspectJExpressionPointcut* @see AspectJExpressionPointcut* 设置beanDefinition 属性 expression  AspectJPointcutAdvisor*/private void parseAspect(Element aspectElement, ParserContext parserContext) {String aspectId = aspectElement.getAttribute(ID);String aspectName = aspectElement.getAttribute(REF);try {this.parseState.push(new AspectEntry(aspectId, aspectName));//存储BeanDefinition形式的PointCutList<BeanDefinition> beanDefinitions = new ArrayList<>();//存储BeanReference形式的PointCut 额外存储了beanReferences.add(new RuntimeBeanReference(aspectName))List<BeanReference> beanReferences = new ArrayList<>();//解析引介增强方式List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS);for (int i = METHOD_INDEX; i < declareParents.size(); i++) {Element declareParentsElement = declareParents.get(i);beanDefinitions.add(parseDeclareParents(declareParentsElement, parserContext));}// We have to parse "advice" and all the advice kinds in one loop, to get the// ordering semantics right./*循环Advice,生成Advice和Advisor的BeanDefinitionAdvice与Advisor一样对应*/NodeList nodeList = aspectElement.getChildNodes();boolean adviceFoundAlready = false;for (int i = 0; i < nodeList.getLength(); i++) {Node node = nodeList.item(i);if (isAdviceNode(node, parserContext)) {if (!adviceFoundAlready) {adviceFoundAlready = true;if (!StringUtils.hasText(aspectName)) {parserContext.getReaderContext().error("<aspect> tag needs aspect bean reference via 'ref' attribute when declaring advices.",aspectElement, this.parseState.snapshot());return;}beanReferences.add(new RuntimeBeanReference(aspectName));}//生成单个Advisor的DefinitionAbstractBeanDefinition advisorDefinition = parseAdvice(aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences);beanDefinitions.add(advisorDefinition);}}//注册事件相关的AspectComponentDefinition aspectComponentDefinition = createAspectComponentDefinition(aspectElement, aspectId, beanDefinitions, beanReferences, parserContext);parserContext.pushContainingComponent(aspectComponentDefinition);List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);for (Element pointcutElement : pointcuts) {//解析里面的<aop:pointcut>元素parsePointcut(pointcutElement, parserContext);}//注册事件相关的parserContext.popAndRegisterContainingComponent();}finally {this.parseState.pop();}}//注册事件相关的private AspectComponentDefinition createAspectComponentDefinition(Element aspectElement, String aspectId, List<BeanDefinition> beanDefs,List<BeanReference> beanRefs, ParserContext parserContext) {BeanDefinition[] beanDefArray = beanDefs.toArray(new BeanDefinition[beanDefs.size()]);BeanReference[] beanRefArray = beanRefs.toArray(new BeanReference[beanRefs.size()]);Object source = parserContext.extractSource(aspectElement);return new AspectComponentDefinition(aspectId, beanDefArray, beanRefArray, source);}/***  创建Pointcut对应的BeanDefinition,beanClass为:AspectJExpressionPointcut* @see AspectJExpressionPointcut** 设置beanDefinition 属性 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;}/***  创建Advisor对应的BeanDefinition,beanClass为:DefaultBeanFactoryPointcutAdvisor* @see DefaultBeanFactoryPointcutAdvisor** 设置beanDefinition 属性 expression*/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 { //设置依赖的AdviceadvisorDefinition.getPropertyValues().add(ADVICE_BEAN_NAME, new RuntimeBeanNameReference(adviceRef));}if (advisorElement.hasAttribute(ORDER_PROPERTY)) {advisorDefinition.getPropertyValues().add(ORDER_PROPERTY, advisorElement.getAttribute(ORDER_PROPERTY));}return advisorDefinition;}/*** 解析pointcut或者pointcut-ref,属性不能同时出现,二者选一*  pointcut="execution(* org.spring.aop.service..*.*(..))"*  pointcut-ref="callAt"** @return*/private Object parsePointcutProperty(Element element, ParserContext parserContext) {if (element.hasAttribute(POINTCUT) && element.hasAttribute(POINTCUT_REF)) {parserContext.getReaderContext().error("Cannot define both 'pointcut' and 'pointcut-ref' on <advisor> tag.",element, this.parseState.snapshot());return null;}else if (element.hasAttribute(POINTCUT)) { //为pointcut时,创建BeanDefinition,beanClass为:AspectJExpressionPointcutString expression = element.getAttribute(POINTCUT);AbstractBeanDefinition pointcutDefinition = createPointcutDefinition(expression);pointcutDefinition.setSource(parserContext.extractSource(element));return pointcutDefinition;}else if (element.hasAttribute(POINTCUT_REF)) { //为pointcut-ref时,直接返回字符串内容String pointcutRef = element.getAttribute(POINTCUT_REF);if (!StringUtils.hasText(pointcutRef)) {parserContext.getReaderContext().error("'pointcut-ref' attribute contains empty value.", element, this.parseState.snapshot());return null;}return pointcutRef;}else {parserContext.getReaderContext().error("Must define one of 'pointcut' or 'pointcut-ref' on <advisor> tag.",element, this.parseState.snapshot());return null;}}/*1、创建PointCut的BeanDefinition,PointCut代表拦截点2、创建Advice的BeanDefinition,Advice代表在哪个位置增强,around、before、after、return、throw3、创建Advisor的BeanDefinition,持有Advice的BeanDefinition*///beanDefinitions, BeanDefinition形式的PointCut//beanReferences, BeanReference形式的PointCutprivate AbstractBeanDefinition parseAdvice(String aspectName, int order, Element aspectElement, Element adviceElement, ParserContext parserContext,List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {try {this.parseState.push(new AdviceEntry(parserContext.getDelegate().getLocalName(adviceElement)));/*<bean id="aopAdvice" class="org.spring.aop.aspectj.AopAdvice"></bean><aop:config proxy-target-class="true"><aop:aspect ref="aopAdvice"><aop:around method="around" pointcut-ref="execution(* org.spring.aop.service..*.*(..))"/></aop:aspect></aop:config>*///MethodLocatingFactoryBean主要用途是根据类名(targetBeanName)和方法名(methodName)获取Advice实例的method方法对象 AopAdvice.around()RootBeanDefinition methodDefinition = new RootBeanDefinition(MethodLocatingFactoryBean.class);methodDefinition.getPropertyValues().add("targetBeanName", aspectName);methodDefinition.getPropertyValues().add("methodName", adviceElement.getAttribute("method"));methodDefinition.setSynthetic(true);//SimpleBeanFactoryAwareAspectInstanceFactory用途主要是根据aspectBeanName获取Advice的Bean实例//<bean id="aopAdvice" class="org.spring.aop.aspectj.AopAdvice"></bean>//将来可以查询bean==》aopAdviceRootBeanDefinition aspectFactoryDef =new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class);aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName);aspectFactoryDef.setSynthetic(true);// 创建Advice的BeanDefinition//AspectJAroundAdvice构造方法==>public AspectJAroundAdvice(Method aspectJAroundAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {}//下面代码构建上述构造函数的BeanDefinitionAbstractBeanDefinition adviceDef = createAdviceDefinition(adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef,beanDefinitions, beanReferences);// 创建Advisor的BeanDefinition, 构造函数参数是上面Advice的BeanDefinitionRootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);advisorDefinition.setSource(parserContext.extractSource(adviceElement));advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef);if (aspectElement.hasAttribute(ORDER_PROPERTY)) {advisorDefinition.getPropertyValues().add(ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY));}// 将advisor的BeanDefinition注册进IOC容器parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition);return advisorDefinition;}finally {this.parseState.pop();}}/*创建advice对应的BeanDefinition,BeanDefinition的beanClass由advice元素名称决定1、<aop:around>==》AspectJAroundAdvice2、<aop:before>==》AspectJMethodBeforeAdvice3、<aop:after>==》AspectJAfterAdvice4、<aop:after-returning>==》AspectJAfterReturningAdvice5、<aop:after-throwing>==》AspectJAfterThrowingAdviceBeanDefinition有三个构造函数参数第一个参数:methodDef ==> RootBeanDefinition(MethodLocatingFactoryBean.class)有两个属性:targetBeanName对应<aop:aspect ref="aopAdvice">的ref值methodName对应<aop:around method="around">的method值第二个参数:pointcut<aop:around pointcut-ref="callAt"/>类型就是RuntimeBeanReference(expression),其实最后还是AspectJExpressionPointcut<aop:before pointcut="execution(* xxx.xxx.service..*.*(..))"/>类型就是RootBeanDefinition(AspectJExpressionPointcut)第三个参数:aspectFactoryDef ==> RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class)有个一个属性:aspectBeanName对应<aop:aspect ref="aopAdvice">的ref值比如环绕advice: AspectJAroundAdvice构造方法==>public AspectJAroundAdvice(Method aspectJAroundAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {}*///beanDefinitions, BeanDefinition形式的PointCut,后面直接注册进IOC容器//beanReferences, BeanReference形式的PointCut,后面封装成BeanDefinition注册进IOC容器private AbstractBeanDefinition createAdviceDefinition(Element adviceElement, ParserContext parserContext, String aspectName, int order,RootBeanDefinition methodDef, RootBeanDefinition aspectFactoryDef,List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {RootBeanDefinition adviceDefinition = new RootBeanDefinition(getAdviceClass(adviceElement, parserContext));adviceDefinition.setSource(parserContext.extractSource(adviceElement));adviceDefinition.getPropertyValues().add(ASPECT_NAME_PROPERTY, aspectName);adviceDefinition.getPropertyValues().add(DECLARATION_ORDER_PROPERTY, order);if (adviceElement.hasAttribute(RETURNING)) {adviceDefinition.getPropertyValues().add(RETURNING_PROPERTY, adviceElement.getAttribute(RETURNING));}if (adviceElement.hasAttribute(THROWING)) {adviceDefinition.getPropertyValues().add(THROWING_PROPERTY, adviceElement.getAttribute(THROWING));}if (adviceElement.hasAttribute(ARG_NAMES)) {adviceDefinition.getPropertyValues().add(ARG_NAMES_PROPERTY, adviceElement.getAttribute(ARG_NAMES));}//创建adviceDefinition的构造函数ConstructorArgumentValues cav = adviceDefinition.getConstructorArgumentValues();cav.addIndexedArgumentValue(METHOD_INDEX, methodDef);/*** 解析pointcut或者pointcut-ref,属性不能同时出现,二者选一*  pointcut="execution(* org.spring.aop.service..*.*(..))"*  pointcut-ref="callAt"*/Object pointcut = parsePointcutProperty(adviceElement, parserContext);if (pointcut instanceof BeanDefinition) {cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcut);beanDefinitions.add((BeanDefinition) pointcut);}else if (pointcut instanceof String) {RuntimeBeanReference pointcutRef = new RuntimeBeanReference((String) pointcut);cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcutRef);beanReferences.add(pointcutRef);}cav.addIndexedArgumentValue(ASPECT_INSTANCE_FACTORY_INDEX, aspectFactoryDef);return adviceDefinition;}/** 根据advice元素名称获取对应的beanClass*  <aop:around>==》AspectJAroundAdvice*  <aop:before>==》AspectJMethodBeforeAdvice*  <aop:after>==》AspectJAfterAdvice*  <aop:after-returning>==》AspectJAfterReturningAdvice*  <aop:after-throwing>==》AspectJAfterThrowingAdvice**/private Class getAdviceClass(Element adviceElement, ParserContext parserContext) {String elementName = parserContext.getDelegate().getLocalName(adviceElement);if (BEFORE.equals(elementName)) {return AspectJMethodBeforeAdvice.class;}else if (AFTER.equals(elementName)) {return AspectJAfterAdvice.class;}else if (AFTER_RETURNING_ELEMENT.equals(elementName)) {return AspectJAfterReturningAdvice.class;}else if (AFTER_THROWING_ELEMENT.equals(elementName)) {return AspectJAfterThrowingAdvice.class;}else if (AROUND.equals(elementName)) {return AspectJAroundAdvice.class;}else {throw new IllegalArgumentException("Unknown advice kind [" + elementName + "].");}}/*** 判断是否为advice节点元素*/private boolean isAdviceNode(Node aNode, ParserContext parserContext) {if (!(aNode instanceof Element)) {return false;}else {String name = parserContext.getDelegate().getLocalName(aNode);return (BEFORE.equals(name) || AFTER.equals(name) || AFTER_RETURNING_ELEMENT.equals(name) ||AFTER_THROWING_ELEMENT.equals(name) || AROUND.equals(name));}}/***  解析引介增强方式 	<aop:declare-parents types-matching="匹配要被引介增强的类" implement-interface="引介增强接口" default-impl="引介增强实现类"/>* @return*/private AbstractBeanDefinition parseDeclareParents(Element declareParentsElement, ParserContext parserContext) {BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(DeclareParentsAdvisor.class);//引介增强接口builder.addConstructorArgValue(declareParentsElement.getAttribute(IMPLEMENT_INTERFACE));//匹配要被引介增强的类builder.addConstructorArgValue(declareParentsElement.getAttribute(TYPE_PATTERN));//引介增强实现类全路径String defaultImpl = declareParentsElement.getAttribute(DEFAULT_IMPL);//引介增强实现类bean对象String delegateRef = declareParentsElement.getAttribute(DELEGATE_REF);if (StringUtils.hasText(defaultImpl) && !StringUtils.hasText(delegateRef)) {builder.addConstructorArgValue(defaultImpl);}else if (StringUtils.hasText(delegateRef) && !StringUtils.hasText(defaultImpl)) {builder.addConstructorArgReference(delegateRef);}else {parserContext.getReaderContext().error("Exactly one of the " + DEFAULT_IMPL + " or " + DELEGATE_REF + " attributes must be specified",declareParentsElement, this.parseState.snapshot());}AbstractBeanDefinition definition = builder.getBeanDefinition();definition.setSource(parserContext.extractSource(declareParentsElement));parserContext.getReaderContext().registerWithGeneratedName(definition);return definition;}
}
AspectJAwareAdvisorAutoProxyCreator:ConfigBeanDefinitionParser中会创建AspectJAwareAdvisorAutoProxyCreator的BeanDefinition,在ApplicationContext的refresh()中自动调用,将AspectJAwareAdvisorAutoProxyCreator转为对象。

AspectJAwareAdvisorAutoProxyCreator实现了接口BeanPostProcessor,说明它是个后置处理器,所以每个bean初始化完成后会执行BeanPostProcessor.postProcessAfterInitialization(Object bean, String beanName),对应实现在父类AbstractAutoProxyCreator
package org.springframework.aop.framework.autoproxy;public abstract class AbstractAutoProxyCreator extends ProxyConfigimplements SmartInstantiationAwareBeanPostProcessor, BeanClassLoaderAware, BeanFactoryAware,Ordered, AopInfrastructureBean {// ...其它代码代码(略)//源码分析:节点1//关键入口public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if (bean != null) {Object cacheKey = getCacheKey(bean.getClass(), beanName);if (!this.earlyProxyReferences.containsKey(cacheKey)) {//源码分析:节点2return wrapIfNecessary(bean, beanName, cacheKey);}}return bean;}//源码分析:节点2protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {if (beanName != null && this.targetSourcedBeans.containsKey(beanName)) {return bean;}if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {return bean;}if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;}//源码分析:节点3// 将当前容器中的所以Advisor和当前bean匹配,最后将匹配成功的Advisor列表返回Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);if (specificInterceptors != DO_NOT_PROXY) {this.advisedBeans.put(cacheKey, Boolean.TRUE);//源码分析:节点4//创建代理对象Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));this.proxyTypes.put(cacheKey, proxy.getClass());return proxy;}this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;}//源码分析:节点4//创建代理对象//参考CSDN博文:https://blog.csdn.net/java_key_code/article/details/140076947protected Object createProxy(Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {ProxyFactory proxyFactory = new ProxyFactory();// Copy our properties (proxyTargetClass etc) inherited from ProxyConfig.proxyFactory.copyFrom(this);if (!shouldProxyTargetClass(beanClass, beanName)) {// Must allow for introductions; can't just set interfaces to// the target's interfaces only.Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, this.proxyClassLoader);for (Class<?> targetInterface : targetInterfaces) {proxyFactory.addInterface(targetInterface);}}Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);for (Advisor advisor : advisors) {proxyFactory.addAdvisor(advisor);}proxyFactory.setTargetSource(targetSource);customizeProxyFactory(proxyFactory);proxyFactory.setFrozen(this.freezeProxy);if (advisorsPreFiltered()) {proxyFactory.setPreFiltered(true);}return proxyFactory.getProxy(this.proxyClassLoader);}// ...其它代码代码(略)
}
源码分析:节点3
package org.springframework.aop.framework.autoproxy;import java.util.List;import org.springframework.aop.Advisor;
import org.springframework.aop.TargetSource;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.core.OrderComparator;public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator {// ...其它代码代码(略)//源码分析:节点3@Overrideprotected Object[] getAdvicesAndAdvisorsForBean(Class beanClass, String beanName, TargetSource targetSource) {//源码分析:节点3 分支1List advisors = findEligibleAdvisors(beanClass, beanName);if (advisors.isEmpty()) {return DO_NOT_PROXY;}return advisors.toArray();}//源码分析:节点3 分支1protected List<Advisor> findEligibleAdvisors(Class beanClass, String beanName) {//获取所有的候选AdvisorList<Advisor> candidateAdvisors = findCandidateAdvisors();//和当前bean匹配,获取匹配成功的AdvisorList<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);//额外添加一个Advisor:ExposeInvocationInterceptor.ADVISOR//将MethodInvocation放到ThreadLocal,这个类很重要/**public class ExposeInvocationInterceptor implements MethodInterceptor, Ordered, Serializable {private static final ThreadLocal<MethodInvocation> invocation = new NamedThreadLocal<MethodInvocation>("Current AOP method invocation");public Object invoke(MethodInvocation mi) throws Throwable {MethodInvocation oldInvocation = invocation.get();invocation.set(mi);try {return mi.proceed();}finally {invocation.set(oldInvocation);}}}*/extendAdvisors(eligibleAdvisors);if (!eligibleAdvisors.isEmpty()) {eligibleAdvisors = sortAdvisors(eligibleAdvisors);}return eligibleAdvisors;}protected List<Advisor> findCandidateAdvisors() {return this.advisorRetrievalHelper.findAdvisorBeans();}protected List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class beanClass, String beanName) {ProxyCreationContext.setCurrentProxiedBeanName(beanName);try {return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);}finally {ProxyCreationContext.setCurrentProxiedBeanName(null);}}// ...其它代码代码(略)
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/867419.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

django之url路径

方式一&#xff1a;path 语法&#xff1a;<<转换器类型:自定义>> 作用&#xff1a;若转换器类型匹配到对应类型的数据&#xff0c;则将数据按照关键字传参的方式传递给视图函数 类型&#xff1a; str: 匹配除了”/“之外的非空字符串。 /test/zvxint: 匹配0或任何…

golang线程池ants-实现架构

1、总体架构 ants协程池&#xff0c;在使用上有多种方式(使用方式参考这篇文章&#xff1a;golang线程池ants-四种使用方法)&#xff0c;但是在实现的核心就一个&#xff0c;如下架构图&#xff1a; 总的来说&#xff0c;就是三个数据结构&#xff1a; Pool、WorkerStack、goW…

【前端实现】在父组件中调用公共子组件:注意事项逻辑示例 + 将后端数组数据格式转换为前端对象数组形式 + 增加和删除行

【前端】在父组件中调用公共子组件的实现方法 写在最前面一、调用公共子组件子组件CommonRow.vue父组件ParentComponent.vue 二、实现功能1. 将后端数组数据格式转换为前端对象数组形式2. 增加和删除row 三、小结 &#x1f308;你好呀&#xff01;我是 是Yu欸 &#x1f30c; 2…

全景图三维3D模型VR全景上传展示H5开发

全景图三维3D模型VR全景上传展示H5开发 3D互动体验平台的核心功能概览 兼容广泛格式&#xff1a;支持OBJ、FBX、GLTF等主流及前沿3D模型格式的无缝上传与展示&#xff0c;确保创意无界。 动态交互探索&#xff1a;用户可自由旋转、缩放、平移模型&#xff0c;深度挖掘每一处…

STMF4 硬件IIC(天空星开发板)

前言&#xff1a;笔记参考立创开发文档&#xff0c;连接放在最后 #IIC概念介绍 #IIC介绍 IIC通信协议&#xff0c;一种常见的串行通信协议&#xff0c;英文全程是 Inter-Integrated Circuit 使用这种通信方式的模块&#xff0c;通常有SCL&#xff08;Serial Clock Line&…

pytest使用报错(以及解决pytest所谓的“抑制print输出”)

1. 测试类的类名问题 #codingutf-8import pytestclass TestClass1:def setup(self) -> None:print(setup)def test_01(self) -> None:print(test_01111111111111111111111)def test_02(self) -> None:print(test_02)以上述代码为例&#xff0c;如果类名是Test开头&am…

Chair Footrest Protective Cover

Chair Footrest Protective Cover 万能通用型椅子脚垫保护套凳子耐磨硅胶加厚垫桌椅脚垫防滑静音套

Docker逃逸CVE-2019-5736、procfs云安全漏洞复现,全文5k字,超详细解析!

Docker容器挂载procfs 逃逸 procfs是展示系统进程状态的虚拟文件系统&#xff0c;包含敏感信息。直接将其挂载到不受控的容器内&#xff0c;特别是容器默认拥有root权限且未启用用户隔离时&#xff0c;将极大地增加安全风险。因此&#xff0c;需谨慎处理&#xff0c;确保容器环…

我使用HarmonyOs Next开发了b站的首页

1.实现效果展示&#xff1a; 2.图标准备 我使用的是iconfont图标&#xff0c;下面为项目中所使用到的图标 3. 代码 &#xff08;1&#xff09;Index.ets&#xff1a; import {InfoTop} from ../component/InfoTop import {InfoCenter} from ../component/InfoCenter import…

Mxnet转Onnx 踩坑记录

0. 前言 使用将MXNET模型转换为ONNX的过程中有很多算子不兼容&#xff0c;在此对那些不兼容的算子替换。在此之前需要安装mxnet分支v1.x版本作为mx2onnx的工具&#xff0c;git地址如下&#xff1a; mxnet/python/mxnet/onnx at v1.x apache/mxnet GitHub 同时还参考了如下…

【postgresql】 基础知识学习

PostgreSQL是一个高度可扩展的开源对象关系型数据库管理系统&#xff08;ORDBMS&#xff09;&#xff0c;它以其强大的功能、灵活性和可靠性而闻名。 官网地址&#xff1a;https://www.postgresql.org/ 中文社区&#xff1a;文档目录/Document Index: 世界上功能最强大的开源…

数据结构1:C++实现边长数组

数组作为线性表的一种&#xff0c;具有内存连续这一特点&#xff0c;可以通过下标访问元素&#xff0c;并且下标访问的时间复杂的是O(1)&#xff0c;在数组的末尾插入和删除元素的时间复杂度同样是O(1)&#xff0c;我们使用C实现一个简单的边长数组。 数据结构定义 class Arr…

web零碎知识2

不知道我的这个axios的包导进去没。 找一下关键词&#xff1a; http请求协议&#xff1a;就是进行交互式的格式 需要定义好 这个式一发一收短连接 而且没有记忆 这个分为三个部分 第一个式请求行&#xff0c;第二个就是请求头 第三个就是请求体 以get方式进行请求的失手请求…

Vatee万腾平台:智慧生活的无限可能

在科技日新月异的今天&#xff0c;我们的生活正被各种智能技术悄然改变。从智能家居到智慧城市&#xff0c;从个人健康管理到企业数字化转型&#xff0c;科技的力量正以前所未有的速度渗透到我们生活的每一个角落。而在这场智能革命的浪潮中&#xff0c;Vatee万腾平台以其卓越的…

Swagger php注解常用语法梳理

Swagger php注解常用语法梳理 快速编写你的 RESTFUL API 接口文档工具&#xff0c;通过注释定义接口和模型&#xff0c;可以和代码文件放置一起&#xff0c;也可以单独文件存放。 Swagger 优势 通过代码注解定义文档&#xff0c;更容易保持代码文档的一致性模型复用&#xff0…

C++(Qt)-GIS开发-QGraphicsView显示瓦片地图简单示例

C(Qt)-GIS开发-QGraphicsView显示瓦片地图简单示例 文章目录 C(Qt)-GIS开发-QGraphicsView显示瓦片地图简单示例1、概述2、实现效果3、主要代码4、源码地址 更多精彩内容&#x1f449;个人内容分类汇总 &#x1f448;&#x1f449;GIS开发 &#x1f448; 1、概述 支持多线程加…

【十三】图解 Spring 核心数据结构:BeanDefinition 其二

图解 Spring 核心数据结构&#xff1a;BeanDefinition 其二 概述 前面写过一篇相关文章作为开篇介绍了一下BeanDefinition&#xff0c;本篇将深入细节来向读者展示BeanDefinition的设计&#xff0c;让我们一起来揭开日常开发中使用的bean的神秘面纱&#xff0c;深入细节透彻理解…

第9章 项目总结01:项目流程,每个模块的介绍

1 请介绍一下你的项目 学成在线项目是一个B2B2C的在线教育平台&#xff0c;本项目包括了用户端、机构端、运营端。 核心模块包括&#xff1a;内容管理、媒资管理、课程搜索、订单支付、选课管理、认证授权等。 下图是项目的功能模块图&#xff1a; 项目采用前后端分离的技…

去除gif动图背景的工具网站

选择视频或GIF - 取消屏幕 (unscreen.com)https://www.unscreen.com/upload

24-7-6-读书笔记(八)-《蒙田随笔集》[法]蒙田 [译]潘丽珍

文章目录 《蒙田随笔集》阅读笔记记录总结 《蒙田随笔集》 《蒙田随笔集》蒙田&#xff08;1533-1592&#xff09;&#xff0c;是个大神人&#xff0c;这本书就是250页的样子&#xff0c;但是却看了好长好长时间&#xff0c;体会还是挺深的&#xff0c;但看的也是不大仔细&…