SpringAOP创建增强类

编程

   

 1)前置增强:org.springframework.aop.BeforeAdvice 代表前置增强,因为Spring 只支持方法级的增强,所有MethodBeforeAdvice是目前可用的前置增强,表示在目标方法执行前实施增强,而BeforeAdvice是为了将来版本扩展需要而定义的;

   

 2)后置增强:org.springframework.aop.AfterReturningAdvice 代表后增强,表示在目标方法执行后实施增强;

  

  3)环绕增强:org.aopalliance.intercept.MethodInterceptor 代表环绕增强,表示在目标方法执行前后实施增强;

    

4)异常抛出增强:org.springframework.aop.ThrowsAdvice 代表抛出异常增强,表示在目标方法抛出异常后实施增强;

    

5)引介增强:org.springframework.aop.IntroductionInterceptor 代表引介增强,表示在目标类中添加一些新的方法和属性。

 

1、前置增强

    模拟服务员向顾客表示欢迎和对顾客提供服务。

Waiter接口:

package com.yyq.advice;

publicinterface Waiter {

void greetTo(String name);

void serveTo(String name);

}

NaiveWaiter服务类:

package com.yyq.advice;

publicclass NaiveWaiter implements Waiter {

@Override

publicvoid greetTo(String name) {

System.out.println("greet to " + name + "...");

}

@Override

publicvoid serveTo(String name) {

System.out.println("serving to " + name + "...");

}

}

前置增强实现类:

package com.yyq.advice;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

publicclass GreetingBeforeAdvice implements MethodBeforeAdvice {

@Override

publicvoid before(Method method, Object[] objects, Object o) throws Throwable {

String clientName = (String) objects[0];

System.out.println("How are you ! Mr." + clientName + ".");

}

}

测试方法:

@Test

publicvoid testBeforeAdvice(){

Waiter target = new NaiveWaiter();

BeforeAdvice advice = new GreetingBeforeAdvice();

ProxyFactory pf = new ProxyFactory(); //Spring提供的代理工厂

pf.setTarget(target); //设置代理目标

pf.addAdvice(advice);

Waiter proxy = (Waiter)pf.getProxy(); //生成代理实例

proxy.greetTo("John");

proxy.serveTo("Tom");

}

输出结果:

How are you ! Mr.John.

greet to John...

How are you ! Mr.Tom.

serving to Tom...

 

在Spring中配置:beans.xml

<bean id="greetingAdvice" class="com.yyq.advice.GreetingBeforeAdvice"/>

<bean id="target" class="com.yyq.advice.NaiveWaiter"/>

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

p:proxyInterfaces="com.yyq.advice.Waiter"

p:interceptorNames="greetingAdvice"

p:target-ref="target"/>

  ProxyFactoryBean 是FactoryBean接口的实现类。

    · target:代理的目标对象;

    · proxyInterfaces:代理所实现的接口,可以是多个接口。该属性还有一个别名属性interfaces;

    · interceptorNames:需要织入目标对象的Bean列表,采用Bean的名称指定。这些Bean必须是实现了org.aopalliance.intercept.Method 或 org.springframework.aop.Advisor的Bean,配置中的顺序对应调用的顺序;

    · singleton:返回的代理是否是单实例,默认为单实例;

    · optimize:当设置为true时,强制使用CGLib代理。对于singleton的代理,我们推荐使用CGLib,对于其他作用域类型的代理,最好使用JDK代理。原因是CGLib创建代理时速度慢,而创建出的代理对象运行效率较高,而使用JDK代理的表现正好相反;

    · proxyTargetClass:是否对类进行代理(而不是对接口进行代理),设置为true时,使用CGLib代理。

测试方法:

@Test

publicvoid testBeforeAdvice2(){

String configPath = "com\yyq\advice\beans.xml";

ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath);

Waiter waiter = (Waiter)ctx.getBean("waiter1");

waiter.greetTo("Joe");

}

输出结果:

How are you ! Mr.Joe.

greet to Joe...

 

2、后置增强

    后置增强在目标类方法调用后执行。模拟服务员在每次服务后使用礼貌用语。

GreetingAfterAdvice后置增强实现类:

package com.yyq.advice;

import org.springframework.aop.AfterReturningAdvice;

import java.lang.reflect.Method;

publicclass GreetingAfterAdvice implements AfterReturningAdvice {

@Override

publicvoid afterReturning(Object o, Method method, Object[] objects, Object o2) throws Throwable {

System.out.println("Please enjoy yourself.");

}

}

 在beans.xml文件添加后置增强:

