参考
Spring 使用笔记之(二) - AOP和Interceptor(拦截器)
spring AOP概念讲解
AOP--Filter使用,过滤器和拦截器的区别
AOP原理
AOP介绍
AOP:Aspect Oriented Programing,面向切面编程。
面向切面编程(AOP)是对面向对象编程(OOP)在另一程序结构上面的补充. OOP 的核心单位是 class, 而AOP的核心单位则是 aspect(切面). 切面使得对于像事务管理这种横切不同类型和对象的逻辑变得模块化.
应用场景
AOP主要的功能是:日志记录,性能统计,安全控制,事务处理,异常处理等等。
主要的意图是:将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。
AOP优点
- 降低模块的耦合度
- 使系统容易扩展
- 设计决定的迟绑定:使用AOP,设计师可以推迟为将来的需求作决定,因为它可以把这种需求作为独立的方面很容易的实现。
- 更好的代码复用性
AOP概念
1.Aspect
横切关注点的模块化,比如上边提到的日志组件。可以认为是增强、引入和切入点的组合;在Spring中可以使用Schema和@AspectJ方式进行组织实现;在AOP中表示为“在哪里做和做什么集合”;
2.Join point
表示需要在程序中插入横切关注点的扩展点,连接点可能是类初始化、方法执行、方法调用、字段调用或处理异常等等,Spring只支持方法执行连接点,在AOP中表示为“在哪里做”;
3.Advice
在一个特定的连接点上所采取的动作,类型包括around,before,after等,Spring中 advice就是一个interceptor模式,包括around连接点的interceptor链
4.Pointcut
选择一组相关连接点的模式,即可以认为连接点的集合,Spring支持perl5正则表达式和AspectJ切入点模式,Spring默认使用AspectJ语法,在AOP中表示为“在哪里做的集合”;
5.Introduction
声明一个类型的其他方法或字段,Spring AOP允许引入新接口(和对应的实现)的任意advised对象
6.Target object
由一个或多个切面advised对象,从SpringAOP实现代理运行开始,这个对象一直是一个代理对象
7.AOP proxy
AOP框架创建的对象,该对象实现了aspect规则(advise 方法执行等),在Spring框架中,一个AOP代理就是一个JDK动态代理或CGLIB代理
8.Weaving
织入是一个过程,是将切面应用到目标对象从而创建出AOP代理对象的过程,织入可以在编译期、类装载期、运行期进行。
9.Advice 类型
在连接点上执行的行为,提供了在AOP中需要在切入点所选择的连接点处进行扩展现有行为的手段;在Spring中通过代理模式实现AOP,并通过拦截器模式以环绕连接点的拦截器链织入增强 ;在AOP中表示为“做什么”;
- Before advice:在连接点之前执行,它无法阻止AOP执行连接点(除非抛出异常)
- After returning advice: 在一个连接点正常完成后执行,例如,一个方法正常返回值且未抛出异常
- After throwing advice:如果一个方法因抛出异常而退出,这时就会执行该Advice
- After (finally) advice: 无论方法是正常返回还是抛出异常都会执行该Advice
- Around advice: 在方法before之前和after之后执行该Advice,它也可以决定是否继续向后执行或返回自定义值或抛出异常
10.AOP代理
Spring AOP默认使用标准的J2SE动态代理,它可以代理任意接口。也可以使用CGLIB代理,当一个业务对象不实现接口的情况下,默认使用CGLIB代理,但建议使用面向接口编程。
AOP的几种实现
AOP在Spring中的支持
- 基于代理的的经典AOP(只能代理接口)
- 基于@AspectJ注解驱动的切面(只能代理类)
- 纯POJO切面
- 注入式AspectJ切面
XML配置方式
使用此种方式,可直接对execution配置的所有包中的接口添加切面,进行处理。
package com.myparamita;
public class TestInterceptor {
public void after() {
System.out.println("After");
}
public void before() {
System.out.println("before");
}
}
mvc:interceptors 方式
使用spring mvc的拦截器来实现,拦截器可同时配置多个,根据配置的顺序执行,可直接对拦截器中配置的规则进行拦截处理。
package com.myparamita.interceptors;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ControllerInterceptor implements HandlerInterceptor {
long inTime;
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
inTime = System.currentTimeMillis();
System.out.println("in controller: "+request.getServletPath());
return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
long timeGap = Math.abs(System.currentTimeMillis() - inTime);
System.out.println("out controller: "+"{\"controllerPath\":\"" + request.getServletPath() + "\",\"timeGap\":" + timeGap + "}");
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
}
}
纯注解方式
采用此方式,配置均通过注解方式在拦截类中进行设置,如下:
package com.myparamita.aop;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LogInterceptor {
@Pointcut("execution(public * com.myparamita.controller.*.*(..))")
public void myMethod() {
}
@Before("myMethod()")
public void before() {
System.out.println("=========================================method start");
}
@After("myMethod()")
public void after() {
System.out.println("=========================================method after");
}
}
spring配置文件中添加:
基于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所不能匹敌的功能:在目标方法的整个执行前后有效,并且有能力控制目标方法的执行!
package com.myparamita.aop;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class TestInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("======================before====");
//此处可根据实际情况决定是否执行目标方法
Object ret = invocation.proceed();
System.out.println("======================after====");
return ret;
}
}