Spring入门(AOP API、ProxyFactoryBean其一)

来源:互联网 发布:八千湘女嫁新疆知乎 编辑:程序博客网 时间:2024/05/19 00:07

介绍

这是Spring1.2历史用法,现在(V4.0)仍然支持
这是SpringAOP基础,不得不了解
现在的用法也是基于历史的,只是更简便了

Pointcut

Pointcut作为一个接口,它有几个实现类,这里以其中一个来介绍,他就是NameMatchMethodPointcut。它根据方法名字进行匹配。
它有一个成员变量mappedNames,匹配的方法名集合。
来看一下下面这个配置文件的例子:

<bean id="pointcutBean" class="org.springframework.aop.support.NameMatchMethodPointcut">    <property name="mappedNames">        <list>            <value>sa*</value>        </list>    </property></bean>

定义一个bean,class就是刚才提到的。property是里边的属性,里边用一个list,list表示当前这个属性是一个集合,list里边就是value,这里写了一个,也可以写多个,这里的意思是sa开头的所有方法。

然后看一个例子。
首先是配置文件:

<?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:context="http://www.springframework.org/schema/context"    xmlns:aop="http://www.springframework.org/schema/aop"    xsi:schemaLocation="http://www.springframework.org/schema/beans         http://www.springframework.org/schema/beans/spring-beans.xsd          http://www.springframework.org/schema/context        http://www.springframework.org/schema/context/spring-context.xsd        http://www.springframework.org/schema/aop         http://www.springframework.org/schema/aop/spring-aop.xsd">    <bean id="bizLogicImplTarget" class="com.imooc.aop.api.BizLogicImpl"></bean>    <bean id="pointcutBean" class="org.springframework.aop.support.NameMatchMethodPointcut">        <property name="mappedNames">            <list>                <value>sa*</value>            </list>        </property>    </bean></beans>

这里看到有一个bean,class为BizLogicImpl。另一个bean是定义好了一个切入点。
首先我们有一个BizLogic接口:

public interface BizLogic {    String save();}

然后是它的一个实现类

