转载请注明作者和出处 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"); } }
<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! *************************
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/
原文地址:http://blog.csdn.net/pearyangyang/article/details/45053913