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

Spring AOP三种拦截方式举例详解

2015-01-29 17:46 399 查看
Spring的AOP是上面代理模式的深入。使用Spring AOP,开发者无需实现业务逻辑对象工厂,无需实现代理工厂,这两个工厂都由Spring容器充当。Spring AOP不仅允许使用XML文件配置目标方法,ProxyHandler也允许使用依赖注入管理,Spring AOP提供了更多灵活的选择。

在下面Spring AOP的示例中,InvocationHandler采用动态配置,需要增加的方法也采用动态配置,一个目标对象可以有多个拦截器(类似于代理模式中的代理处理器)。

下面是原始的目标对象:

//目标对象的接口

public interface Person

{

//该接口声明了两个方法

void info();

void run();

}

下面是原始目标对象的实现类,实现类的代码如下:

//目标对象的实现类,实现类实现Person接口

public class PersonImpl implements Person

{

// 两个成员属性

private String name;

private int age;

// name属性的 setter方法

public void setName(String name) {

this.name = name;

}

// age属性的setter方法

public void setAge(int age) {

this.age = age;

}

// info方法,该方法仅仅在控制台打印一行字符串

public void info() {

System.out.println("我的名字是: " + name + " , 今年年龄为: " + age);

}

// run方法,该方法也在控制台打印一行字符串。

public void run() {

if (age < 45) {

System.out.println("我还年轻,奔跑迅速...");

} else {

System.out.println("我年老体弱,只能慢跑...");

}

}

}

该Person实例将由Spring容器负责产生和管理,name属性和age属性也采用依赖注入管理。

为了充分展示Spring AOP的功能,此处为Person对象创建三个拦截器。第一个拦截器是调用方法前的拦截器,代码如下:

//调用目标方法前的拦截器,拦截器实现MethodBeforeAdvice接口

public class MyBeforeAdvice implements MethodBeforeAdvice

{

//实现MethodBeforeAdvice接口,必须实现before方法,该方法将在目标

//方法调用之前,自动被调用。

public void before(Method m, Object[] args, Object target) throws Throwable

{

System.out.println("方法调用之前...");

System.out.println("下面是方法调用的信息:");

System.out.println("所执行的方法是:" + m);

System.out.println("调用方法的参数是:" + args);

System.out.println("目标对象是:" + target);

}

}

第二个拦截器是方法调用后的拦截器,该拦截器将在方法调用结束后自动被调用,拦截器代码如下:

//调用目标方法后的拦截器,该拦截器实现AfterReturningAdvice接口

public class MyAfterAdvice implements AfterReturningAdvice

{

//实现AfterReturningAdvice接口必须实现afterReturning方法,该方法将在目标方法

//调用结束后,自动被调用。

public void afterReturning(Object returnValue, Method m, Object[] args, Object target)throws Throwable

{

System.out.println("方法调用结束...");

System.out.println("目标方法的返回值是 : " + returnValue);

System.out.println("目标方法是 : " + m);

System.out.println("目标方法的参数是 : " + args);

System.out.println("目标对象是 : " + target);

}

}

第三个拦截器是是Around拦截器,该拦截器既可以在目标方法之前调用,也可以在目标方法调用之后被调用。下面是Around拦截器的代码:

//Around拦截器实现MethodInterceptor接口

public class MyAroundInterceptor implements MethodInterceptor

{

//实现MethodInterceptor接口必须实现invoke方法

public Object invoke(MethodInvocation invocation) throws Throwable

{

//调用目标方法之前执行的动作

System.out.println("调用方法之前: invocation对象:[" + invocation + "]");

//调用目标方法

Object rval = invocation.proceed();

//调用目标方法之后执行的动作

System.out.println("调用结束...");

return rval;

}

}

利用Spring AOP框架,实现之前的代理模式相当简单。只需要实现对应的拦截器即可,无需创建自己的代理工厂,只需采用Spring容器作为代理工厂。下面在Spring配置文件中配置目标bean,以及拦截器。

下面是Spring配置文件的代码:

<?xml version="1.0" encoding="gb2312"?>

<!-- Spring配置文件的文件头-->

<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"

"http://www.springframework.org/dtd/spring-beans.dtd">

<!-- Spring配置文件的根元素-->

<beans>

<!-- 配置目标对象-->

