1、简单使用

首先定义要拦截的bean,简单的写一个:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* 用于拦截的Bean
*/
public class CustomBean {
private String str = "A";

public String getStr() {
return str;
}

public void setStr(String str) {
this.str = str;
}

@Override
public String toString() {
return str;
}
}

之后定义切面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/**
* 切面
*/
@Aspect
public class CustomAspect {
/**
* 配置切入点
*/
private final String POINT_CUT = "execution(* com.minivision.test.spring.AOP.test.CustomBean.*(..))";
/**
* 配置环绕通知
*
* @param point JoinPoint的支持接口
* @return Object
*/
@Around(POINT_CUT)
public Object around(ProceedingJoinPoint point) {
System.out.println("around before");
Object object = null;
try {
object = point.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("around after");
return object;
}
/**
* 配置前置通知
* 同时接受JoinPoint切入点对象,可以没有该参数
*/
@Before(POINT_CUT)
public void before() {
System.out.println("before");
}
/**
* 配置后置通知
*/
@After(POINT_CUT)
public void after() {
System.out.println("after");
}
}

其实使用注解会更简单,但是没有使用xml文档直观,因为是学习,所以使用xml配置文件:
spring-aop.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?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.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">

<!-- 激活自动代理功能 -->
<aop:aspectj-autoproxy/>

<!-- 业务逻辑切面配置 -->
<bean id="customBean" class="com.demo.CustomBean"/>
<bean class="com.demo.CustomAspect"/>

</beans>

最后写个main方法测试:

1
2
3
4
5
public static void main(String[] arge) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-aop.xml");
CustomBean bean = context.getBean("customBean", CustomBean.class);
System.out.println(bean.toString());
}

运行结果:

1
2
3
4
5
around before
before
around after
after
A

下面开始源码分析,首先需要从xml解析开始

2、标签aop:aspectj-autoproxy/的解析

由配置文件spring-aop.xml可知:标签aop:aspectj-autoproxy/的命名空间为:http://www.springframework.org/schema/aop,
所以从new ClassPathXmlApplicationContext(“spring-aop.xml”);层层深入源码,到达org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader类中的parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)方法,
会走delegate.parseCustomElement(ele);这个自定义解析逻辑。

下面看org.springframework.beans.factory.xml.BeanDefinitionParserDelegate类中的 parseCustomElement(Element ele)方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Nullable
public BeanDefinition parseCustomElement(Element ele) {
return parseCustomElement(ele, null);
}

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

首先要获取NamespaceHandler,会在META-INF/spring.handlers中获取相应的类的全量名:
spring-aop-5.1.8.RELEASE.jar中为:

1
http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler

即获取的NamespaceHandler为:AopNamespaceHandler:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class AopNamespaceHandler extends NamespaceHandlerSupport {

/**
* Register the {@link BeanDefinitionParser BeanDefinitionParsers} for the
* '{@code config}', '{@code spring-configured}', '{@code aspectj-autoproxy}'
* and '{@code scoped-proxy}' tags.
*/
@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:aspectj-autoproxy/的类为:AspectJAutoProxyBeanDefinitionParser,
之后调用parse方法:

1
2
3
4
5
6
7
8
9
10
/**
* Parses the supplied {@link Element} by delegating to the {@link BeanDefinitionParser} that is
* registered for that {@link Element}.
*/
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
BeanDefinitionParser parser = findParserForElement(element, parserContext);
return (parser != null ? parser.parse(element, parserContext) : null);
}

即根据标签获取BeanDefinitionParser,这里为AspectJAutoProxyBeanDefinitionParser。
最后调用AspectJAutoProxyBeanDefinitionParser中的parse方法:

1
2
3
4
5
6
7
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
extendBeanDefinition(element, parserContext);
return null;
}

下面来分析这个AspectJAutoProxyBeanDefinitionParser的解析方法。

tencent.jpg