Spring系列之-Spring AOP设计原理(一)
2017-12-25 14:10
393 查看
Spring AOP作为Spring中两大最要特性跟IOC一样重要,看了很多书籍,都没有把这个东西的来龙去脉讲清楚,网上很多文章标题也都是一知半解,甚至很多直接就切入到动态代理这块来讲。本文参考了网上相关分析以及《深入理解Spring技术设计原理》一书,从源码级别来分析Spring AOP的设计过程,用一个例子来从头到尾分析Spring AOP实现过程。
我们先上一个简单的例子:
XML配置:
测试类:
输出:
当前时间:1514042119262
nike shop
当前时间:1514042119283
可以看见在getShopName()方法执行前后都打印了当前时间,也就是执行了TimeHandler中的printTime()方法。
这是一个简单的AOP使用,下面将从这个例子触发解析Spring AOP设计实现。
可以发现打印时间是在getBean()方法之后执行的,说明AOP被Spring 容器处理过了,那么只有两个地方处理:
1.在Spring IOC容器初始化过程中处理。
2.在获取bean的过程中被处理。
前几篇文章分析过Spring IOC的初始化过程,在Spring IOC出事化过程中会调用XmlBeanDefinitionReader对XML文件中的Bean定义进行读取获取到Dom文档后进行解析,最终的解析BeanDefinition在DefaultBeanDefinitionDocumentReader的下述方法中。(本文源码均基于Spring 4.3.9)
在Spring IOC容器初始化过程中调用的是这句代码parseDefaultElement(ele, delegate),因为我们的bean都是通过<bean id="">声明的,这属于Spring默认命名,从上面配置Spring AOP XML中可以看出AOP的配置为<aop:>,这种配置不属于Spring默认命名,故不会执行parseDefaultElement(ele, delegate),而会执行delegate.parseCustomElement(ele),这句代码是解析自定义命名bean定义,<aop:>就属于自定义命名。
进一步进去:
其中这句代码NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); 获得了命名空间处理Handler,而String namespaceUri = getNamespaceURI(ele);这个获得的值就是http://www.springframework.org/schema/aop
NamespaceHandlerResolver用于根据命名空间解析得到命名空间处理Handler,NamespaceHandlerResolver通过resolve方法来根据http://www.springframework.org/schema/aop过去AOP命名空间处理Handler,NamespaceHandlerResolver有个默认实现DefaultNamespaceHandlerResolver,内部resolve实现如下:
其中Map<String, Object> handlerMappings = getHandlerMappings();获取到了url所对应的handler对应对象。getHandlerMappings()方法如下:
getHandlerMappings会在第一次调用时加载handler与url映射关系,并且会把class路径下的所有META-INF/spring.handlers下文件下的内容加载到Properties文件中然后转成map,其中Spring 每个Jar包下都有spring.handlers文件夹,在Spring-aop Jar包中该文件夹下内容是http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler
故Map<String, Object>维护了http://www.springframework.org/schema/aop与org.springframework.aop.config.AopNamespaceHandler之间的映射关系,即Aop的handler为AopNamespaceHandler。
故NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);这句代码得到了AopNamespaceHandler。
上面这行代码对aop定义进行解析,具体解析过程是先得到BeanDefinitionParser然后再调用BeanDefinitionParser中的BeanDefinition parse(Element element, ParserContext parserContext);方法
解析得到BeanDefinition。具体过程在NamespaceHandlerSupport中,其中AopNamespaceHandler继承了NamespaceHandlerSupport,而NamespaceHandlerSupport实现了NamespaceHandler接口。
其中String localName = parserContext.getDelegate().getLocalName(element),因为当前标签是<aop:config>,故得到的值为config,故获取到的BeanDefinitionParser为parser中key为config的对象,其中在AopNamespaceHandler初始化了下面几个BeanDefinitionParser,这个init方法是在 public NamespaceHandler resolve(String namespaceUri) {}即获取到AopNamespaceHandler后立即对其进行了初始化。
故<aop:config>得到的BeanDefinitionParser为ConfigBeanDefinitionParser,其中ConfigBeanDefinitionParser的parser方法如下:
其中configureAutoProxyCreator(parserContext, element)向Spring容器中注册了一个beanName为org.springframework.aop.config.internalAutoProxyCreator的bean,这个bean的默认实现为AspectJAwareAdvisorAutoProxyCreator。这个类是Spring AOP中非常重要的类,本文主要介绍AOP的初始化XML解析过程,这个类留在后续做处理。
从名字很容易看出上面代码分别处理了<aop:config>下的<aop:pointcut> <aop:advisor>以及<aop:aspect>,从我们的例子使用中我们分别介绍:
<aop:aspect>标签解析:
AbstractBeanDefinition advisorDefinition = parseAdvice( aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences);
这句代码对通知节点进行了解析,其实现如下。
其中createAdviceDefinition创建了通知定义是一种Spring Bean定义RootBeanDefinition,其中针对每个通知有对应的bean与之对应。
从上面方法可以看出5种通知对应的bean定义分别为
before对应AspectJMethodBeforeAdvice
After对应AspectJAfterAdvice
after-returning对应AspectJAfterReturningAdvice
after-throwing对应AspectJAfterThrowingAdvice
around对应AspectJAroundAdvice
故我们例子中<aop:before>、<aop:after>两个标签的Spring Bean定义都创建完成,具体创建Bean定义跟Spring IOC一样,只不过这里直接指定了Bean实现。
获取通知的BeanDefinition后会会实例化一个
RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);并将通知Bean封装起来,这个bean是AspectJPointcutAdvisor。
回到上面节点循环中,其中解析了通知节点后会解析横切点,代码如下:
pointcutDefinition = createPointcutDefinition(expression);方法如下:
即创建了一个AspectJExpressionPointcut Bean定义。
创建完成后无非就是将bean注册到BeanFactory中。
这样整个Spring AOP初始化就基本完成,AOP初始化过程中就是解析各种标签创建Spring IOC中bean定义。
回顾下AOP初始化主要创建了一下Bean
我们先上一个简单的例子:
public interface ShopService { public String getShopName(); } public class ShopServiceImpl implements ShopService{ public String getShopName() { System.out.println("nike shop"); return "Nike"; } } public class TimeHandler { public void printTime() { System.out.println("当前时间:" + System.currentTimeMillis()); } }
XML配置:
<bean id="shopService" class="com.dianping.aop.ShopServiceImpl"/> <bean id="timeHandler" class="com.dianping.aop.TimeHandler"/> <aop:config proxy-target-class="true"> <aop:aspect id="time" ref="timeHandler"> <aop:pointcut id="point" expression="execution(* com.dianping.aop.ShopService.*(..))"/> <aop:before method="printTime" pointcut-ref="point"/> <aop:after method="printTime" pointcut-ref="point"/> </aop:aspect> </aop:config>
测试类:
public class Main { public static void main(String[] args) { BeanFactory beanFactory = new FileSystemXmlApplicationContext("classpath:appcontext.xml"); ShopService shopService = (ShopService) beanFactory.getBean("shopService"); shopService.getShopName(); } }
输出:
当前时间:1514042119262
nike shop
当前时间:1514042119283
可以看见在getShopName()方法执行前后都打印了当前时间,也就是执行了TimeHandler中的printTime()方法。
这是一个简单的AOP使用,下面将从这个例子触发解析Spring AOP设计实现。
可以发现打印时间是在getBean()方法之后执行的,说明AOP被Spring 容器处理过了,那么只有两个地方处理:
1.在Spring IOC容器初始化过程中处理。
2.在获取bean的过程中被处理。
前几篇文章分析过Spring IOC的初始化过程,在Spring IOC出事化过程中会调用XmlBeanDefinitionReader对XML文件中的Bean定义进行读取获取到Dom文档后进行解析,最终的解析BeanDefinition在DefaultBeanDefinitionDocumentReader的下述方法中。(本文源码均基于Spring 4.3.9)
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); } }
在Spring IOC容器初始化过程中调用的是这句代码parseDefaultElement(ele, delegate),因为我们的bean都是通过<bean id="">声明的,这属于Spring默认命名,从上面配置Spring AOP XML中可以看出AOP的配置为<aop:>,这种配置不属于Spring默认命名,故不会执行parseDefaultElement(ele, delegate),而会执行delegate.parseCustomElement(ele),这句代码是解析自定义命名bean定义,<aop:>就属于自定义命名。
进一步进去:
public BeanDefinition parseCustomElement(Element ele) { return parseCustomElement(ele, null); } public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) { //获取命名空间并根据命名空间获取相应的处理 String namespaceUri = getNamespaceURI(ele); NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); if (handler == null) { error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele); return null; } return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); }
其中这句代码NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); 获得了命名空间处理Handler,而String namespaceUri = getNamespaceURI(ele);这个获得的值就是http://www.springframework.org/schema/aop
NamespaceHandlerResolver用于根据命名空间解析得到命名空间处理Handler,NamespaceHandlerResolver通过resolve方法来根据http://www.springframework.org/schema/aop过去AOP命名空间处理Handler,NamespaceHandlerResolver有个默认实现DefaultNamespaceHandlerResolver,内部resolve实现如下:
@Override public NamespaceHandler resolve(String namespaceUri) { //加载handler map映射 Map<String, Object> handlerMappings = getHandlerMappings(); Object handlerOrClassName = handlerMappings.get(namespaceUri); if (handlerOrClassName == null) { return null; } else if (handlerOrClassName instanceof NamespaceHandler) { return (NamespaceHandler) handlerOrClassName; } else { String className = (String) handlerOrClassName; try { Class<?> handlerClass = ClassUtils.forName(className, this.classLoader); if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) { throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri + "] does not implement the [" + NamespaceHandler.class.getName() + "] interface"); } NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass); namespaceHandler.init(); handlerMappings.put(namespaceUri, namespaceHandler); return namespaceHandler; } catch (ClassNotFoundException ex) { throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "] not found", ex); } catch (LinkageError err) { throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "]: problem with handler class file or dependent class", err); } } }
其中Map<String, Object> handlerMappings = getHandlerMappings();获取到了url所对应的handler对应对象。getHandlerMappings()方法如下:
private Map<String, Object> getHandlerMappings() { if (this.handlerMappings == null) { synchronized (this) { if (this.handlerMappings == null) { try { Properties mappings = PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader); if (logger.isDebugEnabled()) { logger.debug("Loaded NamespaceHandler mappings: " + mappings); } Map<String, Object> handlerMappings = new ConcurrentHashMap<String, Object>(mappings.size()); CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings); this.handlerMappings = handlerMappings; } catch (IOException ex) { throw new IllegalStateException( "Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex); } } } } return this.handlerMappings; }
getHandlerMappings会在第一次调用时加载handler与url映射关系,并且会把class路径下的所有META-INF/spring.handlers下文件下的内容加载到Properties文件中然后转成map,其中Spring 每个Jar包下都有spring.handlers文件夹,在Spring-aop Jar包中该文件夹下内容是http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler
故Map<String, Object>维护了http://www.springframework.org/schema/aop与org.springframework.aop.config.AopNamespaceHandler之间的映射关系,即Aop的handler为AopNamespaceHandler。
故NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);这句代码得到了AopNamespaceHandler。
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
上面这行代码对aop定义进行解析,具体解析过程是先得到BeanDefinitionParser然后再调用BeanDefinitionParser中的BeanDefinition parse(Element element, ParserContext parserContext);方法
解析得到BeanDefinition。具体过程在NamespaceHandlerSupport中,其中AopNamespaceHandler继承了NamespaceHandlerSupport,而NamespaceHandlerSupport实现了NamespaceHandler接口。
@Override public BeanDefinition parse(Element element, ParserContext parserContext) { return findParserForElement(element, parserContext).parse(element, parserContext); } /** * Locates the {@link BeanDefinitionParser} from the register implementations using * the local name of the supplied {@link Element}. */ private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) { String localName = parserContext.getDelegate().getLocalName(element); BeanDefinitionParser parser = this.parsers.get(localName); if (parser == null) { parserContext.getReaderContext().fatal( "Cannot locate BeanDefinitionParser for element [" + localName + "]", element); } return parser; }
其中String localName = parserContext.getDelegate().getLocalName(element),因为当前标签是<aop:config>,故得到的值为config,故获取到的BeanDefinitionParser为parser中key为config的对象,其中在AopNamespaceHandler初始化了下面几个BeanDefinitionParser,这个init方法是在 public NamespaceHandler resolve(String namespaceUri) {}即获取到AopNamespaceHandler后立即对其进行了初始化。
@Override public void init() { // In 2.0 XSD as well as in 2.1 XSD. registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser()); registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser()); registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator()); // Only in 2.0 XSD: moved to context namespace as of 2.1 registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser()); }
故<aop:config>得到的BeanDefinitionParser为ConfigBeanDefinitionParser,其中ConfigBeanDefinitionParser的parser方法如下:
@Override public BeanDefinition parse(Element element, ParserContext parserContext) { CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element)); parserContext.pushContainingComponent(compositeDef); 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; }
其中configureAutoProxyCreator(parserContext, element)向Spring容器中注册了一个beanName为org.springframework.aop.config.internalAutoProxyCreator的bean,这个bean的默认实现为AspectJAwareAdvisorAutoProxyCreator。这个类是Spring AOP中非常重要的类,本文主要介绍AOP的初始化XML解析过程,这个类留在后续做处理。
if (POINTCUT.equals(localName)) { parsePointcut(elt, parserContext); } else if (ADVISOR.equals(localName)) { parseAdvisor(elt, parserContext); } else if (ASPECT.equals(localName)) { parseAspect(elt, parserContext); }
从名字很容易看出上面代码分别处理了<aop:config>下的<aop:pointcut> <aop:advisor>以及<aop:aspect>,从我们的例子使用中我们分别介绍:
<aop:aspect>标签解析:
private void parseAspect(Element aspectElement, ParserContext parserContext) { //得到 <aop:aspect id="time" ref="timeHandler">中的time String aspectId = aspectElement.getAttribute(ID); //得到timeHandler String aspectName = aspectElement.getAttribute(REF); try { //初始化一个切面实体 this.parseState.push(new AspectEntry(aspectId, aspectName)); List<BeanDefinition> beanDefinitions = new ArrayList<BeanDefinition>(); List<BeanReference> beanReferences = new ArrayList<BeanReference>(); //获取<aop:aspect>节点为declare-parents的元素,本次不会涉及到,这个有时间再研究 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. //获取<aop:aspect>下所有的节点 NodeList nodeList = aspectElement.getChildNodes(); boolean adviceFoundAlready = false; //循环遍历所有节点 for (int i = 0; i < nodeList.getLength(); i++) { Node node = nodeList.item(i); if (isAdviceNode(node, parserContext)) { //如果节点为为通知类型即<aop:before>、<aop:after>、<aop:after-returning>、<aop:after-throwing method="">、<aop:around method=""> 5个节点 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)); } //解析定义 AbstractBeanDefinition 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) { parsePointcut(pointcutElement, parserContext); } parserContext.popAndRegisterContainingComponent(); } finally { this.parseState.pop(); } }
AbstractBeanDefinition advisorDefinition = parseAdvice( aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences);
这句代码对通知节点进行了解析,其实现如下。
private 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))); // create the method factory bean RootBeanDefinition methodDefinition = new RootBeanDefinition(MethodLocatingFactoryBean.class); methodDefinition.getPropertyValues().add("targetBeanName", aspectName); methodDefinition.getPropertyValues().add("methodName", adviceElement.getAttribute("method")); methodDefinition.setSynthetic(true); // create instance factory definition RootBeanDefinition aspectFactoryDef = new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class); aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName); aspectFactoryDef.setSynthetic(true); // 注册切点 AbstractBeanDefinition adviceDef = createAdviceDefinition( adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef, beanDefinitions, beanReferences); // 配置通知 RootBeanDefinition 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)); } // 注册到beanFactory中 parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition); return advisorDefinition; } finally { this.parseState.pop(); } }
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)); } ConstructorArgumentValues cav = adviceDefinition.getConstructorArgumentValues(); cav.addIndexedArgumentValue(METHOD_INDEX, methodDef); 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; }
其中createAdviceDefinition创建了通知定义是一种Spring Bean定义RootBeanDefinition,其中针对每个通知有对应的bean与之对应。
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 + "]."); } }
从上面方法可以看出5种通知对应的bean定义分别为
before对应AspectJMethodBeforeAdvice
After对应AspectJAfterAdvice
after-returning对应AspectJAfterReturningAdvice
after-throwing对应AspectJAfterThrowingAdvice
around对应AspectJAroundAdvice
故我们例子中<aop:before>、<aop:after>两个标签的Spring Bean定义都创建完成,具体创建Bean定义跟Spring IOC一样,只不过这里直接指定了Bean实现。
获取通知的BeanDefinition后会会实例化一个
RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);并将通知Bean封装起来,这个bean是AspectJPointcutAdvisor。
回到上面节点循环中,其中解析了通知节点后会解析横切点,代码如下:
//获取横切点的元素节点 List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT); for (Element pointcutElement : pointcuts) { parsePointcut(pointcutElement, parserContext); }
private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) { //获取<aop:pointcut id="point" expression="execution(* com.dianping.aop.ShopService.*(..))"/>中id和expression的值 String id = pointcutElement.getAttribute(ID); String expression = pointcutElement.getAttribute(EXPRESSION); AbstractBeanDefinition pointcutDefinition = null; try { this.parseState.push(new PointcutEntry(id)); //创建切点bean定义 pointcutDefinition = createPointcutDefinition(expression); pointcutDefinition.setSource(parserContext.extractSource(pointcutElement)); 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; }
pointcutDefinition = createPointcutDefinition(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 Bean定义。
创建完成后无非就是将bean注册到BeanFactory中。
这样整个Spring AOP初始化就基本完成,AOP初始化过程中就是解析各种标签创建Spring IOC中bean定义。
回顾下AOP初始化主要创建了一下Bean
相关文章推荐
- Spring系列之-Spring AOP设计原理(二)
- Spring技术内幕——深入解析Spring架构与设计原理(二)AOP
- Spring技术内幕——深入解析Spring架构与设计原理(二)AOP
- Spring系列之 (八):AOP实现原理
- 深入解析Spring架构与设计原理-AOP
- 深入解析Spring架构与设计原理(二)AOP原理
- 死磕Spring AOP系列5:设计模式在AOP中的使用
- Spring技术内幕——深入解析Spring架构与设计原理(二)AOP
- Spring 系列:AOP原理
- spring系列(三)——springAOP原理探究(CGLIB代理机制)
- Spring技术内幕——深入解析Spring架构与设计原理(二)AOP
- AOP的概念和实现原理—Spring系列介绍
- Spring Aop配置与原理(二)
- Spring AOP 实现原理
- 《Spring技术内幕——深入解析Spring架构与设计原理》连载2
- Spring3.1.0实现原理分析(十).AOP之代理对象执行拦截过程
- 理解Spring AOP 原理(一)Spring AOP的Demo应用和相关概念
- spring源码剖析(六)AOP实现原理剖析
- Spring AOP 实现原理
- Spring的AOP实现原理