首先有几个AOP术语,在这里陈述一下。
1. 连接点(joinpoint)
程序执行的某一个特定位置,如类初始化前,初始化后,类的某个方法调用前和调用后,方法抛出异常后,一个类或者一段代码拥有一些具有边界性质的特定点,这些代码中的特定点就是“连接点”。spring仅支持方法的连接点,即仅能在方法调用前,方法调用后,方法抛出异常时以及方法调用前后这些程序执行点的织入增强,有一个形象的比如可以让我们清晰的描述这个概念,AOP就像一个黑客,它攻击别人要找到突破点,连接点就想黑客找到入侵的突破点一样,怎么样,是不是很形象。
2.切点(pointcut)
每一个程序有多个连接点,如一个类拥有两个方法,这两个方法都是连接点,即连接点是程序类客观存在的事务,但在众多的连接点中,如何定位到一个连接点感兴趣的连接点呢?AOP通过“切点”来定位特定的连接点,再用一个例子来说明,可以通过数据库的查询概念来类比这个概念,连接点相当于数据库中的记录,而切点 相当于查询条件,切点和连接点不是一一对应的关系,一个切点可以匹配多个连接点。确切的说,切点是定位到某个方法上的,所以如果希望定位到具体连接点上,还你需要提供方位信息。
3.增强(Advice)
增强是织入目标类连接点上的一段程序代码,因为增强既包含了用于添加到目标连接点上的一段执行逻辑代码,又包含了用于定位连接点的方位信息,所以spring多提供的增强都是带有方位名的:BeforeAdvice,AfterReturningAdvice,ThrowsAdvice等,所以增强只有结合切点才能确定特定的连接点并实施增强逻辑。
4.目标对象(target)
这个简单易懂,见名知意,即增强逻辑的织入目标类。
5.引介(introduction)
引入是一种特殊的增强,它为类添加了一些属性和方法,即如果原本一个业务类没有实现某个接口,通过AOP的引介功能,也可以动态的为该业务类添加接口的实现逻辑,让业务类成为这个接口的实现类。
6.织入(Weaving)
织入是将增强添加到目标类具体连接点上的过程,AOP像一台织布机,将目标类和增强或者引介通过aop这台织布机天衣无缝的编织到一起,Aop有三种织入方式:
7.代理(proxy)
一个类被织入增强后,就产出了一个结果类,它是融合了原类和增强逻辑的代理类,根据不用的代理方式,代理 类既可以与原类具有相同接口的类,也可以是原类的子类,所有可以采用与调用原类相同的方式调用代理类。
8.切面(Aspect)
切面由切点和增强(引介)组成,它既包含了横切逻辑,有包含了连接点的定义,spring aop就是负责切面的框架,它将切面所定义的横切逻辑织入切面所指定的连接点中。
在介绍完上面的一些概念后,我们来具体的介绍一下增强的类型,并且通过一些例子来实践。
1.增强类型:
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