本篇文章主要对Spring AOP配置背后进行了哪些事情做下说明。还是如上类似的工程,在xml中AOP拦截配置如下:
其中接口AService和类BServiceImpl都在com.lg.aop.service包下,AService的实现类
AServiceImpl在com.lg.aop.service.impl包下。
测试方法如下:
运行效果如下:
接下来就需要看下配置完成之后是如何生成代理对象的。
还是要从对xml中的配置<aop:config>标签的解析来入手。同样是从标签解析接口开始,即找BeanDefinitionParser的实现类,最终我们会找到AspectJAutoProxyBeanDefinitionParser是用来处理aspectj-autoproxy标签的,而ConfigBeanDefinitionParser则是用来处理aop:config标签的。看下ConfigBeanDefinitionParser的解析过程:
这个过程比较费劲,有兴趣的可以弄清楚。这里主要注册一些Advisor,同时注册了一个AspectJAwareAdvisorAutoProxyCreator,并且设置xml中所配置的proxy-target-class和expose-proxy到它的属性中。AspectJAwareAdvisorAutoProxyCreator本身存储着配置信息,然后使用这些配置创建出来代理对象,在它的父类AbstractAutoProxyCreator的createProxy方法中:
在该方法中创建出代理对象,待会我们再详细说这个过程。我们先看下ProxyFactory是什么东西。
把下面的图理解透了,就掌握了SpringAOP的整个运行机制。
然后我们就详细的说明下整个过程:
重点1:proxyFactory.copyFrom(this);将ProxyConfig信息复制到ProxyFactory 中。ProxyFactory、AspectJAwareAdvisorAutoProxyCreator都继承了ProxyConfig,ProxyConfig拥有代理的一些配置信息。看下ProxyConfig:
含有两个我们所关注的proxyTargetClass,exposeProxy :
proxyTargetClass:是否强制使用cglib来实现代理
exposeProxy:是否在线程内部暴露出代理对象(使用ThreadLocal模式实现线程内共享,见http://lgbolgger.iteye.com/blog/2116164中对exposeProxy的描述)。
重点2:复制完配置信息后,看下proxyTargetClass 属性是否为false,则查看目标类是否含有接口,若无则仍然设置proxyTargetClass为true,若有则把接口设置到ProxyFactory中。然后在设置些Advisor、targetSource等其他参数,为创建代理对象做准备。来看下上述Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);的具体内容:
对配置信息中的specificInterceptors全部封装成Advisor。再看下具体的封装过程,在上述wrap方法中
如果是Advisor直接返回不处理,接下来必须是Advice,然后通过MethodInterceptor和AdvisorAdapter 对Advice进行包装。对此过程还不清楚的,请先去看之前的接口介绍(http://lgbolgger.iteye.com/blog/2117214)
重点3:使用DefaultAopProxyFactory来创建AopProxy,有了AopProxy我们就能创建代理对象了。看下AopProxy的创建过程:
这里决定着到底采用jdk动态代理还是cglib方式来创建代理对象。
条件1:config.isOptimize()是否进行优化,默认是false。
条件2:config.isProxyTargetClass()就是ProxyConfig的proxyTargetClass属性,是否强制使用cglib代理。但它为true也不是肯定就采用cglib,因为下面还有一个判断条件,即目标类是接口,则使用jdk动态代理的方式。
条件3:hasNoUserSuppliedProxyInterfaces(config)目标类没有实现接口,或者有但是是接口类型是SpringProxy,如下:
只要上述三个条件有一个为true并且目标类不是接口就会采用cglib方式来创建代理对象,其他情况使用jdk动态代理的方式来创建。
有了JdkDynamicAopProxy和ObjenesisCglibAopProxy则可以顺利创建出代理对象,便可以跳到这篇文章http://lgbolgger.iteye.com/blog/2116164,至此整个过程就连接通了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<bean id=
"aspectBean"
class
=
"com.lg.aop.TestAspect"
/>
<aop:config expose-proxy=
"false"
proxy-target-
class
=
"false"
>
<aop:aspect id=
"TestAspect"
ref=
"aspectBean"
>
<aop:pointcut id=
"businessService1"
expression=
"execution(* com.lg.aop.service.*.bar*(..))"
/>
<aop:pointcut id=
"businessService2"
expression=
"execution(* com.lg.aop.service.*.foo*(..))"
/>
<aop:before pointcut-ref=
"businessService1"
method=
"doBefore"
/>
<aop:after pointcut-ref=
"businessService2"
method=
"doAfter"
/>
<aop:around pointcut-ref=
"businessService2"
method=
"doAround"
/>
<aop:after-throwing pointcut-ref=
"businessService1"
method=
"doThrowing"
throwing=
"ex"
/>
</aop:aspect>
</aop:config>
|
其中接口AService和类BServiceImpl都在com.lg.aop.service包下,AService的实现类
AServiceImpl在com.lg.aop.service.impl包下。
1
2
3
4
5
6
|
public
interface
AService {
public
void
fooA(String _msg);
public
void
barA();
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
@Service
public
class
BServiceImpl {
public
static
final
void
barB(String _msg,
int
_type) {
System.out.println(
"BServiceImpl.barB(msg:"
+_msg+
" type:"
+_type+
")"
);
if
(_type ==
1
)
throw
new
IllegalArgumentException(
"测试异常"
);
}
public
void
fooB() {
System.out.println(
"BServiceImpl.fooB()"
);
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
@Service
public
class
AServiceImpl
implements
AService{
@Override
public
void
fooA(String _msg) {
System.out.println(
"AServiceImpl.fooA(msg:"
+_msg+
")"
);
}
@Override
public
void
barA() {
System.out.println(
"AServiceImpl.barA()"
);
}
}
|
测试方法如下:
1
2
3
4
5
|
@Test
public
void
testAOP(){
aService.barA();
bServiceImpl.fooB();
}
|
运行效果如下:
1
2
3
4
5
|
log Begining method: com.lg.aop.service.impl.AServiceImpl.barA
AServiceImpl.barA()
BServiceImpl.fooB()
process time:
12
ms
log Ending method: com.lg.aop.service.BServiceImpl.fooB
|
接下来就需要看下配置完成之后是如何生成代理对象的。
还是要从对xml中的配置<aop:config>标签的解析来入手。同样是从标签解析接口开始,即找BeanDefinitionParser的实现类,最终我们会找到AspectJAutoProxyBeanDefinitionParser是用来处理aspectj-autoproxy标签的,而ConfigBeanDefinitionParser则是用来处理aop:config标签的。看下ConfigBeanDefinitionParser的解析过程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
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
;
}
|
这个过程比较费劲,有兴趣的可以弄清楚。这里主要注册一些Advisor,同时注册了一个AspectJAwareAdvisorAutoProxyCreator,并且设置xml中所配置的proxy-target-class和expose-proxy到它的属性中。AspectJAwareAdvisorAutoProxyCreator本身存储着配置信息,然后使用这些配置创建出来代理对象,在它的父类AbstractAutoProxyCreator的createProxy方法中:
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
|
protected
Object createProxy(
Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
ProxyFactory proxyFactory =
new
ProxyFactory();
// Copy our properties (proxyTargetClass etc) inherited from ProxyConfig.
//重点1
proxyFactory.copyFrom(
this
);
//重点2
if
(!proxyFactory.isProxyTargetClass()) {
if
(shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(
true
);
}
else
{
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
for
(Advisor advisor : advisors) {
proxyFactory.addAdvisor(advisor);
}
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(
this
.freezeProxy);
if
(advisorsPreFiltered()) {
proxyFactory.setPreFiltered(
true
);
}
//重点3
return
proxyFactory.getProxy(
this
.proxyClassLoader);
}
|
在该方法中创建出代理对象,待会我们再详细说这个过程。我们先看下ProxyFactory是什么东西。
把下面的图理解透了,就掌握了SpringAOP的整个运行机制。
然后我们就详细的说明下整个过程:
重点1:proxyFactory.copyFrom(this);将ProxyConfig信息复制到ProxyFactory 中。ProxyFactory、AspectJAwareAdvisorAutoProxyCreator都继承了ProxyConfig,ProxyConfig拥有代理的一些配置信息。看下ProxyConfig:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public
class
ProxyConfig
implements
Serializable {
/** use serialVersionUID from Spring 1.2 for interoperability */
private
static
final
long
serialVersionUID = -8409359707199703185L;
private
boolean
proxyTargetClass =
false
;
private
boolean
optimize =
false
;
boolean
opaque =
false
;
boolean
exposeProxy =
false
;
private
boolean
frozen =
false
;
}
|
含有两个我们所关注的proxyTargetClass,exposeProxy :
proxyTargetClass:是否强制使用cglib来实现代理
exposeProxy:是否在线程内部暴露出代理对象(使用ThreadLocal模式实现线程内共享,见http://lgbolgger.iteye.com/blog/2116164中对exposeProxy的描述)。
重点2:复制完配置信息后,看下proxyTargetClass 属性是否为false,则查看目标类是否含有接口,若无则仍然设置proxyTargetClass为true,若有则把接口设置到ProxyFactory中。然后在设置些Advisor、targetSource等其他参数,为创建代理对象做准备。来看下上述Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);的具体内容:
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
|
protected
Advisor[] buildAdvisors(String beanName, Object[] specificInterceptors) {
// Handle prototypes correctly...
Advisor[] commonInterceptors = resolveInterceptorNames();
List<Object> allInterceptors =
new
ArrayList<Object>();
if
(specificInterceptors !=
null
) {
allInterceptors.addAll(Arrays.asList(specificInterceptors));
if
(commonInterceptors !=
null
) {
if
(
this
.applyCommonInterceptorsFirst) {
allInterceptors.addAll(
0
, Arrays.asList(commonInterceptors));
}
else
{
allInterceptors.addAll(Arrays.asList(commonInterceptors));
}
}
}
if
(logger.isDebugEnabled()) {
int
nrOfCommonInterceptors = (commonInterceptors !=
null
? commonInterceptors.length :
0
);
int
nrOfSpecificInterceptors = (specificInterceptors !=
null
? specificInterceptors.length :
0
);
logger.debug(
"Creating implicit proxy for bean '"
+ beanName +
"' with "
+ nrOfCommonInterceptors +
" common interceptors and "
+ nrOfSpecificInterceptors +
" specific interceptors"
);
}
Advisor[] advisors =
new
Advisor[allInterceptors.size()];
for
(
int
i =
0
; i < allInterceptors.size(); i++) {
//重点重点重点重点重点重点重点
advisors[i] =
this
.advisorAdapterRegistry.wrap(allInterceptors.get(i));
}
return
advisors;
}
|
对配置信息中的specificInterceptors全部封装成Advisor。再看下具体的封装过程,在上述wrap方法中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
public
Advisor wrap(Object adviceObject)
throws
UnknownAdviceTypeException {
if
(adviceObject
instanceof
Advisor) {
return
(Advisor) adviceObject;
}
if
(!(adviceObject
instanceof
Advice)) {
throw
new
UnknownAdviceTypeException(adviceObject);
}
Advice advice = (Advice) adviceObject;
if
(advice
instanceof
MethodInterceptor) {
// So well-known it doesn't even need an adapter.
return
new
DefaultPointcutAdvisor(advice);
}
for
(AdvisorAdapter adapter :
this
.adapters) {
// Check that it is supported.
if
(adapter.supportsAdvice(advice)) {
return
new
DefaultPointcutAdvisor(advice);
}
}
throw
new
UnknownAdviceTypeException(advice);
}
|
如果是Advisor直接返回不处理,接下来必须是Advice,然后通过MethodInterceptor和AdvisorAdapter 对Advice进行包装。对此过程还不清楚的,请先去看之前的接口介绍(http://lgbolgger.iteye.com/blog/2117214)
重点3:使用DefaultAopProxyFactory来创建AopProxy,有了AopProxy我们就能创建代理对象了。看下AopProxy的创建过程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
@Override
public
AopProxy createAopProxy(AdvisedSupport config)
throws
AopConfigException {
if
(config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if
(targetClass ==
null
) {
throw
new
AopConfigException(
"TargetSource cannot determine target class: "
+
"Either an interface or a target is required for proxy creation."
);
}
if
(targetClass.isInterface()) {
return
new
JdkDynamicAopProxy(config);
}
return
new
ObjenesisCglibAopProxy(config);
}
else
{
return
new
JdkDynamicAopProxy(config);
}
}
|
这里决定着到底采用jdk动态代理还是cglib方式来创建代理对象。
条件1:config.isOptimize()是否进行优化,默认是false。
条件2:config.isProxyTargetClass()就是ProxyConfig的proxyTargetClass属性,是否强制使用cglib代理。但它为true也不是肯定就采用cglib,因为下面还有一个判断条件,即目标类是接口,则使用jdk动态代理的方式。
条件3:hasNoUserSuppliedProxyInterfaces(config)目标类没有实现接口,或者有但是是接口类型是SpringProxy,如下:
1
2
3
4
|
private
boolean
hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
Class<?>[] interfaces = config.getProxiedInterfaces();
return
(interfaces.length ==
0
|| (interfaces.length ==
1
&& SpringProxy.
class
.equals(interfaces[
0
])));
}
|
只要上述三个条件有一个为true并且目标类不是接口就会采用cglib方式来创建代理对象,其他情况使用jdk动态代理的方式来创建。
有了JdkDynamicAopProxy和ObjenesisCglibAopProxy则可以顺利创建出代理对象,便可以跳到这篇文章http://lgbolgger.iteye.com/blog/2116164,至此整个过程就连接通了。