Spring AOP随笔(一)

一,概念

首先有几个AOP术语,在这里陈述一下。
1. 连接点(joinpoint)
程序执行的某一个特定位置,如类初始化前,初始化后,类的某个方法调用前和调用后,方法抛出异常后,一个类或者一段代码拥有一些具有边界性质的特定点,这些代码中的特定点就是“连接点”。spring仅支持方法的连接点,即仅能在方法调用前,方法调用后,方法抛出异常时以及方法调用前后这些程序执行点的织入增强,有一个形象的比如可以让我们清晰的描述这个概念,AOP就像一个黑客,它攻击别人要找到突破点,连接点就想黑客找到入侵的突破点一样,怎么样,是不是很形象。

2.切点(pointcut)
每一个程序有多个连接点,如一个类拥有两个方法,这两个方法都是连接点,即连接点是程序类客观存在的事务,但在众多的连接点中,如何定位到一个连接点感兴趣的连接点呢?AOP通过“切点”来定位特定的连接点,再用一个例子来说明,可以通过数据库的查询概念来类比这个概念,连接点相当于数据库中的记录,而切点 相当于查询条件,切点和连接点不是一一对应的关系,一个切点可以匹配多个连接点。确切的说,切点是定位到某个方法上的,所以如果希望定位到具体连接点上,还你需要提供方位信息。

3.增强(Advice)
增强是织入目标类连接点上的一段程序代码,因为增强既包含了用于添加到目标连接点上的一段执行逻辑代码,又包含了用于定位连接点的方位信息,所以spring多提供的增强都是带有方位名的:BeforeAdvice,AfterReturningAdvice,ThrowsAdvice等,所以增强只有结合切点才能确定特定的连接点并实施增强逻辑。

4.目标对象(target)
这个简单易懂,见名知意,即增强逻辑的织入目标类。

5.引介(introduction)
引入是一种特殊的增强,它为类添加了一些属性和方法,即如果原本一个业务类没有实现某个接口,通过AOP的引介功能,也可以动态的为该业务类添加接口的实现逻辑,让业务类成为这个接口的实现类。

6.织入(Weaving)
织入是将增强添加到目标类具体连接点上的过程,AOP像一台织布机,将目标类和增强或者引介通过aop这台织布机天衣无缝的编织到一起,Aop有三种织入方式:

  • 编译器织入,这要求使用特殊的java编译器
  • 类装载期织入,这要求使用特殊的类装载器
  • 动态代理织入,在运行期间为目标类添加增强生成子类的方式。

7.代理(proxy)
一个类被织入增强后,就产出了一个结果类,它是融合了原类和增强逻辑的代理类,根据不用的代理方式,代理 类既可以与原类具有相同接口的类,也可以是原类的子类,所有可以采用与调用原类相同的方式调用代理类。

8.切面(Aspect)
切面由切点和增强(引介)组成,它既包含了横切逻辑,有包含了连接点的定义,spring aop就是负责切面的框架,它将切面所定义的横切逻辑织入切面所指定的连接点中。

二,创建增强类

在介绍完上面的一些概念后,我们来具体的介绍一下增强的类型,并且通过一些例子来实践。
1.增强类型:

  • 前置增强:表示在目标方法执行前增强。org.aopalliance.aop.BeforeAdvice类代表前置增强。因为spring中只支持方法级的增强,所以MethodBeforeAdvice是当前可用的前置增强,表示在目标方法执行前实施增强。
  • 后置增强:org.aopalliance.aop.AfterRetruningAdvice代表后置增强,表示目标方法执行后实施增强。
  • 环绕增强:org.aopalliance.aop.MethodInteceptor代表环绕增强,表示在目标方法执行前后实施增强。
  • 异常抛出增强:org.aopalliance.aop.ThrowsAdvice代表抛出异常增强,表示在目标方法抛出异常后实施增强。
  • 引介增强:org.aopalliance.aop.IntroductionInterceptor代表引介增强,表示在目标类中添加一些新的方法和属性。

2.前置增强
首先我们来通过一个实例来看一下前置增强
比如我进一个饭馆吃饭的时候,服务生都很礼貌,现在我们用通过前置增强对服务生服务用语进行强制规范。假设服务生在你进门时欢迎顾客,然后对顾客提供服务。
下面是一个服务生的接口


public interface Writer {
    public void greeTo(String name);
    public void serverTo(String name);
}

然后我们再看一个训练不足的服务生的欢迎 顾客的方式

public class WriterImpl implements Writer{

    @Override
    public void greeTo(String name) {
        System.out.println("gree to "+name);
    }

    @Override
    public void serverTo(String name) {
        System.out.println("server to "+name);
    }
}

上面这个服务生只是闷不做声的简单向客户打招呼,这样并不是我们想要的,我们要的是一个热情好客的服务生。来让我们来规范这个服务生类。在他对客户服务时,必须先对客户使用礼貌用语:

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;
/**
 * 增加既包含了用于添加到目标连接点上的一段执行逻辑,又包含了用于定位连接点的方位信息,所以
 * spring所提供的接口都是带有方位名的BeforeAdvice,AfterReturningAdvice,ThrowsAdvice
 * BeforeAdvice是方法调用前的位置,AfterReturningAdvice表示访问返回后的位置,所以只有
 * 结合切点和增强才能确实特定的连接点并且实施增强逻辑
 * @author Shinelon
 *
 */
public class GreetingBeforeAdvice implements MethodBeforeAdvice{
    /**
     * 第一个参数Method 是指目标方法
     * 第二个参数是指目标方法的入参
     * 第三个参数是指目标类的实例
     */
    @Override
    public void before(Method method, Object[] arg, Object obj)
            throws Throwable {
        String clientname=(String)arg[0];
        System.out.println("How are you "+clientname);
    }
}

怎么样。通过我们的调教(增强)。这个服务生是不是礼貌多了,这样也易与顾客接受,是不是感觉很亲切,还没有完,我们在前置增强制定好之后,下面强制在服务生队伍中应用这个规定,代码如下:

import org.junit.Before;
import org.junit.Test;
import org.springframework.aop.BeforeAdvice;
import org.springframework.aop.framework.ProxyFactory;

public class BeforeAdviceTest {
    private Writer target;
    private BeforeAdvice beforeAdvice;
    private ProxyFactory proxyFactory;
    //执行每个方法之前调用
    @Before
    public void init(){
        target=new WriterImpl();
        beforeAdvice=new GreetingBeforeAdvice();
        //spring提供的代理工厂
        proxyFactory=new ProxyFactory();
        //设置代理目标
        proxyFactory.setTarget(target);
        //我代理目标添加增强
        proxyFactory.addAdvice(beforeAdvice);
    }

    @Test
    public void beforeAdvice(){
        Writer proxy=(Writer) proxyFactory.getProxy();
        proxy.greeTo("shinelon");
        proxy.serverTo("tom");
    }
}

运行上面的测试,我们将看到以下的输出信息,是不是感觉到这个服务生礼貌多了。

How are you shinelon
gree toshinelon
How are you tom
server totom

你可能感兴趣的:(spring,aop,异常,Java)