public class BizLogicImpl implements BizLogic {    public String save() {        System.out.println("BizLogicImpl : BizLogicImpl save.");        return "BizLogicImpl save.";//      throw new RuntimeException();    }}

xml文件中配置了这个bean,并且id是bizLogicImplTarget,至于为什么是Target,后边的例子里会有说明。

Before Advice

一个简单的通知类型
只是在进入方法之前被调用,不需要MethodInvocation对象(和基于配置中讲到的是差不多的)
前置通知可以在连接点执行之前插入自定义行为,但不能改变返回值

接着刚才的例子,我们新建一个类MoocBeforeAdvice类实现MethodBeforeAdvice接口,里边输出内容即自定义行为:

public class MoocBeforeAdvice implements MethodBeforeAdvice {    @Override    public void before(Method method, Object[] args, Object target)            throws Throwable {        System.out.println("MoocBeforeAdvice : " + method.getName() + "     " +                  target.getClass().getName());    }}

这样一个前置通知就定义好了。暂时不去单元测试类执行它,因为执行它需要用到后边讲到的内容。

Throw advice

如果连接点抛出异常,throws advice在连接点返回后被调用
如果throws-advice的方法抛出异常,那么它将覆盖原有异常
接口org.springframework.aop.ThrowsAdvice不包含任何方法,仅仅是一个声明,实现类需要实现类似下面的方法:
void afterThrowing([Method,args,target],ThrowableSubclass);

我们来看一下它的说明
这里写图片描述
这是几种形式,有一个特点就是异常是必须有的,前边的内容可有可无。然后图中代码的例子就是这样。

继续刚才的例子,在代码中定义一个类MoocThrowsAdvice实现接口ThrowsAdvice

public class MoocThrowsAdvice implements ThrowsAdvice {    public void afterThrowing(Exception ex) throws Throwable {        System.out.println("MoocThrowsAdvice afterThrowing 1");    }    public void afterThrowing(Method method, Object[] args, Object target, Exception ex) throws Throwable {        System.out.println("MoocThrowsAdvice afterThrowing 2 : " + method.getName() + "       " +                 target.getClass().getName());    }}

只是完成了定义,具体使用依赖后边的内容。

After Returning advice

后置通知必须实现org.springframework.aop.AfterReturningAdvice接口
可以访问返回值(但不能进行修改)、被调用的方法、方法的参数和目标
如果抛出异常,将会抛出拦截器链,替代返回值

继续刚才的例子,我们自己定义一个类MoocAfterReturningAdvice继承AfterReturningAdvice接口:

public class MoocAfterReturningAdvice implements AfterReturningAdvice {    @Override    public void afterReturning(Object returnValue, Method method,            Object[] args, Object target) throws Throwable {        System.out.println("MoocAfterReturningAdvice : " + method.getName() + "     " +             target.getClass().getName() + "       " + returnValue);    }}

Interception around advice

Spring的切入点模型使得切入点可以独立与advice重用,以针对不同的advice可以使用相同的切入点。这个和之前基于xml配置文件的AOP实现方式类似,切入点可以在外面单独配置,每一个advice都可以使用相同的切入点。

定义一个类MoocMethodInterceptor继承MethodInterceptor接口:

public class MoocMethodInterceptor implements MethodInterceptor {    @Override    public Object invoke(MethodInvocation invocation) throws Throwable {        System.out.println("MoocMethodInterceptor 1 : " + invocation.getMethod().getName() + "     " +                 invocation.getStaticPart().getClass().getName());         Object obj = invocation.proceed();         System.out.println("MoocMethodInterceptor 2 : " + obj);         return obj;    }}

返回的是invocation的proceed方法的返回值。在方法执勤啊和之后都进行输出,我们可以通过invication可以得到method,进一步得到方法的名称。

Introduct advice

和在xml配置中实现的Introduction advice中实现的是一样的
Spring把引入通知作为一种特殊的拦截通知
需要IntroductionAdvisor和IntroductionInterceptor两个接口
仅适用于类,不能和任何切入点一起使用
然后来看一下这两个接口的内容:
这里写图片描述
IntroductionInterceptor里边有一个implementsInterface,就像我们在前边的配置中配置的那样,使它实现了哪个接口。还有IntroductionAdvisor里的内容。这些都对应了我们基于xml配置的SpringAOP实现里的一些内容。

然后看一下一个Introduction advice的小例子。这个例子实在Spring test suit里边提供的一个例子。用法:
如果调用lock()方法,希望所有的setter方法抛出LockedException异常(如使物体不可变,这是AOP典型例子)
需要一个完成繁重任务的IntroductionInterceptor,这种情况下,可以使用org.springframework.aop.support.DelegatingIntroductionInterceptor,而不是去实现这个接口

public interface Lockable{    void lock();    void unlock();    boolean locked();}

来看一下代码
接口

public interface Lockable {    void lock();    void unlock();    boolean locked();}

实现类

public class LockMixin extends DelegatingIntroductionInterceptor implements Lockable {    private static final long serialVersionUID = 6943163819932660450L;    private boolean locked;    public void lock() {        this.locked = true;    }    public void unlock() {        this.locked = false;    }    public boolean locked() {        return this.locked;    }    public Object invoke(MethodInvocation invocation) throws Throwable {        if (locked() && invocation.getMethod().getName().indexOf("set") == 0) {            throw new RuntimeException();        }        return super.invoke(invocation);    }}

invoke方法里的意思是,如果当前是被锁住,并且方法的名称中包含set,那么不希望执行set方法去改变物体的属性。如果符合这样的内容就抛出一个异常,否则正常执行。
里边做了一点修改,返回的是RuntimeException,而不是LockedException

introduction advisor比较简单,持有独立的LockMixin实例:

public class LockMixinAdvisor extends DefaultIntroductionAdvisor {    private static final long serialVersionUID = -171332350782163120L;    public LockMixinAdvisor() {        super(new LockMixin(), Lockable.class);    }}

这里实现的是spring提供的用来简化操作的DefaultIntroductionAdvisor 类。

Advisor API in Spring

Advisor是仅包含一个切入点表达式关联的单个通知的方面
除了introductions,advisors可以用于任何通知
org.springframework,aop.support.DefaultPointcutAdvisor是最常用的advisor类,它可以与MethodInterceptor,BeforeAdvice或者ThrowsAdvice一起使用
它可以混合在Spring同一个AOP代理的advisor和advice

阅读全文
0 0
原创粉丝点击