这篇文章里面就要说说Spring自己的AOP,搞清楚哪种方式是Spring自己实现的AOP,哪种方式是Spring引入aspectj的AOP。
Spring自己的AOP实现在于ProxyFactoryBean。先看下使用案例(仍和之前的案例是一样的):接口AService、实现类AServiceImpl、通知MyBeforeAdvice
然后就是xml的配置:
然后就可以使用了:
运行这个单元测试,然后你就会看到报如下错误:
原因就是对于接口AService,有两个实现类aServiceImpl和ProxyFactoryBean所生产的代理类。所以我们不能使用@Autowired(它是按类型注入),所以要使用按名称注入,我们怎么获取ProxyFactoryBean所产生的代理类的名称呢?其实就是ProxyFactoryBean配置的名称。因为ProxyFactoryBean实现了FactoryBean接口,对于这种接口从容器中获取该bean,不是获取的本身而是获取他的getObject方法所返回的值,看FactoryBean的文档:
所以通过beanName找到了ProxyFactoryBean,然而不是返回该对象,而是返回他的getObject方法的返回值,所以我们通过ProxyFactoryBean的id就可以获取到它所产生的代理对象,所以更改如下:
在使用注入的时候按名称注入
然后就可以正常运行了如下:
然后我们就要源码分析下这一过程,先看下是如何产生代理对象的,在ProxyFactoryBean的getObject方法中:
重点1:就是根据我们配置的interceptorNames来获取对应的bean,并却转化成Advisor。如下:
this.advisorChainInitialized:标示是否已进行过初始化,若以初始化则不再进行初始化。然后就是将interceptorNames转化成Advisor。根据interceptorNames所包含的字符串到容器中进行查找,如果含有*则,则表示进行一定的匹配,符合的都会纳入。如官方文档中说的:
这中间页经过了Advice到Advisor的转换,如下:
这个包裹过程已经见过很多遍了,采用了适配器的模式。
之后又是和其他的AOP方式接轨了,设置一些列要实现的接口和参数,使用DefaultAopProxyFactory先创建出AopProxy,要么是JdkDynamicAopProxy,要么是CglibAopProxy,然后就可以调用AopProxy的getProxy方法来获取代理对象了。这个过程详见上一篇博客http://lgbolgger.iteye.com/blog/2119810。
这种方式实现的AOP还是比较麻烦的,同时配置一个ProxyFactoryBean仅能实现对一个目标对象的拦截,要想拦截多个目标对象,需要配置多个ProxyFactoryBean。所以大部分还是使用Spring引进的aspectj的AOP方式来进行AOP编程。
Spring自己的AOP实现在于ProxyFactoryBean。先看下使用案例(仍和之前的案例是一样的):接口AService、实现类AServiceImpl、通知MyBeforeAdvice
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
|
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
6
7
8
9
|
public
class
MyBeforeAdvice
implements
MethodBeforeAdvice{
@Override
public
void
before(Method method, Object[] args, Object target)
throws
Throwable {
System.out.println(
"run my before advice"
);
}
}
|
然后就是xml的配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<bean id=
"aServiceImpl"
class
=
"com.lg.aop.service.impl.AServiceImpl"
/>
<bean id=
"myBeforAdvice"
class
=
"com.lg.aop.MyBeforeAdvice"
/>
<bean
class
=
"org.springframework.aop.framework.ProxyFactoryBean"
>
<property name=
"interfaces"
value=
"com.lg.aop.service.AService"
/>
<property name=
"target"
>
<ref bean=
"aServiceImpl"
/>
</property>
<property name=
"interceptorNames"
>
<list>
<value>myBeforAdvice</value>
</list>
</property>
</bean>
|
然后就可以使用了:
1
2
3
4
5
6
7
|
@Autowired
private
AService aService;
@Test
public
void
testAOP(){
aService.barA();
}
|
运行这个单元测试,然后你就会看到报如下错误:
1
|
No qualifying bean of type [com.lg.aop.service.AService] is defined: expected single matching bean but found
2
: aServiceImpl,org.springframework.aop.framework.ProxyFactoryBean#
0
|
原因就是对于接口AService,有两个实现类aServiceImpl和ProxyFactoryBean所生产的代理类。所以我们不能使用@Autowired(它是按类型注入),所以要使用按名称注入,我们怎么获取ProxyFactoryBean所产生的代理类的名称呢?其实就是ProxyFactoryBean配置的名称。因为ProxyFactoryBean实现了FactoryBean接口,对于这种接口从容器中获取该bean,不是获取的本身而是获取他的getObject方法所返回的值,看FactoryBean的文档:
1
2
3
4
5
6
7
8
9
10
|
/**
* Interface to be implemented by objects used within a {
@link
BeanFactory}
* which are themselves factories. If a bean
implements
this
interface
,
* it is used as a factory
for
an object to expose, not directly as a bean
* instance that will be exposed itself.
*
* <p><b>NB: A bean that
implements
this
interface
cannot be used as a
* normal bean.</b> A FactoryBean is defined in a bean style, but the
* object exposed
for
bean references ({
@link
#getObject()} is always
* the object that it creates.
|
所以通过beanName找到了ProxyFactoryBean,然而不是返回该对象,而是返回他的getObject方法的返回值,所以我们通过ProxyFactoryBean的id就可以获取到它所产生的代理对象,所以更改如下:
1
2
|
<bean id=
"aServiceImplProxy"
class
=
"org.springframework.aop.framework.ProxyFactoryBean"
>
其他略
|
在使用注入的时候按名称注入
1
2
|
@Resource
(name=
"aServiceImplProxy"
)
private
AService aService;
|
然后就可以正常运行了如下:
1
2
|
run my before advice
AServiceImpl.barA()
|
然后我们就要源码分析下这一过程,先看下是如何产生代理对象的,在ProxyFactoryBean的getObject方法中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public
Object getObject()
throws
BeansException {
//重点1
initializeAdvisorChain();
if
(isSingleton()) {
//重点2
return
getSingletonInstance();
}
else
{
if
(
this
.targetName ==
null
) {
logger.warn(
"Using non-singleton proxies with singleton targets is often undesirable. "
+
"Enable prototype proxies by setting the 'targetName' property."
);
}
return
newPrototypeInstance();
}
}
|
重点1:就是根据我们配置的interceptorNames来获取对应的bean,并却转化成Advisor。如下:
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
|
private
synchronized
void
initializeAdvisorChain()
throws
AopConfigException, BeansException {
if
(
this
.advisorChainInitialized) {
return
;
}
if
(!ObjectUtils.isEmpty(
this
.interceptorNames)) {
if
(
this
.beanFactory ==
null
) {
throw
new
IllegalStateException(
"No BeanFactory available anymore (probably due to serialization) "
+
"- cannot resolve interceptor names "
+ Arrays.asList(
this
.interceptorNames));
}
// Globals can't be last unless we specified a targetSource using the property...
if
(
this
.interceptorNames[
this
.interceptorNames.length -
1
].endsWith(GLOBAL_SUFFIX) &&
this
.targetName ==
null
&&
this
.targetSource == EMPTY_TARGET_SOURCE) {
throw
new
AopConfigException(
"Target required after globals"
);
}
// Materialize interceptor chain from bean names.
for
(String name :
this
.interceptorNames) {
if
(logger.isTraceEnabled()) {
logger.trace(
"Configuring advisor or advice '"
+ name +
"'"
);
}
if
(name.endsWith(GLOBAL_SUFFIX)) {
if
(!(
this
.beanFactory
instanceof
ListableBeanFactory)) {
throw
new
AopConfigException(
"Can only use global advisors or interceptors with a ListableBeanFactory"
);
}
addGlobalAdvisor((ListableBeanFactory)
this
.beanFactory,
name.substring(
0
, name.length() - GLOBAL_SUFFIX.length()));
}
else
{
// If we get here, we need to add a named interceptor.
// We must check if it's a singleton or prototype.
Object advice;
if
(
this
.singleton ||
this
.beanFactory.isSingleton(name)) {
// Add the real Advisor/Advice to the chain.
advice =
this
.beanFactory.getBean(name);
}
else
{
// It's a prototype Advice or Advisor: replace with a prototype.
// Avoid unnecessary creation of prototype bean just for advisor chain initialization.
advice =
new
PrototypePlaceholderAdvisor(name);
}
addAdvisorOnChainCreation(advice, name);
}
}
}
this
.advisorChainInitialized =
true
;
}
|
this.advisorChainInitialized:标示是否已进行过初始化,若以初始化则不再进行初始化。然后就是将interceptorNames转化成Advisor。根据interceptorNames所包含的字符串到容器中进行查找,如果含有*则,则表示进行一定的匹配,符合的都会纳入。如官方文档中说的:
1
2
3
4
5
6
7
8
9
10
11
|
<bean id=
"proxy"
class
=
"org.springframework.aop.framework.ProxyFactoryBean"
>
<property name=
"target"
ref=
"service"
/>
<property name=
"interceptorNames"
>
<list>
<value>global*</value>
</list>
</property>
</bean>
<bean id=
"global_debug"
class
=
"org.springframework.aop.interceptor.DebugInterceptor"
/>
<bean id=
"global_performance"
class
=
"org.springframework.aop.interceptor.PerformanceMonitorInterceptor"
/>
|
这中间页经过了Advice到Advisor的转换,如下:
1
2
3
4
5
6
7
8
9
|
private
void
addAdvisorOnChainCreation(Object next, String name) {
// We need to convert to an Advisor if necessary so that our source reference
// matches what we find from superclass interceptors.
Advisor advisor = namedBeanToAdvisor(next);
if
(logger.isTraceEnabled()) {
logger.trace(
"Adding advisor with name '"
+ name +
"'"
);
}
addAdvisor(advisor);
}
|
1
2
3
4
5
6
|
private
Advisor namedBeanToAdvisor(Object next) {
try
{
return
this
.advisorAdapterRegistry.wrap(next);
}
}
}
|
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);
}
|
这个包裹过程已经见过很多遍了,采用了适配器的模式。
之后又是和其他的AOP方式接轨了,设置一些列要实现的接口和参数,使用DefaultAopProxyFactory先创建出AopProxy,要么是JdkDynamicAopProxy,要么是CglibAopProxy,然后就可以调用AopProxy的getProxy方法来获取代理对象了。这个过程详见上一篇博客http://lgbolgger.iteye.com/blog/2119810。
这种方式实现的AOP还是比较麻烦的,同时配置一个ProxyFactoryBean仅能实现对一个目标对象的拦截,要想拦截多个目标对象,需要配置多个ProxyFactoryBean。所以大部分还是使用Spring引进的aspectj的AOP方式来进行AOP编程。