1、Spring AOP编程之方法切入(Adivce)
Spring面向切面编程方法提供了拦截(代理)类,在方法调用前、执行完成后、发生异常时、或者综合上述三种情况,实现额外代码切入。spring AOP支持四种情况下的代码切入:
-
通知(Advice)之前 - 该方法执行前运行
- 通知(Advice)返回之后 – 运行后,该方法返回一个结果
- 通知(Advice)抛出之后 – 运行方法抛出异常后,
- 环绕通知 – 环绕方法执行运行,结合以上这三个通知。
如下示例代码。实现属性内容的打印输出:
package com.yiibai.customer.services;
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();
}
}
编写对象执行代理类,进行方法执行拦截,即:创建一个实现MethodBeforeAdvice接口的实现类
package com.yiibai.aop;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class HijackBeforeMethod implements MethodBeforeAdvice
{
@Override
public void before(Method method, Object[] args, Object target)
throws Throwable {
System.out.println("HijackBeforeMethod : Before method hijacked!");
}
}
在spring配置文件中增加类型为ProxyFactoryBean的bean定义,将该对象的拦截目标(target属性)设置为你需要拦截的对象,本例中即为CustomerServicce对象;将拦截器名称设置为MethodBeforeAdvice等接口的实现类,本例中为HijackBeforeMethod,spring 配置文件内容为:
<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.yiibai.customer.services.CustomerService">
<property name="name" value="Yiibai Mook Kim" />
<property name="url" value="http://www.yiibai.com" />
</bean>
<bean id="hijackBeforeMethodBean" class="com.yiibai.aop.HijackBeforeMethod" />
<bean id="customerServiceProxy"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="customerService" />
<property name="interceptorNames">
<list>
<value>hijackBeforeMethodBean</value>
</list>
</property>
</bean>
</beans>
注意:可以定义一组拦截器,分别实现方法执行前、执行后、以及执行异常时的代码切入
采用aop编程后,代码中实例化的bean将不再是被拦截对象,而是拦截代理类,以达到代码切入目的,示例代码如下:
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) {
}
}
}
若需要实现方法执行后拦截,需实现AfterReturningAdvice接口;实现异常拦截需实现ThrowAdvice接口;实现全面上述三种情况的代码切入需要实现MethodInterceptor接口类。再MethodInterceptor的接口实现类中,需要调用proceed()方法,以执行被拦截方法。MethodInterceptor接口实现类示例代码如下示意:
package com.yiibai.aop;
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()));
//注入方法执行前代码
System.out.println("HijackAroundMethod : Before method hijacked!");
try {
Object result = methodInvocation.proceed();
//注入方法执行后代码
System.out.println("HijackAroundMethod : Before after hijacked!");
return result;
} catch (IllegalArgumentException e) {
//注入异常处理代码
System.out.println("HijackAroundMethod : Throw exception hijacked!");
throw e;
}
}
}
2、使用切入点实现拦截方法选择
在Spring AOP中,有三个非常专业术语- Advices, Yiibaicut , Advisor,把它在非官方的方式...
- Advice – 指示之前或方法执行后采取的行动。即切入的代码。
- Yiibaicut – 指明哪些方法应该拦截,通过方法的名称或正则表达式模式。类似方法过滤器
- Advisor – 分组"通知"和”切入点“成为一个单元,并把它传递到代理工厂对象。组合拦截器和过滤器,实现对特定对象的特定方法进行拦截并注入代码。
<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-->
<bean id="customerService" class="com.yiibai.customer.services.CustomerService">
<property name="name" value="Yiibai" />
<property name="url" value="http://www.yiibai.com" />
</bean>
<!--代码注入bean-->
<bean id="hijackAroundMethodBeanAdvice" class="com.yiibai.aop.HijackAroundMethod" />
<!--注入代理-->
<bean id="customerServiceProxy"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="customerService" />
<property name="interceptorNames">
<list>
<!--采用Adivsor方式,实现按方法名称过滤的代码注入-->
<value>customerAdvisor</value>
</list>
</property>
</bean>
<!--代码注入过滤器-->
<bean id="customerYiibaicut"
class="org.springframework.aop.support.NameMatchMethodYiibaicut">
<property name="mappedName" value="printName" />
</bean>
<!--组合过滤器和拦截器-->
<bean id="customerAdvisor"
class="org.springframework.aop.support.DefaultYiibaicutAdvisor">
<property name="pointcut" ref="customerYiibaicut" />
<property name="advice" ref="hijackAroundMethodBeanAdvice" />
</bean>
</beans>
也可采用正则表达式进行拦截方法过滤,对应的advisor(没有使用过滤器,直接再adviosor中配置正则表达式)配置如下示意:
<bean id="customerAdvisor"
class="org.springframework.aop.support.RegexpMethodYiibaicutAdvisor">
<property name="patterns">
<list>
<value>.*URL.*</value>
</list>
</property>
<property name="advice" ref="hijackAroundMethodBeanAdvice" />
</bean>
备注:以上配置实现了针对特定对象进行拦截按照方法名称进行过滤后注入代码;而实际编程实现中常常要求按照对象名称和方法过滤后进行拦截并注入代码,针对的是一批对象的一批方法和名称,需要采用自动代理创建的方法实现代码切入,如使用:DefaultAdvisorAutoProxyCreator,它会自动根据bean对象是否具有Advisor定义的方法来启动代码切入。spring配置文件如下示意:
<bean id="customerAdvisor"
class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="mappedName" value="printName" />
<property name="advice" ref="hijackAroundMethodBeanAdvice" />
</bean>
<!--自动拦截代理-->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />
还可以采用BeanNameAutoProxyCreator对象,按照对象名称进行切入bean对象过滤,同时再使用adviosor中使用正则表达式进行方法名称过滤,实现特定对象、特定方法的代码切入,spring配置如下示意:
<bean id="customerAdvisor"
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="patterns">
<list>
<value>.*URL.*</value>
</list>
</property>
<property name="advice" ref="hijackAroundMethodBeanAdvice" />
</bean>
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>*Service</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>customerAdvisor</value>
</list>
</property>
</bean>
采用AOP编程的典型应用是实现持久层的事务处理,再更改执行前注入事务启动代码、更改执行后提交事务,执行失败发生异常时回滚事务