Spring入门(AOP API、ProxyFactoryBean其一)

介绍

这是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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值