Spring系列之-Spring AOP设计原理(一)


声明:本文转载自https://my.oschina.net/wenbo123/blog/1594133,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。

Spring AOP作为Spring中两大最要特性跟IOC一样重要,看了很多书籍,都没有把这个东西的来龙去脉讲清楚,网上很多文章标题也都是一知半解,甚至很多直接就切入到动态代理这块来讲。本文旨在从源码级别来分析Spring AOP的设计过程,用一个例子来从头到尾分析Spring AOP实现过程。

我们先上一个简单的例子:

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)); 	}

 

 

本文发表于2017年12月24日 10:32
(c)注:本文转载自https://my.oschina.net/wenbo123/blog/1594133,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 651 讨论 0 喜欢 0

抢先体验

扫码体验
趣味小程序
文字表情生成器

闪念胶囊

一直到现在我才突然明白,我梦寐以求,是真爱和自由。

把爱情留给我身边最真心的姑娘,你陪我歌唱陪我流浪,陪我两败俱伤。

把青春献给身后那座辉煌的都市,为了这个美梦,我们付出着代价。

又是一年五一,祝我们工人阶级劳动节快乐! 今年被困在北京了,离境再入境需要隔离十五天。只能京津冀周边走一走了,想出去玩啊啊啊啊啊~

人活一辈子,不是一年两年。时间是有连续性的,做抉择的时候要多看几步。保持警惕,大丈夫有所为,有所不为。

快捷链接
网站地图
提交友链
Copyright © 2016 - 2020 Cion.
All Rights Reserved.
ICP备案:鲁ICP备19012333号-4.

鲁公网安备 37061302000383号.