易网时代-编程资源站
Welcome
微信登录
首页
/
操作系统
/
Linux
/
Spring中的AOP
何为AOP
AOP,面向切面编程。在不改动代码的前提下,灵活的在现有代码的执行顺序前后,添加进新规机能。来一个简单的Sample:
目标类:
[java]
package
com.hyron.tony;
public
class
CustomerService {
private
String name;
private
String url;
public
void
setName(String name) {
this
.name = name;
}
public
void
setUrl(String url) {
this
.url = url;
}
public
void
printName() {
System.out.println(
"Customer name : "
+
this
.name);
}
public
void
printURL() {
System.out.println(
"Customer website : "
+
this
.url);
}
public
void
printThrowException() {
throw
new
IllegalArgumentException();
}
}
advice
:只以Around
advice
为例
[java]
import
java.util.Arrays;
import
org.aopalliance.intercept.MethodInterceptor;
import
org.aopalliance.intercept.MethodInvocation;
public
class
HijackAroundMethod
implements
MethodInterceptor {
@Override
public
Object invoke(MethodInvocation methodInvocation)
throws
Throwable {
System.out.println(
"Method name : "
+ methodInvocation.getMethod().getName());
System.out.println(
"Method arguments : "
+ Arrays.toString(methodInvocation.getArguments()));
// same with MethodBeforeAdvice
System.out.println(
"HijackAroundMethod : Before method hijacked!"
);
try
{
// proceed to original method call
Object result = methodInvocation.proceed();
// same with AfterReturningAdvice
System.out.println(
"HijackAroundMethod : Before after hijacked!"
);
return
result;
}
catch
(IllegalArgumentException e) {
// same with ThrowsAdvice
System.out
.println(
"HijackAroundMethod : Throw exception hijacked!"
);
throw
e;
}
}
}
编织切入关系的配置文件:
[html]
<bean
id
=
"customerService"
class
=
"com.mkyong.customer.services.CustomerService"
>
<property
name
=
"name"
value
=
"Yong Mook Kim"
/>
<property
name
=
"url"
value
=
"http://www.mkyong.com"
/>
</bean>
<bean
id
=
"hijackAroundMethodBean"
class
=
"com.mkyong.aop.HijackAroundMethod"
/>
<bean
id
=
"customerServiceProxy"
class
=
"org.springframework.aop.framework.ProxyFactoryBean"
>
<property
name
=
"target"
ref
=
"customerService"
/>
<property
name
=
"interceptorNames"
>
<list>
<value>
hijackAroundMethodBean
</value>
</list>
</property>
</bean>
Sample的启动:
[java]
import
org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
import
com.mkyong.customer.services.CustomerService;
public
class
App {
public
static
void
main(String[] args) {
ApplicationContext appContext =
new
ClassPathXmlApplicationContext(
new
String[] {
"Spring-Customer.xml"
});
CustomerService cust = (CustomerService) appContext
.getBean(
"customerServiceProxy"
);
System.out.println(
"*************************"
);
cust.printName();
System.out.println(
"*************************"
);
cust.printURL();
System.out.println(
"*************************"
);
try
{
cust.printThrowException();
}
catch
(Exception e) {
}
}
}
以上代码,用customerServiceProxy代理CustomerService的执行在customerServiceProxy的配置中,定义了用hijackAroundMethodBean作为方法拦截器,在hijackAroundMethodBean中利用
invoke方法,拦截住所有的方法调用,塞入自己的逻辑业务。
AOP的两种实现
上面看到的是Spring的Sample。 其实,Spring的AOP也是调用了其他开源技术实现。 比较常用的是JDK自己的Proxy,和开源的CGLIB 两者的区别,Proxy需要Advice必须从接口继承过来。如果切入的目标物是实体类,则无法使用。 CGLIB则可以用于直接覆盖实体类的方法。 Spring对以上两种都有支持。
Spring的底层实现
Spring在配置文件中,通过
ProxyFactoryBean
编织和实现了切面的构成。 我们在执行以下这行话的时候
CustomerService cust = (CustomerService) appContext
.getBean("customerServiceProxy");
其实是将动态对象的生成委托给了
ProxyFactoryBean
当配置文件中 <bean>的class属性配置的实现类是FactoryBean时,通过getBean方法返回的不是FactoryBean本身,而是 FactoryBean#getObject()方法所返回的对象,相当于FactoryBean#getObject()代理了getBean()方 法。
执行顺序如下:
1.
ProxyFactoryBean中的getObject
[java]
/**
* Return a proxy. Invoked when clients obtain beans from this factory bean.
* Create an instance of the AOP proxy to be returned by this factory.
* The instance will be cached for a singleton, and create on each call to
* <code>getObject()</code> for a proxy.
* @return a fresh AOP proxy reflecting the current state of this factory
*/
public
Object getObject()
throws
BeansException {
initializeAdvisorChain();
if
(isSingleton()) {
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();
}
}
2.
ProxyFactoryBean中的
initializeAdvisorChain从配置文件中的advice list中取得interceptorNames,并将其加入advisorChain
[java]
view plain
copy
print
?
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()));
}
版权所有©石家庄振强科技有限公司2024
冀ICP备08103738号-5
网站地图