<bean id="personTarget" class="lee.PersonImpl">

<!-- 为目标对象注入name属性值-->

<property name="name">

<value>Wawa</value>

</property>

<!-- 为目标对象注入age属性值-->

<property name="age">

<value>51</value>

</property>

</bean>

<!-- 第一个拦截器-->

<bean id="myAdvice" class="lee.MyBeforeAdvice" />

<!-- 第二个拦截器-->

<bean id="myAroundInterceptor" class="lee.MyAroundInterceptor" />

<!-- 将拦截器包装成Advisor,该对象还确定代理对怎样的方法增加处理-->

<bean id="runAdvisor"

class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">

<!-- advice属性确定处理bean-->

<property name="advice">

<!-- 此处的处理bean定义采用嵌套bean,也可引用容器的另一个bean-->

<bean class="lee.MyAfterAdvice" />

</property>

<!-- patterns确定正则表达式模式-->

<property name="patterns">

<list>

<!-- 确定正则表达式列表-->

<value>.*run.*</value>

</list>

</property>

</bean>

<!-- 使用ProxyFactoryBean 产生代理对象-->

<bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean">

<!-- 代理对象所实现的接口-->

<property name="proxyInterfaces">

<value>lee.Person</value>

</property>

<!-- 设置目标对象-->

<property name="target">

<ref local="personTarget" />

</property>

<!-- 代理对象所使用的拦截器-->

<property name="interceptorNames">

<list>

<value>runAdvisor</value>

<value>myAdvice</value>

<value>myAroundInterceptor</value>

</list>

</property>

</bean>

</beans>

该配置文件使用ProxyFactoryBean来生成代理对象,配置ProxyFactoryBean工厂bean时,指定了target属性,该属性值就是目标对象,该属性值为personTarget,指定代理的目标对象为personTarget。通过interceptorNames属性确定代理需要的拦截器,拦截器可以是普通的Advice,普通Advice将对目标对象的所有方法起作用,拦截器也可以是Advisor,Advisor是Advice和切面的组合,用于确定目标对象的哪些方法需要增加处理,以及怎样的处理。在上面的配置文件中,使用了三个拦截器,其中myAdvice、myAroundInterceptor都是普通Advice,它们将对目标对象的所有方法起作用。而runAdvisor则使用了正则表达式切面,匹配run方法,即该拦截器只对目标对象的run方法起作用。

下面是测试代理的主程序:

public class BeanTest

{

public static void main(String[] args)throws Exception

{

//创建Spring容器

ApplicationContext ctx = new FileSystemXmlApplicationContext("bean.xml");

//获取代理对象

Person p = (Person)ctx.getBean("person");

//执行info方法

p.info();

System.out.println("===========================================");

//执行run方法

p.run();

}

}

下面是程序的执行结果:

方法调用之前...

下面是方法调用的信息:

所执行的方法是:public abstract void lee.Person.info()

调用方法的参数是:null

目标对象是:lee.PersonImpl@b23210

调用方法之前: invocation对象:[invocation: method 'info', arguments

[]; target is of class [lee.PersonImpl]]

我的名字是: Wawa , 今年年龄为: 51

调用结束...

===========================================

方法调用之前...

下面是方法调用的信息:

所执行的方法是:public abstract void lee.Person.run()

调用方法的参数是:null

目标对象是:lee.PersonImpl@b23210

调用方法之前: invocation对象:[invocation: method 'run', arguments [

]; target is of class [lee.PersonImpl]]

我年老体弱,只能慢跑...

调用结束...

方法调用结束...

目标方法的返回值是 : null

目标方法是 : public abstract void lee.Person.run()

目标方法的参数是 : null

目标对象是 : lee.PersonImpl@b23210

程序的执行结果中一行“=”用于区分两次调用的方法。在调用info方法时,只有myAdvice和myAroundInterceptor两个拦截器起作用,调用run方法时候,三个拦截器都起作用了。

通过上面的介绍,可看出Spring的AOP框架是对代理模式简化,并拓展了代理模式的使用。

Spring AOP是Spring声明式事务的基础。了解Spring AOP对深入理解Spring的声明式事务管理是非常有好处的。Spring AOP还可以完成很多功能,例如基于AOP的权限检查。

原文链接:
http://blog.sina.com.cn/s/blog_624a352c01018bsr.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: