??xml version="1.0" encoding="utf-8" standalone="yes"?>
Spring AOP介绍
Spring的AOP是上面代理模式的深入。用Spring AOPQ开发者无需实现业务逻辑对象工厂Q无需实现代理工厂Q这两个工厂都由Spring容器充当。Spring AOP不仅允许使用XML文g配置目标ҎQProxyHandler也允怋用依赖注入管理,Spring AOP提供了更多灵zȝ选择?br />
在下面Spring AOP的示例中QInvocationHandler采用动态配|,需要增加的Ҏ也采用动态配|,一个目标对象可以有多个拦截器(cM于代理模式中的代理处理器Q?br />
下面是原始的目标对象Q?br />
//目标对象的接?br />
public interface Person
{
//该接口声明了两个Ҏ
void info();
void run();
}
下面是原始目标对象的实现c,实现cȝ代码如下Q?br />
//目标对象的实现类Q实现类实现Person接口
public class PersonImpl implements Person
{
//两个成员属?br />
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ҎQ该Ҏ仅仅在控制台打印一行字W串
public void info()
{
System.out.println("我的名字? " + name + " , 今年q龄? " + age);
}
//runҎQ该Ҏ也在控制台打C行字W串?br />
public void run()
{
if (age < 45)
{
System.out.println("我还q轻Q奔跑迅?..");
}
else
{
System.out.println("我年老体弱,只能慢跑...");
}
}
}
该Person实例由Spring容器负责产生和管理,name属性和age属性也采用依赖注入理?br />
Z充分展示Spring AOP的功能,此处为Person对象创徏三个拦截器。第一个拦截器是调用方法前的拦截器Q代码如下:
//调用目标Ҏ前的拦截器,拦截器实现MethodBeforeAdvice接口
public class MyBeforeAdvice implements MethodBeforeAdvice
{
//实现MethodBeforeAdvice接口Q必d现beforeҎQ该Ҏ在目标
//Ҏ调用之前Q自动被调用?br />
public void before(Method m, Object[] args, Object target) throws Throwable
{
System.out.println("Ҏ调用之前...");
System.out.println("下面是方法调用的信息Q?);
System.out.println("所执行的方法是:" + m);
System.out.println("调用Ҏ的参数是Q? + args);
System.out.println("目标对象是:" + target);
}
}
W二个拦截器是方法调用后的拦截器Q该拦截器将在方法调用结束后自动被调用,拦截器代码如下:
//调用目标Ҏ后的拦截器,该拦截器实现AfterReturningAdvice接口
public class MyAfterAdvice implements AfterReturningAdvice
{
//实现AfterReturningAdvice接口必须实现afterReturningҎQ该Ҏ在目标Ҏ
//调用l束后,自动被调用?br />
public void afterReturning(Object returnValue, Method m, Object[] args, Object target)throws Throwable
{
System.out.println("Ҏ调用l束...");
System.out.println("目标Ҏ的返回值是 : " + returnValue);
System.out.println("目标Ҏ?: " + m);
System.out.println("目标Ҏ的参数是 : " + args);
System.out.println("目标对象?: " + target);
}
}
W三个拦截器是是Around拦截器,该拦截器既可以在目标Ҏ之前调用Q也可以在目标方法调用之后被调用。下面是Around拦截器的代码Q?br />
//Around拦截器实现MethodInterceptor接口
public class MyAroundInterceptor implements MethodInterceptor
{
//实现MethodInterceptor接口必须实现invokeҎ
public Object invoke(MethodInvocation invocation) throws Throwable
{
//调用目标Ҏ之前执行的动?br />
System.out.println("调用Ҏ之前: invocation对象Q[" + invocation + "]");
//调用目标Ҏ
Object rval = invocation.proceed();
//调用目标Ҏ之后执行的动?br />
System.out.println("调用l束...");
return rval;
}
}
利用Spring AOP框架Q实C前的代理模式相当单。只需要实现对应的拦截器即可,无需创徏自己的代理工厂,只需采用Spring容器作ؓ代理工厂。下面在Spring配置文g中配|目标beanQ以及拦截器?br />
下面是Spring配置文g的代码:
<?xml version="1.0" encoding="gb2312"?>
<!-- Spring配置文g的文件头-->
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<!-- Spring配置文g的根元素-->
<beans>
<!-- 配置目标对象-->
<bean id="personTarget" class="lee.PersonImpl">
<!-- 为目标对象注入name属性?->
<property name="name">
<value>Wawa</value>
</property>
<!-- 为目标对象注入age属性?->
<property name="age">
<value>51</value>
</property>
</bean>
<!-- W一个拦截器-->
<bean id="myAdvice" class="lee.MyBeforeAdvice"/>
<!-- W二个拦截器-->
<bean id="myAroundInterceptor" class="lee.MyAroundInterceptor"/>
<!-- 拦截器包装成AdvisorQ该对象q确定代理对怎样的方法增加处?->
<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属性,该属性值就是目标对象,该属性gؓpersonTargetQ指定代理的目标对象为personTarget。通过interceptorNames属性确定代理需要的拦截器,拦截器可以是普通的AdviceQ普通Advice对目标对象的所有方法v作用Q拦截器也可以是AdvisorQAdvisor是Advice和切面的l合Q用于确定目标对象的哪些Ҏ需要增加处理,以及怎样的处理。在上面的配|文件中Q用了三个拦截器,其中myAdvice、myAroundInterceptor都是普通AdviceQ它们将对目标对象的所有方法v作用。而runAdvisor则用了正则表达式切面,匚wrunҎQ即该拦截器只对目标对象的runҎ起作用?br />
下面是测试代理的ȝ序:
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();
}
}
下面是程序的执行l果Q?br />
Ҏ调用之前...
下面是方法调用的信息Q?br />
所执行的方法是:public abstract void lee.Person.info()
调用Ҏ的参数是Qnull
目标对象是:lee.PersonImpl@b23210
调用Ҏ之前: invocation对象Q[invocation: method 'info', arguments
[]; target is of class [lee.PersonImpl]]
我的名字? Wawa , 今年q龄? 51
调用l束...
===========================================
Ҏ调用之前...
下面是方法调用的信息Q?br />
所执行的方法是:public abstract void lee.Person.run()
调用Ҏ的参数是Qnull
目标对象是:lee.PersonImpl@b23210
调用Ҏ之前: invocation对象Q[invocation: method 'run', arguments [
]; target is of class [lee.PersonImpl]]
我年老体弱,只能慢跑...
调用l束...
Ҏ调用l束...
目标Ҏ的返回值是 : null
目标Ҏ?: public abstract void lee.Person.run()
目标Ҏ的参数是 : null
目标对象?: lee.PersonImpl@b23210
E序的执行结果中一?#8220;=”用于区分两次调用的方法。在调用infoҎӞ只有myAdvice和myAroundInterceptor两个拦截器v作用Q调用runҎ时候,三个拦截器都起作用了?br />
通过上面的介l,可看出Spring的AOP框架是对代理模式化,q拓展了代理模式的用?br />
Spring AOP是Spring声明式事务的基础。了解Spring AOPҎ入理解Spring的声明式事务理是非常有好处的。Spring AOPq可以完成很多功能,例如ZAOP的权限检查?/p>