Spring-AOP:增强类型和相关实现


在上篇文章详细介绍了AOP的思想以及相关的术语 《Spring AOP原理》并写了一个前置增强的示例代码,本篇文章继续把其他类型的增强实现码出来,希望对家有所帮助。

后置增强:

1.目标类:

public class Waiter {

    public void greetTo(String name) {
        System.out.println("waiter greet to " + name + "...");
    }

    public void serveTo(String name) {
        System.out.println("waiter serving " + name + "...");
    }
}

2.后置增强:实现 org.springframework.aop.AfterReturningAdvice

public class GreetAterAdvice implements AfterReturningAdvice {
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println("Please enjoy yourself!");
    }
}

3.测试:

public class AfterAdviceTest {

    private Waiter target;
    private AfterAdvice advice;
    private ProxyFactory pf;

    @BeforeTest
    public void init() {
        target = new Waiter();
        advice = new GreetAterAdvice();
        //①Spring提供的代理工厂
        pf = new ProxyFactory();
        // ②设置代理目标
        pf.setTarget(target);
        //③为代理目标添加增强
        pf.addAdvice(advice);
    }

    @Test
    public void beforeAdvice() {
        Waiter proxy = (Waiter) pf.getProxy();
        proxy.greetTo("John");
        proxy.serveTo("Tom");
    }
}

打印结果:

waiter greet to John...
Please enjoy yourself! //该行是后置增强植入的逻辑
waiter serving Tom...
Please enjoy yourself! //该行是后置增强植入的逻辑

这样就在方法执行之后,织入了增强逻辑。如果想同时织入前置增强和后置增强,可以同时添加多个增强,如下,(或者一个增强类同时实现多个增强接口)

 //③为代理目标添加增强
 pf.addAdvice(advice);
 pf.addAdvice(beforeAdvice);

当然也可以采用Spring提供的环绕增强,也可以达到相同的目的。

环绕增强:

环绕增强需要实现:rg.aopalliance.intercept.MethodInterceptor

实现方法和前面提到的后置增强有所不同:

public class GreetInterceptor implements MethodInterceptor {

    public Object invoke(MethodInvocation invocation) throws Throwable {
        Object[] args = invocation.getArguments();
        String clientName = (String) args[0];
        //在目标方法执行前调用
        System.out.println("How are you!Mr." + clientName + ".");
		//通过反射调用目标方法
        Object obj = invocation.proceed();
		//在目标方法执行后调用
        System.out.println("Please enjoy yourself!");

        return obj;
    }
}

最终效果和上面同时引入前置增强和后置增强的效果一致。

异常抛出增强:

该增强最适合的场景是事务管理,当参与事务的Dao发生异常,事务管理器就必须回滚事务。

1.目标类:

在模拟业务类ViewSpaceService中定义了两个业务方法,deleteViewSpace ()抛出运行期异常,而updateViewSpace ()抛出SQLException。

public class ViewSpaceService {

    public boolean deleteViewSpace(int spaceId) {

        throw new RuntimeException("运行异常。");
    }

    public void updateViewSpace(ViewSpace viewSpace) throws Exception {
        // do sth...
        throw new SQLException("数据更新操作异常。");

    }
}

2.抛出异常增强:

public class TransactionManager implements ThrowsAdvice {
    
    public void afterThrowing(Method method, Object[] args, Object target,
                              Exception ex) throws Throwable {
        ex = null;
        System.out.println("-----------");
        System.out.println("method:" + method.getName());
        //System.out.println("抛出异常:" + ex.getMessage());
        System.out.println("成功回滚事务。");
    }


ThrowsAdvice异常抛出增强接口没有定义任何方法,它是一个标识接口,在运行期Spring使用反射的机制自行判断,必须采用以下签名形式定义异常抛出的增强方法。

void afterThrowing([Method method, Object[] args, Object target], Throwable);

方法名必须为afterThrowing,方法入参规定如下:前3个入参Method method, Object[] args, Object target是可选的(要么提供3个入参,要么不提供),而最后一个入参是Throwable或其子类。

下面几种都是合法的:

· afterThrowing(SQLException e);
· afterThrowing(RuntimeException e);
· afterThrowing(Method method, Object[] args, Object target,RuntimeException e)

可以在同一个异常抛出增强中定义多个afterThrowing(),当目标类方法,抛出异常时,Spring会自动选用最匹配的增强方法。

引介增强:

引介增强,不太常用,这里暂不讨论。

基于XML配置的增强实现:

前面我们在织入 增强时,通过代码进行装配 :

advice = new GreetInterceptor();
        //①Spring提供的代理工厂
        pf = new ProxyFactory();
        // ②设置代理目标
        pf.setTarget(target);
        //③为代理目标添加增强
        pf.addAdvice(advice);

开发中很多时候是基于配置文件进行组织(当然,到SpringBoot就另当别论,当原理都是一样)

下面我们用xml配置实现抛出异常增强的配置:

1.增强类编写(和前面一致)

TransactionManager

2.xml配置:

将目标对象和增强类,通过bean标签配置。

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 		      		xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
     http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">

    <!--
	<bean id="greetingBefore" class="com.smart.advice.GreetingBeforeAdvice" />
	<bean id="greetingAfter" class="com.smart.advice.GreetingAfterAdvice" />
	<bean id="greetingAdvice" class="com.smart.advice.GreetingBeforeAdvice" />
	<bean id="greetingAround" class="com.smart.advice.GreetingInterceptor" />
	<bean id="target" class="com.smart.advice.NaiveWaiter" />
	-->


	



	<!--4. 异常抛出增强 -->
	<bean id="viewSpaceServiceTarget" class="com.smart.advice.ViewSpaceService" />
	<bean id="transactionManager" class="com.smart.advice.TransactionManager" />
	<bean id="viewSpaceService" class="org.springframework.aop.framework.ProxyFactoryBean"
	  p:interceptorNames="transactionManager"
	  p:target-ref="viewSpaceServiceTarget"
	  p:proxyTargetClass="true"/>

</beans>

说明:p:interceptorNames 指明要织入的增强类id,关联上面的配置。

​ p:target-ref指明目标对象

​ p:proxyTargetClass指明要使用CGLib代理。因为ViewSpace是一个类。(如果不指定,也会默认使用)

总结:

我们介绍了几种增强的简单示例,但是我们注意到一个问题,增强,被织入到了类中的所有方法。如果我们希望有选择的织入目标类的某些特定方法,就需要使用切点进行目标连接点的定位。这就涉及到切点和切面相关的内容。最近更新,码字不易,路过点个赞。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值