<bean id="greetingBefore" class="com.yyq.advice.GreetingBeforeAdvice"/>

<bean id="greetingAfter" class="com.yyq.advice.GreetingAfterAdvice"/>

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

p:proxyInterfaces="com.yyq.advice.Waiter"

p:interceptorNames="greetingBefore,greetingAfter"

p:target-ref="target"/>

测试方法:

 @Test

publicvoid testBeforeAndAfterAdvice(){

String configPath = "com\yyq\advice\beans.xml";

ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath);

Waiter waiter = (Waiter)ctx.getBean("waiter2");

waiter.greetTo("Joe");

}

结果输出:

How are you ! Mr.Joe.

greet to Joe...

Please enjoy yourself.

 

3、环绕增强

    环绕增强允许在目标类方法调用前后织入横切逻辑,它综合实现了前置、后置增强两者的功能。

GreetingInterceptor环绕增强实现类:

package com.yyq.advice;

import org.aopalliance.intercept.MethodInterceptor;

import org.aopalliance.intercept.MethodInvocation;

publicclass GreetingInterceptor implements MethodInterceptor {

@Override

public Object invoke(MethodInvocation methodInvocation) throws Throwable {

Object[] args = methodInvocation.getArguments();

String clientName = (String) args[0];

System.out.println("Hi,Mr " + clientName + ".");

Object obj = methodInvocation.proceed();

System.out.println("Please enjoy yourself~");

return obj;

}

}

   Spring 直接使用AOP联盟所定义的MethodInterceptor作为环绕增强的接口。该接口拥有唯一的接口方法 Object invoke(MethodInvocation invocation), MethodInvocation不但封装目标方法及其入参数组,还封装了目标方法所在的实例对象,通过MethodInvocation的getArguments()可以获取目标方法的入参数组,通过proceed()反射调用目标实例相应的方法。

在beans.xml文件添加环绕增强:

<bean id="greetingAround" class="com.yyq.advice.GreetingInterceptor"/>

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

p:proxyInterfaces="com.yyq.advice.Waiter"

p:interceptorNames="greetingAround"

p:target-ref="target"/>

测试方法:

  @Test

publicvoid testAroundAdvice(){

String configPath = "com\yyq\advice\beans.xml";

ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath);

Waiter waiter = (Waiter)ctx.getBean("waiter3");

waiter.greetTo("Joe");

}

结果输出:

Hi,Mr Joe.

greet to Joe...

Please enjoy yourself~

 

4、异常抛出增强

    异常抛出增强最适合的应用场景是事务管理,当参与事务的某个Dao发送异常时,事务管理器就必须回滚事务。

Forum业务类:

package com.yyq.advice;

publicclass Forum {

privateint forumId;

publicint getForumId() {

return forumId;

}

publicvoid setForumId(int forumId) {

this.forumId = forumId;

}

}

 ForumService业务类:

package com.yyq.advice;

import java.sql.SQLException;

publicclass ForumService {

publicvoid removeForum(int forumId){

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

thrownew RuntimeException("运行异常");

}

publicvoid updateForum(Forum forum)throws Exception{

System.out.println("updateForum");

thrownew SQLException("数据更新操作异常。");

}

}

TransactionManager异常抛出增强实现类:

package com.yyq.advice;

import org.springframework.aop.ThrowsAdvice;

import java.lang.reflect.Method;

publicclass TransactionManager implements ThrowsAdvice {

publicvoid afterThrowing(Method method, Object[] args, Object target, Exception ex) throws Throwable {

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

System.out.println("method:" + method.getName());

System.out.println("抛出异常:" + ex.getMessage());

System.out.println("成功回滚事务。");

}

}

    ThrowAdvice异常抛出增强接口没有定义任何方法,它是一个标识接口,在运行期Spring使用反射的机制自行判断,我们采用以下签名形式定义异常抛出的增强方法:void afterThrowing(Mehod method, Object[] args, Object target, Throwable);方法名必须为afterThrowing,方法入参规定,前三个参数是可选的,要么三个入参提供,要么不提供,最后一个入参是Throwable或者子类。

在beans.xml文件添加异常抛出增强:

<bean id="transactionManager" class="com.yyq.advice.TransactionManager"/>

<bean id="forumServiceTarget" class="com.yyq.advice.ForumService"/>

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

p:interceptorNames="transactionManager"

p:target-ref="forumServiceTarget"

