spring学习笔记(五)

Advice详解

         前面提到了,一个切面由一个PointCut和一个Advice组成,Advice主要包含了横切代码以及,织入位置的部分信息(即织入PointCut给定方法的方法的前面、后面、前面和后面、异常抛出时、添加一些新的方法和属性)。java

         针对上面的位置信息,Spring提供了5种对应的子接口:前置加强、后置加强、环绕加强、异常抛出加强、引介加强。spring

(1)       前置加强:

        Spring提供了org.springframework.aop.BeforeAdvice接口,可是由于Spring如今只支持方法级别的加强,因此MethodBeforeAdvice是当前可用的前置加强,表示在目标方法执行前实施加强,估计之后还会有其余的前置加强,敬请期待。数组

例子:学习

Person.java

public interface Person {
    public void sleep() ;
}

下面是一个懒人的睡觉方式测试

LazyPerson.java

public class LazyPerson implements Person {
    public void sleep() {
        System.out.println("I am sleeping.....ZZZZ");
    }
}

咱们但愿在睡觉前先完成洗漱,下面使用Advice使其睡觉前先洗漱spa

GreetingBeforeAdvice.java
public class GreetingBeforeAdvice implements MethodBeforeAdvice {
    public void before(Method method, Object[] args, Object obj) throws Throwable {
        System.out.println("I am washing face.....");
    }
}

实现MethodBeforeAdvice接口,实现before方法,这个方法中的代码就是横切代码,参数分别是PointCut提供的目标方法对象(没有PointCut提供默认为类中的全部方法将遍历入参)、方法在调用时传入的参数数组、目标类对象。代理

当该方法发生异常时,将阻止目标类执行code

下面使用Spring提供的ProxyFactory和测试类来验证效果orm

BeforeAdviceTest.java

public class BeforeAdviceTest {
    private Person target;
    private BeforeAdvie advice;
    private ProxyFactory pf;
    
    @BeforeTest
    public void init() {
        target = new LazyPerson();
        advice = new GreetingBeforeAdvice();
        pf = new ProxyFactory();
        pf.setTarget(target);
        pf.addAdvice(advice);
    }
    
    @Test
    public void beforeAdvice() {
        Person proxy = (Person)pf.getProxy;
        proxy.sleep();    
    }
}

运行上面代码,将输出xml

I am washing face.....
I am sleeping.....ZZZZ

        看到这里可能有读者会说了,只是加一句简单的控制台打印代码有必要写的这么复杂吗?因此这里声明一下,上面的例子并非很形象,若是只是像上面同样加一些简单代码彻底能够单独提出一个方法,这个例子只是为了展现Advice的用法,同时这里也突出了一个问题,咱们能够发现并非任什么时候候使用Spring Aop都是好的,他也会增长咱们代码的复杂度,因此用的时候请想清楚使用Aop是否合适。还有这里的例子代码都没有通过真实的运行测试,但愿学习的朋友请本身动手写下代码,有问题能够提出来讨论,下面的例子也有相同问题,请勿怪。

        Spring配置文件中使用代理:

<bean id="advice" class="GreetingBeforeAdvice"/>
<bean id="target" class="LazyPerson"/>
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean"
    p:proxyInterfaces="person"
    p:interceptorNames="advice"
    p:target-ref="target"/>

ProxyFactoryBean负责为其余Bean建立代理实例,内部使用ProxyFactory完成这个工做,ProxyFactoryBean的可配置属性以下:

  • target:代理的目标对象

  • proxyInterfaces:代理所要实现的接口,能够为多借口

  • interceptorNames:须要织入目标对象的Bean列表,采用Bean的名称指定,这些Bean必须实现MethodInterceptor或Advisor,配置顺序对应调用顺序

  • singleton:返回对象是否为单例,默认是

  • optimize:当为true,强制使用CGLIB代理,对应单例推荐使用CGLIB代理,其余用JDK代理,由于CGLIB代理建立慢,但建立出的代理对象运行效率快,JDK相反

  • proxyTargetClass:是否使用类代理(不使用接口代理),true时使用CGLIB代理

(2)       后置加强

    Spring提供了org.springframework.aop.AfterReturningAdvice目标方法执行后实施加强

        实现AfterReturningAdvice接口,实现afterReturning(Object returnObj, Method method, Object[] args, Object obj) throws Throwable方法,returnObj是方法返回结果,其余与前置加强同样。

        还有一点与前置加强区别,当发生异常时,若是异常是目标方法声明的异常,异常将归并到目标方法,不然将异常转换成运行期异常抛出。

        因为后置加强与前置用法相识,这里就不写例子了

(3)    环绕加强

        Spring提供org.aoplliance.intercept.MethodInterceptor目标方法执行先后实施加强

        

GreetingInterceptor.java

public class GreetingInterceptor implements MethodInterceptor {
    //实现如下方法
    public Object invoke(MethodInvocation invocation) throws Throwable {
        Object[] args = invocation.getArguments();//目标方法入参
        //TO-DO 目标方法执行前须要执行的代码
        Object obj = invocation.proceed();//反射调用目标方法
        //TO-DO 目标方法执行后须要执行的代码
        return obj;        
    }
}

(4)    异常抛出加强

        Spring提供了org.springframework.aop.ThrowsAdvice表示在目标方法抛出异常后实施加强

        异常抛出加强最适合是事物的回滚操做,在ThrowsAdvice接口中并无定义任何的抽象方法,他只是一个标识接口,在运行期间Spring会经过反射识别。可是加强方法必须使用void afterThrowing([Method method, Object[] args, Object target], Throwable)这种格式的方法签名。

(5)    引介加强

        Spring提供了org.springframework.aop.IntroductionInterceptor,表示在目标方法中添加一些新的方法和属性,并不经常使用,因此这里不介绍了,感兴趣能够本身查找资料

相关文章
相关标签/搜索