前期准备
分析AOP源码,首先看下AOP的一个应用例子:
UserService和UserServiceImpl实现类
public interface UserService {
void saveUser();
void updateUser();
}
@Service
public class UserServiceImpl implements UserService {
@Override
public void saveUser() {
System.out.println("添加用户");
}
@Override
public void updateUser() {
System.out.println("修改用户");
}
}
}
aop.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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 配置目标对象 -->
<bean class="sourcecode.aop.target.UserServiceImpl"></bean>
<!-- 配置通知类 -->
<bean id="myAdvice" class="sourcecode.aop.advice.MyAdvice"></bean>
<!-- AOP配置 -->
<aop:config>
<!-- 配置AOP切面,切面是由通知和切入点组成的 -->
<aop:aspect ref="myAdvice">
<aop:before method="before"
pointcut="execution(* *..*.*ServiceImpl.*(..))" />
</aop:aspect>
</aop:config>
</beans>
单元测试类:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:spring/spring-aop.xml")
public class TestAOP {
@Autowired
private UserService userService;
@Test
public void test() {
userService.saveUser();
}
}
可以通过上述例子,设置断点调试,一步步看下aop的原理。接下来开始具体分析源码。
一、AOP源码入口
前面有篇文章已经分析过spring的ioc的源码,再次找到DefaultBeanDefinitionDocumentReader类的parseBeanDefinitions方法
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
// 加载的Document对象是否使用了Spring默认的XML命名空间(beans命名空间)
if (delegate.isDefaultNamespace(root)) {
// 获取Document对象根元素的所有子节点(bean标签、import标签、alias标签和其他自定义标签context、aop等)
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;
// bean标签、import标签、alias标签,则使用默认解析规则
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}
else {//像context标签、aop标签、tx标签,则使用用户自定义的解析规则解析元素节点
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
通过代码中注释可知,aop.xml文件中的<aop:config>标签,是通过调用delegate.parseCustomElement(ele)方法解析的,它的源码如下:
@Nullable
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
String namespaceUri = getNamespaceURI(ele);
if (namespaceUri == null) {
return null;
}
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));
}
之前aop.xml文件已经被解析成org.w3c.dom.Document,并且org.w3c.dom.Document以树的形式展示,一个节点就是一个Node(Element是Node的子接口)。
对于解析aop.xml文件中的<aop:config>标签,上述代码第3行,返回的字符串为"http://www.springframework.org/schema/aop"的String对象。
分析第7行,this.readerContext.getNamespaceHandlerResolver()其实返回的是DefaultNamespaceHandlerResolver类,然后调用该类的resolve方法,该行最终返回的是AopNamespaceHandler类。resolve方法参数为第3行获取到的String对象,方法源码如下:
@Override
@Nullable
public NamespaceHandler resolve(String namespaceUri) {
// 读取spring所有工程的META-INF/spring.handlers文件,获取namespaceUri和NamespaceHandler的映射关系
Map<String, Object> handlerMappings = getHandlerMappings();
// 获取 指定namespaceUri对应的namespaceHandler
Object handlerOrClassName = handlerMappings.get(namespaceUri);
if (handlerOrClassName == null) {
return null;
}
else if (handlerOrClassName instanceof NamespaceHandler) {
return (NamespaceHandler) handlerOrClassName;
}
else {
// META-INF/spring.handlers文件中存储的value都是String类型的类名
String className = (String) handlerOrClassName;
try {
// 根据类名通过反射获取到NamespaceHandler的Class类对象
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 = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
// 调用NamespaceHandler类的init方法,初始化一些专门处理指定标签的BeanDefinitionParsers类
namespaceHandler.init();
// 将namespaceUri对应的String类型的类名,替换为NamespaceHandler对象,下一次再获取的话,就不会重复创建实例
handlerMappings.put(namespaceUri, namespaceHandler);
return namespaceHandler;
}
catch (ClassNotFoundException ex) {
throw new FatalBeanException("Could not find NamespaceHandler class [" + className +
"] for namespace [" + namespaceUri + "]", ex);
}
catch (LinkageError err) {
throw new FatalBeanException("Unresolvable class definition for NamespaceHandler class [" +
className + "] for namespace [" + namespaceUri + "]", err);
}
}
}
分析上述代码:第7行返回的是AopNamespaceHandler类。27行代码调用AopNamespaceHandler类的init方法,初始化一些专门处理指定标签的BeanDefinitionParsers类,init方法源码:
@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());
}
分析上述代码:总共4个用于具体标签转换的Parser,分别为:
config–>ConfigBeanDefinitionParser
aspectj-autoproxy–>AspectJAutoProxyBeanDefinitionParser
scoped-proxy–>ScopedProxyBeanDefinitionDecorator
spring-configured–>SpringConfiguredBeanDefinitionParser
通过查看init方法中的其中一个方法registerBeanDefinitionParser可知,这些标签解析类是存储在AopNamespaceHandler的父类NamespaceHandlerSupport的map集合中,供后面使用,如下:
public abstract class NamespaceHandlerSupport implements NamespaceHandler {
/**
* Stores the {@link BeanDefinitionParser} implementations keyed by the
* local name of the {@link Element Elements} they handle.
*/
private final Map<String, BeanDefinitionParser> parsers = new HashMap<>();
回头再接着看BeanDefinitionParserDelegate类的parseCustomElement方法,第12行最终调用的是AopNamespaceHandler类的parse方法。因为通过查看AopNamespaceHandler类,类中无parse方法定义,所以,调用的其实是父类NamespaceHandlerSupport的parse方法。该方法源码如下:
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
BeanDefinitionParser parser = findParserForElement(element, parserContext);
return (parser != null ? parser.parse(element, parserContext) : null);
}
分析上述代码:第4行根据aop标签,获取对应的解析类。对于标签aop:config,第4行获取到它的解析类ConfigBeanDefinitionParser,第5行接着调用该类的parse方法。
二、AOP Bean定义加载(根据织入方式将<aop:before>转换成名为adviceDef的RootBeanDefinition)
接着分析,查看ConfigBeanDefinitionParser类的parse方法,如下:
/**
* element : 就是<aop:config>标签元素对象
*/
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
CompositeComponentDefinition compositeDef =
new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
parserContext.pushContainingComponent(compositeDef);
// 向IoC容器中注册AspectJAwareAdvisorAutoProxyCreator类的BeanDefinition:(用于创建AOP代理对象的)
// BeanPostProcessor可以对实例化之后的bean进行一些操作
// AspectJAwareAdvisorAutoProxyCreator 实现了BeanPostProcessor接口,可以对目标对象实例化之后,创建对应的代理对象
configureAutoProxyCreator(parserContext, element);
// 获取<aop:config>标签的子标签<aop:aspect>、<aop:advisor> 、<aop:pointcut>
List<Element> childElts = DomUtils.getChildElements(element);
for (Element elt: childElts) {
// 获取子标签的节点名称或者叫元素名称
String localName = parserContext.getDelegate().getLocalName(elt);
if (POINTCUT.equals(localName)) {// 解析<aop:pointcut>标签
parsePointcut(elt, parserContext);
}
else if (ADVISOR.equals(localName)) {// 解析<aop:advisor>标签
parseAdvisor(elt, parserContext);
}
else if (ASPECT.equals(localName)) {// 解析<aop:aspect>标签
parseAspect(elt, parserContext);
}
}
parserContext.popAndRegisterContainingComponent();
return null;
}
分析上述代码,查看第28行,该方法是处理<aop:config>下的节点为<aop:aspect>,查看源码:
private void parseAspect(Element aspectElement, ParserContext parserContext) {
// 获取<aop:aspect>标签的id属性值
String aspectId = aspectElement.getAttribute(ID);
// 获取<aop:aspect>标签的ref属性值
String aspectName = aspectElement.getAttribute(REF);
try {
this.parseState.push(new AspectEntry(aspectId, aspectName));
List<BeanDefinition> beanDefinitions = new ArrayList<>();
List<BeanReference> beanReferences = new ArrayList<>();
// 处理<aop: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);
// 判断是否是<aop:before>、<aop:after>、<aop:after-returning>、<aop:after-throwing method="">、<aop:around method="">这五个标签
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));
}
//方法主要做了三件事:
// 1、根据织入方式(before、after这些)创建RootBeanDefinition,名为adviceDef即advice定义
// 2、将上一步创建的RootBeanDefinition写入一个新的RootBeanDefinition,构造一个新的对象,名为advisorDefinition,即advisor定义
// 3、将advisorDefinition注册到DefaultListableBeanFactory中
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);
// 得到所有<aop:aspect>下的<aop:pointcut>子标签
List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);
for (Element pointcutElement : pointcuts) {
// 解析<aop:pointcut>子标签
parsePointcut(pointcutElement, parserContext);
}
parserContext.popAndRegisterContainingComponent();
}
finally {
this.parseState.pop();
}
}
接着进入第43行的parseAdvice方法
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
// 创建方法工厂Bean的BeanDefinition对象:用于获取Method对象
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
// 创建实例工厂BeanDefinition:用于创建增强类的实例
RootBeanDefinition aspectFactoryDef =
new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class);
aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName);
aspectFactoryDef.setSynthetic(true);
//以上的两个BeanDefinition的作用主要是应用在以下这行代码
// method.invoke(obj,args)
// register the pointcut
// 通知增强类的BeanDefinition对象(核心)
AbstractBeanDefinition adviceDef = createAdviceDefinition(
adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef,
beanDefinitions, beanReferences);
// configure the advisor
// 通知器类的BeanDefinition对象
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));
}
// register the final advisor
// 将advisorDefinition注册到IoC容器中
parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition);
return advisorDefinition;
}
finally {
this.parseState.pop();
}
}
接着进入第27行的createAdviceDefinition方法:
private AbstractBeanDefinition createAdviceDefinition(
Element adviceElement, ParserContext parserContext, String aspectName, int order,
RootBeanDefinition methodDef, RootBeanDefinition aspectFactoryDef,
List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {
// 根据通知类型的不同,分别创建对应的BeanDefinition对象(可以去看看getAdviceClass方法)
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();
// 设置第一个构造参数:方法工厂对象的BeanDefinition
cav.addIndexedArgumentValue(METHOD_INDEX, methodDef);
// 解析<aop:before>、<aop:after>、<aop:after-returning>标签中的pointcut或者pointcut-ref属性
Object pointcut = parsePointcutProperty(adviceElement, parserContext);
// 设置第二个构造参数:切入点BeanDefinition
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);
}
// 设置第三个构造参数:实例工厂BeanDefinition
cav.addIndexedArgumentValue(ASPECT_INSTANCE_FACTORY_INDEX, aspectFactoryDef);
return adviceDefinition;
}
分析上述代码:第7行,根据切入方式的不同,分别创建对应的BeanDefinition对象。
before对应AspectJMethodBeforeAdvice
After对应AspectJAfterAdvice
after-returning对应AspectJAfterReturningAdvice
after-throwing对应AspectJAfterThrowingAdvice
around对应AspectJAroundAdvice
到这里为止,aop:before标签对应的AbstractBeanDefinition创建成功。
三、AOP Bean定义加载(包装名为adviceDef的RootBeanDefinition 成 名字为advisorDefinition的RootBeanDefinition)
回来看ConfigBeanDefinitionParser类parseAdvice方法:
// 通知器类的BeanDefinition对象
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));
}
分析上述代码:第4行创建新的名字为advisorDefinition的RootBeanDefinition类。第5行是用于判断aop:aspect标签中是否存在"order"属性的(用来控制切入方法优先级的)。
四、AOP Bean定义加载(AopNamespaceHandler处理<aop:pointcut>标签)
接着看ConfigBeanDefinitionParser类parseAdvice方法中的处理<aop:pointcut>标签的代码:
// 得到所有<aop:aspect>下的<aop:pointcut>子标签
List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);
for (Element pointcutElement : pointcuts) {
// 解析<aop:pointcut>子标签
parsePointcut(pointcutElement, parserContext);
}
进入第5行的parsePointcut方法:
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));
// 此处创建一个AspectJExpressionPointcut类对应的BeanDefinition对象,处理pointcut
pointcutDefinition = createPointcutDefinition(expression);
pointcutDefinition.setSource(parserContext.extractSource(pointcutElement));
String pointcutBeanName = id;
// 如果配置id属性,则走下面代码
if (StringUtils.hasText(pointcutBeanName)) {
parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition);
}
// 如果没有配置id属性,则走下面代码
else {
pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition);
}
parserContext.registerComponent(
new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression));
}
finally {
this.parseState.pop();
}
return pointcutDefinition;
}
进入第10行代码的createPointcutDefinition方法:
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;
}
分析上述代码:<aop:pointcut>标签对应解析出来的BeanDefinition是RootBeanDefinition,且RootBenaDefinitoin中的Class是org.springframework.aop.aspectj.AspectJExpressionPointcut,且RootBeanDefinition对应的Bean被定义成原型。
本文深入剖析Spring AOP的工作原理,从AOP配置文件解析入手,详细解读如何将AOP配置转换为Bean定义并注册到IoC容器的过程。涵盖了AOP切面、通知、连接点的定义与注册机制。
】AOP源码分析---解析xml中的aop:config标签内容并存储在BeanDefinition&spm=1001.2101.3001.5002&articleId=83375360&d=1&t=3&u=857ae46da7fb4a21bab47b36ce31338a)
1155

被折叠的 条评论
为什么被折叠?



