这是<死磕Spring AOP系列>的第三篇。经过前面的讲解,已经掌握了以下知识点
Spring AOP的底层支持,是基于ProxyFactory+ProxyConfig+Advisor生成的
Spring容器的代理对象生成:在Bean生命周期过长中调用BeanPostProcessor,将对象进行包装,生成代理对象。
Advisor的指定:不管编程式指定,还是自动匹配指定。虽然形式不同,但本质是相同的。
如果,还对上面的问题存疑,请回看以上内容。
本篇主要对剖析另外一个BeanPostProcessor,他就是DefaultAdvisorAutoProxyCreator,他是BeanNameAutoProxyCreator的升级版。形象点说:如果ProxyFactory是弓箭的话,代表原始,BeanNameAutoProxyCreator就是步枪,需要自己装配,DefaultAdvisorAutoProxyCreator就是自动步枪了,Spring可以完成自动匹配的部分工作了。
本章主要内容
使用DefaultAdvisorAutoProxyCreator,完成一个“AOP"例子,讲解下如何配置
对比BeanNameAutoProxyCreator,对DefaultAdvisorAutoProxyCreator进行剖析
分析DefaultAdvisorAutoProxyCreator的Advisor的匹配过程
体会自动化
1.使用DefaultAdvisorAutoProxyCreator,完成一个“AOP"例子
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
|
/**
*模拟业务接口
*/
public
interface
UserService {
public
void
updateUser();
}
/**
*模拟具体业务
*/
public
class
UserServiceImpl
implements
UserService{
@Override
public
void
updateUser() {
System.out.println(
"$$$$$$执行业务逻辑$$$$$"
);
}
}
/**
* 模拟切面1
*/
public
class
SecurityInterceptor
implements
MethodInterceptor {
@Override
public
Object invoke(MethodInvocation methodInvocation)
throws
Throwable {
System.out.println(
"==========执行安全校验===================="
);
return
methodInvocation.proceed();
}
}
/**
* 模拟切面2
*/
public
class
LoggerBeforeAdvice
implements
MethodBeforeAdvice {
@Override
public
void
before(Method method, Object[] args, Object target)
throws
Throwable {
System.out.println(
"=======保存更新日志========="
);
}
}
|
xml(proxy_test.xml)
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
|
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<
beans
>
<
bean
class
=
"org.springaop.chap01.UserServiceImpl"
id
=
"userService"
></
bean
>
<
bean
class
=
"org.springaop.chap01.LoggerBeforeAdvice"
id
=
"loggerBeforeAdvice"
></
bean
>
<
bean
class
=
"org.springaop.chap01.SecurityInterceptor"
id
=
"securityInterceptor"
></
bean
>
<!-- 自动代理所有的advisor -->
<
bean
class
=
"org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
>
<
property
name
=
"usePrefix"
value
=
"true"
></
property
>
<
property
name
=
"advisorBeanNamePrefix"
value
=
"advisor"
></
property
>
</
bean
>
<
bean
id
=
"advisor1"
class
=
"org.springframework.aop.support.RegexpMethodPointcutAdvisor"
>
<
property
name
=
"pattern"
>
<
value
>.*update.*</
value
>
<!-- 业务实现方法名匹配 -->
</
property
>
<
property
name
=
"advice"
>
<
ref
bean
=
"loggerBeforeAdvice"
/>
</
property
>
</
bean
>
<
bean
id
=
"advisor2"
class
=
"org.springframework.aop.support.RegexpMethodPointcutAdvisor"
>
<
property
name
=
"pattern"
>
<
value
>.*update.*</
value
>
<!-- 业务实现方法名匹配 -->
</
property
>
<
property
name
=
"advice"
>
<
ref
bean
=
"securityInterceptor"
/>
</
property
>
</
bean
>
</
beans
>
|
Main
1
2
3
4
5
6
7
8
9
|
public
class
ContextMain {
public
static
void
main(String[] args) {
ApplicationContext ctx =
new
ClassPathXmlApplicationContext(
"org/springaop/chap03/proxy_test.xml"
);
UserService userService =(UserService) ctx.getBean(
"userService"
);
// UserService userService2 =(UserService) ctx.getBean("userService2");
userService.updateUser();
// userService2.updateUser();
}
}
|
执行结果
=======保存更新日志=========
==========执行安全校验====================
$$$$$$执行业务逻辑$$$$$
说明:usePrefix和advisorBeanNamePrefix配合使用,如果usePrefix设置为false,advisorBeanNamePrefix设置没有作用。通过上面的设置配置,advisor2和advisor都有效果。
2.剖析DefaultAdvisorAutoProxyCreator类
2.1 结构层次图
可知,DefaultAdvisorAutoProxyCreator,BeanNameAutoProxyCreator是AbstractAutoProxyCreator的子类。通过前面讲解,知道AbstractAutoProxyCreator有个抽象方法。
方法声明如下
1
2
3
4
|
//是否被代理?返回interceptors
//Return whether the given bean is to be proxied, what additional advices (e.g. AOP Alliance interceptors) and advisors to apply.
protected
abstract
Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, TargetSource customTargetSource)
throws
BeansException;
|
DefaultAdvisorAutoProxyCreator 和BeanNameAutoProxyCreator分别实现各自逻辑。BeanNameAutoProxyCreator的实现不再赘述,在死磕Spring AOP系列2已经讲过,代码很简单。
2.2 剖析getAdvicesAndAdvisorsForBean方法
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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
public
abstract
class
AbstractAdvisorAutoProxyCreator
extends
AbstractAutoProxyCreator {
...
protected
Object[] getAdvicesAndAdvisorsForBean(Class beanClass, String beanName, TargetSource targetSource) {
List advisors = findEligibleAdvisors(beanClass, beanName);
if
(advisors.isEmpty()) {
return
DO_NOT_PROXY;
}
return
advisors.toArray();
}
protected
List<Advisor> findEligibleAdvisors(Class beanClass, String beanName) {
List<Advisor> candidateAdvisors = findCandidateAdvisors();
//获取所有的Advisors
//获取可以应用于beanName的Advisor(逻辑尽在此)
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if
(!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return
eligibleAdvisors;
}
//Find all candidate Advisors to use in auto-proxying.
protected
List<Advisor> findCandidateAdvisors() {
//委托给BeanFactoryAdvisorRetrievalHelper处理
return
this
.advisorRetrievalHelper.findAdvisorBeans();
}
}
public
class
BeanFactoryAdvisorRetrievalHelper {
public
List<Advisor> findAdvisorBeans() {
...
if
(advisorNames ==
null
) {
//获取容器中声明的Advisor
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the auto-proxy creator apply to them!
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this
.beanFactory, Advisor.
class
,
true
,
false
);
...
}
if
(advisorNames.length ==
0
) {
return
new
LinkedList<Advisor>();
}
List<Advisor> advisors =
new
LinkedList<Advisor>();
for
(String name : advisorNames) {
//判断返回
if
(isEligibleBean(name) && !
this
.beanFactory.isCurrentlyInCreation(name)) {
try
{
advisors.add(
this
.beanFactory.getBean(name, Advisor.
class
));
}
catch
(BeanCreationException ex) {
...
throw
ex;
}
}
}
return
advisors;
}
}
|
通过层层抽丝剥茧,定位到了AopUtils.findAdvisorsThatCanApply,负责具体的Advisor匹配工作。
3.剖析AopUtils.findAdvisorsThatCanApply方法,(匹配逻辑)
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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
protected
List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class beanClass, String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try
{
return
AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally
{
ProxyCreationContext.setCurrentProxiedBeanName(
null
);
}
}
public
static
List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if
(candidateAdvisors.isEmpty()) {
return
candidateAdvisors;
}
List<Advisor> eligibleAdvisors =
new
LinkedList<Advisor>();
for
(Advisor candidate : candidateAdvisors) {
//遍历
if
(candidate
instanceof
IntroductionAdvisor && canApply(candidate, clazz)) {
//是否IntroductionAdvisor
eligibleAdvisors.add(candidate);
}
}
boolean
hasIntroductions = !eligibleAdvisors.isEmpty();
for
(Advisor candidate : candidateAdvisors) {
if
(candidate
instanceof
IntroductionAdvisor) {
// already processed
continue
;
}
if
(canApply(candidate, clazz, hasIntroductions)) {
//执行
eligibleAdvisors.add(candidate);
}
}
return
eligibleAdvisors;
}
public
static
boolean
canApply(Advisor advisor, Class<?> targetClass,
boolean
hasIntroductions) {
if
(advisor
instanceof
IntroductionAdvisor) {
return
((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}
else
if
(advisor
instanceof
PointcutAdvisor) {
PointcutAdvisor pca = (PointcutAdvisor) advisor;
return
canApply(pca.getPointcut(), targetClass, hasIntroductions);
}
else
{
// It doesn't have a pointcut so we assume it applies.
return
true
;
}
}
public
static
boolean
canApply(Pointcut pc, Class<?> targetClass,
boolean
hasIntroductions) {
Assert.notNull(pc,
"Pointcut must not be null"
);
if
(!pc.getClassFilter().matches(targetClass)) {
return
false
;
}
MethodMatcher methodMatcher = pc.getMethodMatcher();
IntroductionAwareMethodMatcher introductionAwareMethodMatcher =
null
;
if
(methodMatcher
instanceof
IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
Set<Class> classes =
new
HashSet<Class>(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
classes.add(targetClass);
for
(Class<?> clazz : classes) {
Method[] methods = clazz.getMethods();
for
(Method method : methods) {
if
((introductionAwareMethodMatcher !=
null
&&
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||
methodMatcher.matches(method, targetClass)) {
//methodMatcher具体完成匹配
return
true
;
}
}
}
return
false
;
}
|
通过图得知Advisor,持有Advice的聚合信息和PointCut对象,而PointCut接口持有MethodMatcher。
最后MethodMatcher完成方法匹配工作。以当前例子为例,AbstractRegexpMethodPointcut同时也是MethodMatcher.
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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
public
abstract
class
AbstractRegexpMethodPointcut
extends
StaticMethodMatcherPointcut
implements
Serializable {
public
boolean
matches(Method method, Class targetClass) {
return
((targetClass !=
null
&& matchesPattern(targetClass.getName() +
"."
+ method.getName())) ||
matchesPattern(method.getDeclaringClass().getName() +
"."
+ method.getName()));
}
}
protected
boolean
matchesPattern(String signatureString) {
for
(
int
i =
0
; i <
this
.patterns.length; i++) {
boolean
matched = matches(signatureString, i);
if
(matched) {
for
(
int
j =
0
; j <
this
.excludedPatterns.length; j++) {
boolean
excluded = matchesExclusion(signatureString, j);
if
(excluded) {
return
false
;
}
}
return
true
;
}
}
return
false
;
}
public
class
JdkRegexpMethodPointcut
extends
AbstractRegexpMethodPointcut {
/**
* Returns {@code true} if the {@link Pattern} at index {@code patternIndex}
* matches the supplied candidate {@code String}.
*/
@Override
protected
boolean
matches(String pattern,
int
patternIndex) {
Matcher matcher =
this
.compiledPatterns[patternIndex].matcher(pattern);
return
matcher.matches();
}
/**
* Returns {@code true} if the exclusion {@link Pattern} at index {@code patternIndex}
* matches the supplied candidate {@code String}.
*/
@Override
protected
boolean
matchesExclusion(String candidate,
int
patternIndex) {
Matcher matcher =
this
.compiledExclusionPatterns[patternIndex].matcher(candidate);
return
matcher.matches();
}
/**
* Compiles the supplied {@code String[]} into an array of
* {@link Pattern} objects and returns that array.
*/
private
Pattern[] compilePatterns(String[] source)
throws
PatternSyntaxException {
Pattern[] destination =
new
Pattern[source.length];
for
(
int
i =
0
; i < source.length; i++) {
destination[i] = Pattern.compile(source[i]);
}
return
destination;
}
}
|
4.自动化
比起BeanNameAutoProxyCreator,DefaultAdvisorAutoProxyCreator有一个非常优越的地方。那就是advisor已有了自动匹配方法的能力。具体实现逻辑,通过上面的分析就是正则表达式的使用。其实很简单,确定一个方法是否被应用于advice,其实就是讲方法的签名字符串与定义PointCut的pattern进行匹配。今天提到的JdkRegexpMethodPointcut,只是实现之一。另外一个更强大的PointCut是什么?下次再说。
本文转自 randy_shandong 51CTO博客,原文链接:http://blog.51cto.com/dba10g/1786057,如需转载请自行联系原作者