转载请注明作者和出处 Coder的不平凡:http://blog.csdn.net/pearyangyang/article/details/45053913
我们知道Spring有两个重要的特性:IOC和AOP ,大学期间只是对Spring有一个粗浅的认识,认为spring就是配置类,建立bean,然后就可以调用类的方法。直到慢慢了解才知道Spring还有很深的东西,Spring的强大。
这篇博文主要讲述Spring AOP 的 hijack(拦截) 功能,主要描述为当我们在执行一个类的方法的时候我们可以在方法执行前和执行后增加额外的方法
原文就是 Spring AOP can hijack the executing method,and add extra functionality before or after the method execution
我们先声明一个实体类,CustomerService
package com.kwe.bean; /**
* bean
* @author rey.yang
*
*/
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();
}
}
项目的目录大致是这样的:
配置文件spring-customer.xml 放在src的根目录下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="customerService" class="com.kwe.bean.CustomerService">
<property name="name" value="yang yang"></property>
<property name="url" value="http://www.csdn.net"></property>
</bean>
</beans>
测试配置是否OK?
public class App {
public static void main(String[] args) {
ApplicationContext appContext = new ClassPathXmlApplicationContext(
new String[] { "spring-customer.xml" });
CustomerService cust = (CustomerService) appContext.getBean("customerService");
System.out.println("*************************");
cust.printName();
System.out.println("*************************");
cust.printURL();
System.out.println("*************************");
try {
cust.printThrowException();
} catch (Exception e) {
}
}
}
输出如下(没有对方法进行拦截的输出):
*************************
Customer name : yang yang
*************************
Customer website : http://www.csdn.net
*************************
我们建立一个拦截类HijackBeforeMethod继承MethodBeforeAdvice
public class HijackBeforeMethod implements MethodBeforeAdvice{
@Override
public void before(Method method, Object[] args, Object target)
throws Throwable {
System.out.println("HijackBeforeMethod:Before method hijack");
}
}
然后在spring-customer2.xml下配置:
<bean id="customerService" class="com.kwe.bean.CustomerService">
<property name="name" value="yang yang"></property>
<property name="url" value="http://www.csdn.net"></property>
</bean>
<bean id="hijackBeforeMethod" class="com.kwe.hijack.HijackBeforeMethod"></bean>
<bean id="customerServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- target define which bean you want to hijack -->
<property name="target" ref="customerService"></property>
<!-- interceptorNames define which class(advice) you want to apply on this proxy/target object -->
<property name="interceptorNames">
<list>
<value>hijackBeforeMethod</value>
</list>
</property>
</bean>
这里解释一下<property name="target" ref = "customerService"></property> 代表要拦截的类是customerService
<property name="interceptorNames"> 中 <value>hijackBeforeMethod</value>代表基于customerService拦截类的是HijackBeforeMethod
执行一下App(把配置文件改成spring-customer2.xml和相关bean修改下即可),
public class App2 {
public static void main(String[] args) {
ApplicationContext appContext = new ClassPathXmlApplicationContext(
new String[] { "spring-customer2.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) {
}
}
}
输出为:
*************************
HijackBeforeMethod:Before method hijack
Customer name : yang yang
*************************
HijackBeforeMethod:Before method hijack
Customer website : http://www.csdn.net
*************************
HijackBeforeMethod:Before method hijack
我们可以看到它在每个方法执行前都做了一个拦截。
同理,我们想在实体类的方法完成之后再进行操作,则我们可以建立一个HijackAfterMethod实现AfterReturningAdvice类:
public class HijackAfterMethod implements AfterReturningAdvice{
@Override
public void afterReturning(Object returnValue, Method method, Object[] args,
Object target) throws Throwable {
System.out.println("HijackAfterMethod: After method hijacked!");
}
}
在配置文件中进行相关配置,略微改变一点即可:
<bean id="customerServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- target define which bean you want to hijack -->
<property name="target" ref="customerService"></property>
<!-- interceptorNames define which class(advice) you want to apply on this proxy/target object -->
<property name="interceptorNames">
<list>
<value>hijackAfterMethod</value>
</list>
</property>
</bean>
public class App3 {
public static void main(String[] args) {
ApplicationContext appContext = new ClassPathXmlApplicationContext(
new String[] { "spring-customer3.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) {
}
}
}
执行一下,得到我们想要的:
*************************
Customer name : yang yang
HijackAfterMethod: After method hijacked!
*************************
Customer website : http://www.baidu.com
HijackAfterMethod: After method hijacked!
*************************
另外我们想拦截捕获的异常,则可以建立一个HijackThrowException实现ThrowsAdvice接口
public class HijackThrowException implements ThrowsAdvice{
public void afterThrowing(IllegalArgumentException e) throws Throwable{
System.out.println("HijackThrowException:Throw exception hijacked");
}
}
配置文件如上,只修改关键字段名字即可,主类的方法也是一样,执行一下看到,在抛出异常的时候就对方法进行了拦截。
*************************
Customer name : yang yang
*************************
Customer website : http://www.baidu.com
*************************
HijackThrowException:Throw exception hijacked
那么我们想对实体类方法执行前和执行后进行拦截,我们要怎么办? ,这个稍微要复杂些....
/**
* 集合了方法拦截前后和异常的拦截
* @author rey.yang
*
*/
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 ThrowAdvice
System.out.println("HijackArounMethod:Throw exception hijacked!");
throw e;
}
}
}
配置文件如下:
<bean id="hijackAroundMethodBean" class="com.kwe.hijack.HijackAroundMethod"></bean>
<bean id="customerServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- target define which bean you want to hijack -->
<property name="target" ref="customerService"></property>
<!-- interceptorNames define which class(advice) you want to apply on this proxy/target object -->
<property name="interceptorNames">
<list>
<value>hijackAroundMethodBean</value>
</list>
</property>
</bean>
执行一下得到
*************************
Method name:printName
Method arguments:[]
HijackAroundMethod:Before method hijacked!
Customer name : yang yang
HijackAroundMethod:Before after hijacked!
*************************
Method name:printURL
Method arguments:[]
HijackAroundMethod:Before method hijacked!
Customer website : http://www.baidu.com
HijackAroundMethod:Before after hijacked!
*************************
Method name:printThrowException
Method arguments:[]
HijackAroundMethod:Before method hijacked!
HijackArounMethod:Throw exception hijacked!
在Spring AOP中,应该掌握三种配置方法:Advice,Poingcut,Advisor ,上面的例子是用Advice方式进行对方法的拦截。我们可以根据相应的需求进行对应的实现。
原文链接:http://www.mkyong.com/spring/spring-aop-examples-advice/