Aop术语:
通知(Advice):切面的功能被称为通知,通知描述了切面要完成什么工作及何时何时执行切面功能。
连接点(JoinPoint):程序应用通知的时机称为“连接点”。连接点是在程序执行过程中能够插入切面的一个点。这个点可以是方法被调用时,异常抛出时,甚至是字段被编辑时。切 面代码可以通过这些点插入到程序的一般流程之中,从而添加新的行为。
切入点(Pointcut):一个切面不是要通知程序里全部的连接点。切入点可以缩小切面通知的连接点的范围。
如果说通知定义了切面的“什么”和“何时”,那么切入点就定义了“何地”。切入点的定义匹配通知要织入的一个或多个连接点。我们通常使用明确的类和方法名称,或是利用正则表达式定义匹配的类或方法名称模板来指定这些切入点。
个人理解:切入点就是哪些通知要应用到哪些连接点。
切面(Aspect):是通知和切入点的结合。通知和切入点共同定义了关于切面的全部内容--它的功能、在何时、何地完成其功能。
目标(Target):被通知的对象。
代理(Proxy):“代理”是向目标对象应用通知之后被创建的对象。对于客户对象来说,目标对象(AOP之前)和代理对象(AOP之后)是一样的。
织入(Weaving):“织入”是把切面应用到目标对象来创建新的代理对象的过程。
理解Spring AOP框架的几个关键点:
1 Spring通知是用java编写的。
2 Spring在运行时通知对象。
Spring利用代理类包裹切面,从而把他们织入到Spring管理的bean里。在代理截取调用方法之后、实际调用目标bean的方法之前,代理会执行切面逻辑。
Spring知道程序需要背带里的Bean时才创建它。如果使用的是ApplicationContext,被代理的对象会在从BeanFactory加载全部bean时被创建。由于Spring实在运行时创建代理,所以我们不需要使用特殊的编译器把切面织入到Spring的AOP。
Spring生成被代理类的方式有两种。如果目标对象实现的是一个接口,Spring会使用JDK的java.lang.reflect.Proxy类,它允许Spring动态生成一个新类来实现必要的接口、织入任何通知、并且把对这些接口的任何调用都转发到目标类。
如果目标类不是实现一个接口,Spring就使用CGLIB库生成目标类的一个子类。在创建这个子类时,Spring织入通知,并且把对这个子类的调用委托到目标类,在使用这种方式时,需要注意两点。
1 创建接口的代理比使用代理类更受人喜欢,因为它能够更好地实现程序的松耦合。提供代理类的功能是为了让以前或第三方的没有实现接口的类也能够被通知,所以这种· 方法应该被当做一种例外,而不是规则。
2 被标记为final的方法不能被通知。记住,Spring为目标类创建一个子类,需要被通知的任何方法都会被覆盖并被织入通知,这对于final类型的方法是不可能的。
3 Spring只支持方法连接点。
例子程序:
package com.puwu.springidol;
/**
* 该类模拟观众
* 我们希望:观众在演出之前入座并关闭手机
* 演出精彩之处鼓掌
* 演出糟糕时要求退票
* @author puwu
*
*/
public class Audience {
public Audience () {};
/**
* 观众入座
*/
public void takeSeats() {
System.out.println("The audience is taking their seats.");
}
/**
* 观众关闭手机
*/
public void turnOffCellPhones () {
System.out.println("The audience is turning off their cellphones.");
}
/**
* 观众鼓掌
*/
public void applaud() {
System.out.println("CLAP CLAP CLAP CLAP CLAP !");
}
/**
* 观众要求退票
*/
public void demandRefund() {
System.out.println("Boo! We want our money back!");
}
}
创建通知:
Spring中有5种类型的通知:
通知类型 接口
Before(前) org.springframework.aop.MethodBeforeAdvice
After-returning(后) org.springframework.aop.AfterReturningAdvice
After-throwing(抛出后) org.springframework.aop.ThrowsAdvice
Around(周围、环绕) org.aopalliance.intercept.MethodInterceptor
Introduction(引入) org.springframework.aop.IntroductionInterceptor
import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.ThrowsAdvice;
/**
* 根据逻辑,观众入座和关闭手机应该作为前通知,
* 鼓掌为后通知
* 要求退票为抛出后通知
* @author puwu
*
*/
public class AudienceAdvice implements MethodBeforeAdvice,AfterReturningAdvice,ThrowsAdvice{
public AudienceAdvice() {};
private Audience audience;
public void setAudience(Audience audience) {
this.audience = audience;
}
/**
* 在方法之前调用
* method:java.lang.reflect.Method对象,它代表要使用这个通知单方法。
* objects:方法被调用时要传递的参数。
* target:被调用方法所在的对象
*/
@Override
public void before(Method method, Object[] objects, Object target)
throws Throwable {
// TODO Auto-generated method stub
audience.takeSeats();
audience.turnOffCellPhones();
}
/**
* 在成功返回之后执行
* returnValue:包含了从被调用方法返回的值
* 其他参数与before相同
*/
@Override
public void afterReturning(Object returnValue, Method method, Object[] objects,
Object target) throws Throwable {
// TODO Auto-generated method stub
audience.applaud();
}
/**
* 在抛出异常后执行
* ThrowsAdvice不需要实现任何方法,它只是一个标记接口,告诉Spring相应的通知要求处理被抛出的异常
*/
public void afterThrowing(Throwable throwable){
audience.demandRefund();
}
}