p:proxyTargetClass="true"/>

 测试方法:

@Test

publicvoid testThrowsAdvice(){

String configPath = "com\yyq\advice\beans.xml";

ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath);

ForumService fs = (ForumService)ctx.getBean("forumService");

try{

fs.removeForum(10);

} catch (Exception e) {}

try{

fs.updateForum(new Forum());

} catch (Exception e) {}

}

结果输出:

----------------

method:removeForum

抛出异常:运行异常

成功回滚事务。

updateForum

----------------

method:updateForum

抛出异常:数据更新操作异常。

成功回滚事务。

 

5、引介增强

        引介增强为目标类创建新的方法和属性,所以引介增强的连接点是类级别的,而非方法级别的。通过引介增强,我们可以为目标类添加一个接口的实现,即原来目标类未实现某个接口,通过引介增强可以为目标类创建实现某个接口的代理。Spring定义了引介增强接口IntroductionInterceptor,该接口没有定义任何的方法,Spring为该接口提供了DelegatingIntroductionInterceptor实现类。

Monitorable:用于标识目标类是否支持性能监视的接口

package com.yyq.advice;

publicinterface Monitorable {

void setMonitorActive(boolean active);

}

 ControllablePerformanceMonitor 为引介增强实现类:

package com.yyq.advice;

import org.aopalliance.intercept.MethodInvocation;

import org.springframework.aop.support.DelegatingIntroductionInterceptor;

publicclass ControllablePerformanceMonitor extends DelegatingIntroductionInterceptor implements Monitorable {

private ThreadLocal<Boolean> MonitorStatusMap = new ThreadLocal<Boolean>();

@Override

publicvoid setMonitorActive(boolean active) {

MonitorStatusMap.set(active);

}

public Object invoke(MethodInvocation mi) throws Throwable {

Object obj = null;

if (MonitorStatusMap.get() != null && MonitorStatusMap.get()) {

PerformanceMonitor.begin(mi.getClass().getName() + "." + mi.getMethod().getName());

obj = super.invoke(mi);

PerformanceMonitor.end();

} else {

obj = super.invoke(mi);

}

return obj;

}

}

PerformanceMonitor监视类:

package com.yyq.advice;

publicclass PerformanceMonitor {

privatestatic ThreadLocal<MethodPerformance> performanceRecord = new ThreadLocal<MethodPerformance>();

publicstaticvoid begin(String method) {

System.out.println("begin monitor...");

MethodPerformance mp = new MethodPerformance(method);

performanceRecord.set(mp);

}

publicstaticvoid end(){

System.out.println("end monitor...");

MethodPerformance mp = performanceRecord.get();

mp.printPerformance();

}

}

MethodPerformance记录性能信息:

publicclass MethodPerformance {

privatelong begin;

privatelong end;

private String serviceMethod;

public MethodPerformance(String serviceMethod){

this.serviceMethod = serviceMethod;

this.begin = System.currentTimeMillis();

}

publicvoid printPerformance(){

end = System.currentTimeMillis();

long elapse = end - begin;

System.out.println(serviceMethod + "花费" + elapse + "毫秒。");

}

}

在beans.xml文件添加引介增强:

<bean id="pmonitor" class="com.yyq.advice.ControllablePerformanceMonitor"/>

<bean id="forumServiceImplTarget" class="com.yyq.advice.ForumServiceImpl"/>

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

p:interfaces="com.yyq.advice.Monitorable"

p:interceptorNames="pmonitor"

p:target-ref="forumServiceImplTarget"

p:proxyTargetClass="true"/>

 

测试方法:

@Test

publicvoid testIntroduce(){

String configPath = "com\yyq\advice\beans.xml";

ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath);

ForumServiceImpl forumServiceImpl = (ForumServiceImpl)ctx.getBean("forumService2");

forumServiceImpl.removeForum(23);

forumServiceImpl.removeTopic(1023);

Monitorable monitorable = (Monitorable)forumServiceImpl;

monitorable.setMonitorActive(true);

forumServiceImpl.removeForum(22);

forumServiceImpl.removeTopic(1023);

}

结果输出:

模拟删除Forum记录:23

模拟删除Topic记录:1023

begin monitor...

模拟删除Forum记录:22

end monitor...

org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.removeForum花费40毫秒。

begin monitor...

模拟删除Topic记录:1023

end monitor...

org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.removeTopic花费21毫秒。

 

以上是 SpringAOP创建增强类 的全部内容, 来源链接: utcz.com/z/513022.html

回到顶部