您的位置:首页 > 编程语言 > Java开发

spring学习笔记(8)AOP增强(advice)配置与应用

2016-03-20 21:14 741 查看

增强类型

增强(advice)主要包括如下五种类型

1. 前置增强(BeforeAdvice):在目标方法执行前实施增强

2. 后置增强(AfterReturningAdvice):在目标方法执行后实施增强

3. 环绕增强(MrthodInterceptor):在目标方法执行前后实施增强

4. 异常抛出增强(ThrowsAdvice):在目标方法抛出异常后实施增强

5. 引介增强(IntroductionIntercrptor):在目标类中添加一些新的方法和属性

前置增强和后置增强配置

下面通过实例代码来分析前置增强,假如现在要作日志记录,记录了什么人调用什么方法。前置增强的配置可归纳为如下步骤:

1. 配置代理接口:

package test.aop;

public interface ITarget {
String speak(String name);
}


2. 定义被代理对象

package test.aop;
//被代理对象
public class Target implements ITarget{

private static final String name = "zenghao";
@Override
public String speak(Integer age){
System.out.println("hello I'm " + age + " years old");
return "I'm return value";
}
public static String getName() {
return name;
}
}


3. 配置增强

package test.aop;

import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;

public class BeforeAdvice implements MethodBeforeAdvice {
/**
* @param method:目标类的方法
* args: 目标类的方法入参
* obj:目标类实例
*
*/
@Override
public void before(Method method, Object[] args, Object target)
throws Throwable {
if(target instanceof Target){
System.out.println("前置日志记录: "  +  ((Target)target).getName() + "调用了" + method.getName() + "方法,传入参数为:" + args[0] );
}
}

}
/*------------------分割线---------------------*/
package test.aop;

import java.lang.reflect.Method;

import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;

public class AfterAdvice implements  AfterReturningAdvice {
/**
* @param
* returnValue 返回值
* method:目标类的方法
* args: 目标类的方法入参
* obj:目标类实例
*
*/
@Override
public void afterReturning(Object returnValue, Method method,
Object[] args, Object target) throws Throwable {
if(target instanceof Target){
System.out.println("后置日志记录: "  +  ((Target)target).getName() + "调用了" + method.getName() + "方法,返回值为:" + returnValue );
}
}

}


4. 配置代理对象ProxyFactoryBean

PeoxyFactoryBean是FactoryBean的实现类,我们知道FactoryBean负责初始化Bean,而ProxyFactoryBean则负责为其他Bean创建代理实例,通过在xml中配置后注入使用

<!--  配置被代理对象 -->
<bean id="mytarget" class="test.aop.Target" />
<!-- 配置前置增强  -->
<bean id="myBeforeAdvice" class="test.aop.BeforeAdvice" />
<!-- 配置后置增强 -->
<bean id="myAfterReturnAdvice" class="test.aop.AfterAdvice" />
<!-- 配置代理对象 -->
<bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean" >
<!-- 配置代理接口集 -->
<property name="proxyInterfaces" value="test.aop.ITarget" />
<!-- 代理目标对象需要实现的接口,可以通过<list>标签设置多个 -->
<!-- 把通知织入代理对象 -->
<property name="interceptorNames" >
<list>
<idref bean="myBeforeAdvice"/>
<idref bean="myAfterReturnAdvice"/>
</list>
</property><!-- 配置实现了Advice增强接口的Bean,以bean名字进行指定 -->
<property name="targetName" value="mytarget"></property><!-- 代理的目标对象 -->
</bean>


5. 测试

package test.aop;

import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestAOP {

private ApplicationContext ac;
@Before
public void setup(){
ac = new ClassPathXmlApplicationContext("classpath:test/aop/aop.xml");
}

@Test
public void test(){
ITarget iTarget = (ITarget) ac.getBean("proxyFactoryBean");
iTarget.speak(21);
}
}


测试打印:

前置日志记录: zenghao调用了speak方法,传入参数为:21

hello I’m 21 years old

后置日志记录: zenghao调用了speak方法,返回值为:I’m return value

环绕增强配置

在前面的基础上,我们新增环绕增强类:

package test.aop;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class AroundAdvice implements MethodInterceptor {

@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println(invocation.getArguments()[0] + "——" +
invocation.getStaticPart() + "——" +
invocation.getThis().getClass() + "——" +
invocation.getMethod().getName());
invocation.proceed();//反射调用目标对象方法
System.out.println("环绕增强调用结束");
return "I'm around return value";
}
}


在aop.xml中类似前置增强增加环绕增强配置,运行测试方法,得到结果:

前置日志记录: zenghao调用了speak方法,传入参数为:21

21——public abstract java.lang.String test.aop.ITarget.speak(java.lang.Integer)——class test.aop.Target——speak

hello I’m 21 years old

环绕增强调用结束

后置日志记录: zenghao调用了speak方法,返回值为:I’m around return value

从以上我们能看到,当同时使用环绕增强和前后置增强时,它们的执行顺序

异常增强配置

常用场景为配置实物管理器,当进行数据库操作的方法发生异常时,可被异常增强捕获,进行失误回滚等操作。一个抛出异常增强的实例如下所示:

package test.aop;

import java.lang.reflect.Method;
import java.sql.SQLException;

import org.springframework.aop.ThrowsAdvice;

public class ExceptionAdvice implements ThrowsAdvice {
public void AfterThrowing(SQLException e){
System.out.println(e.getMessage());
}
public void AfterThrowing(RuntimeException e){
System.out.println(e.getMessage());
}
public void AfterThrowing(Method method, Object[] args, Object target,SQLException e){
System.out.println(e.getMessage());
}
}


其中有几点是需要注意的:

1. 方法名必须为:afterThrowing

2. 三个入参Method method, Object[] args, Object target 要么一起提供,要么都不提供,而最后一个入参必须为Throwable或其子类。当目标对象抛出异常时,增强会调用相似度最高的匹配异常类的方法(在类的继承树上,两个类的距离越近,相似度就越高)

关于引介增强,它可以动态地为类增加新的接口或方法,具有难以想象的动态特性,在后面的学习中我们会再单独提到。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: