轉載請註明作者和出處 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/