AOP(Aspect Oriented Programming)即:面向切面编程, 通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术
AOP在Spring中的术语:
通知(advice)
Before
After
After-Returning
After-Throwing
Around
连接点(JointPoing)
切点(PointCut)
切面(Aspect)
引入(Introduction)
织入(Weaving)
术语解释:
1.通知(Advice):通知定义了切面是什么以及何时使用。描述了切面要完成的工作和何时需要执行这个工作。
2.连接点(Joinpoint):程序能够应用通知的一个“时机”,这些“时机”就是连接点,例如方法被调用时、异常被抛出时等等。
3.切入点(Pointcut)
通知定义了切面要发生的“故事”和时间,那么切入点就定义了“故事”发生的地点,例如某个类或方法的名称,spring中允许我们方便的用正则表达式来指定
4.切面(Aspect)
通知和切入点共同组成了切面:时间、地点和要发生的“故事”
5.引入(Introduction)
引入允许我们向现有的类添加新的方法和属性(Spring提供了一个方法注入的功能)
6.目标(Target)
即被通知的对象,如果没有AOP,那么它的逻辑将要交叉别的事务逻辑,有了AOP之后它可以只关注自己要做的事(AOP让他做爱做的事)
7.代理(proxy)
应用通知的对象,详细内容参见设计模式里面的代理模式
8.织入(Weaving)
把切面应用到目标对象来创建新的代理对象的过程,织入一般发生在如下几个时机:
(1)编译时:当一个类文件被编译时进行织入,这需要特殊的编译器才可以做的到,例如AspectJ的织入编译器
(2)类加载时:使用特殊的ClassLoader在目标类被加载到程序之前增强类的字节代码
(3)运行时:切面在运行的某个时刻被织入,SpringAOP就是以这种方式织入切面的,原理应该是使用了JDK的动态代理技术
编译器 – AspectJ的做法
类加载期 – AspectJ 5的LTW(Load-time weaving)的做法
运行期 – Spring的做法
AOP实现方式有3种:
基于代理的的经典AOP – 只能代理接口
基于@AspectJ注解驱动的切面 – 只能代理类
纯POJO切面
拦截器(Interceptor)的三种实现
纯POJO切面 :XML配置方式
<aop:config>
<aop:aspect ref=”testInterceptor”>
<aop:pointcut expression=”execution(public * com.freud.test..*.*(..))”
id=”testPointCut” />
<aop:after method=”after” pointcut-ref=”testPointCut” />
<aop:before method=”before” pointcut-ref=”testPointCut” />
</aop:aspect>
</aop:config>
<bean id=”testInterceptor” class=”com.freud.TestInterceptor” />
package com.freud;
public class TestInterceptor {
public void after() {
System.out.println(“After”);
}
public void before() {
System.out.println(“before”);
}
}
切点的表示方式在Spring中有好几种,但是常用的只有两种:1.使用正则表达式 2.使用AspectJ表达式
2基于代理的的经典AOP,基于Spring定义的MethodInterceptor
在Spring中共提供了四种Advice用来支持对方法调用时施加的不同行为
BeforeAdvice:具体接口:MethodBeforeAdvice 在目标方法调用之前调用的Advice
AfterAdvice:具体接口:AfterReturningAdvice 在目标方法调用并返回之后调用的Advice
AroundAdvice:具休接口:MethodInterceptor 在目标方法的整个执行前后有效,并且有能力控制目标方法的执行
ThrowsAdvice:具体接口:ThrowsAdvice 在目标方法抛出异常时调用的Advice
在以上四种Advice中最为特别的就是MethodInterceptor:方法拦截器.它的特别之处在于:首先他所在的包并不Srping中的包而是:org.aopalliance.intercept包.即MethodInterceptor实现了AOP联盟接口,这一点保证了它较之其他的Advice更具有通用性,因为它可以在任何基于AOP联盟接口实现的AOP系统中使用.第二点也就是其最为突出的一点就是它所具有的其他Advice所不能匹敌的功能:在目标方法的整个执行前后有效,并且有能力控制目标方法的执行!
<bean id=”testInterceptor” class=”com.freud.Interceptor.TestInterceptor”></bean>
<aop:config >
<!–切入点–>
<aop:pointcut id=”testPointCut” expression=”execution(public * com.freud.test.*.*(..))”/>
<!– 在该切入点使用自定义拦截器 –>
<aop:advisor pointcut-ref=”testPointCut” advice-ref=”testInterceptor”/>
</aop:config>
package com.freud.test.interceptor;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class TestInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
//Do something before
Object ret = invocation.proceed();
//Do something After
return ret;
}
}
3基于@AspectJ注解驱动的切面 ,纯注解方式
<beans xmlns=”http://www.springframework.org/schema/beans”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xmlns:aop=”http://www.springframework.org/schema/aop”
xsi:schemaLocation=”
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd”>
<aop:aspectj-autoproxy />
</bean>
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class TestInterceptor {
@Pointcut(“execution(public * com.freud.interceptor.*.insert*(..))||execution(* com.freud.interceptor.*.add*(..))”)
public void insert() {
}
@AfterReturning(“insert()”)
public void doAfterReturn(JoinPoint jp) {
System.out.println(“AfterReturn”);
}
@After(“insert()”)
public void doAfter(JoinPoint jp) {
System.out.println(“After”);
}
@Before(“insert()”)
public void doBefore(JoinPoint jp) {
System.out.println(“Before”);
}
@AfterThrowing(“insert()”)
public void doAfterThrowing() {
System.out.println(“AfterThrowing”);
}
@Around(“insert()”)
public void doAround() {
System.out.println(“Around”);
}
}
注意
在使用的过程中,如果Spring AOP和 Spring MVC集成,对Controller及之前的层面进行拦截,需要配置在同webcontext目录下的ApplicationContext文件中,不能配置在源目录下,否则会出现不执行拦截器的现象。