一、AOP技术概念
面向切面编程[底层就是动态代理]指程序在运行期间动态的将某段代码切入到指定方法位置进行运行的编程方式。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
二、Spring AOP 相关术语
1、切面(Aspect):在Spring AOP中,切面可以使用通用类或者在普通类中以@Aspect 注解(@AspectJ风格)来实现;
2、连接点(Joinpoint):在Spring AOP中一个连接点代表一个方法的执行;
3、通知(Advice):在切面的某个特定的连接点(Joinpoint)上执行的动作通知有各种类型,其中包括"around"、 "before”
和"after"等通知。许多AOP框架,包括Spring,都是以拦截器做通知模型,并维护一个以连接点为中心 的拦截器链;
4、切入点(Pointcut):定义出一个或一组方法,当执行这些方法时可产生通知,Spring缺省使用AspectJ切入点语法。
三、通知Advice类型
1、前置通知(@Before):在某连接点(join point)之前执行的通知,但这个通知不能阻止连接点前的执行(除非它抛出一个异常)
2、返回后通知(@AfterReturning):在某连接点(join point)正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回
3、抛出异常后通知(@AfterThrowing):方法抛出异常退出时执行的通知
4、后通知(@After):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)
5、环绕通知(@Around):包围一个连接点(join point)的通知,如方法调用。这是最强大的一种通知类型,环绕通知可
以在方法调用 * 前后完成自定义的行为,它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行
四、代码示例
加入依赖
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.7</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>
1、定义切面织入点注解
@Target({ElementType.PARAMETER,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CollectEnable {
boolean isCollect() default false;
}
2、定义切面
@Aspect
@Component
public class CollectAspect {
private final static Logger LOGGER= LoggerFactory.getLogger(CollectAspect.class);
@Value("${collect.canable}")
private boolean isConfig;
/**
* 判断是否有注解
* @param joinPoint 连接点
*/
private CollectEnable getCollectAnnotation(JoinPoint joinPoint){
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature= (MethodSignature) signature;
Method method=methodSignature.getMethod();
if(method!=null){
return method.getAnnotation(CollectEnable.class);
}
return null;
}
/**
*配置切面的织入点
*/
@Pointcut("@annotation(com.fce.mycat.submeter.anotation.CollectEnable)")
public void collectPointCut(){}
/**
* 在切点方法之前执行
* @param joinPoint
*/
@Before("collectPointCut()")
public void doBefore(JoinPoint joinPoint){
CollectEnable collectAnnotation = getCollectAnnotation(joinPoint);
if(collectAnnotation!=null){
LOGGER.info("CollectAspect-->doBefore-------前置织入");
}
}
@After("collectPointCut()")
public void doAfter(JoinPoint joinPoint){
CollectEnable collectAnnotation = getCollectAnnotation(joinPoint);
if(collectAnnotation!=null){
LOGGER.info("CollectAspect-->doAfter-------后置织入");
}
}
/**
* 环绕增强,控制包裹代码是否执行
* @param joinPoint
*/
@Around("collectPointCut()")
public void doAround(ProceedingJoinPoint joinPoint){
CollectEnable collectAnnotation = getCollectAnnotation(joinPoint);
boolean collect = collectAnnotation.isCollect();
if(collect&&isConfig){
LOGGER.info("CollectAspect-->doAround----开启采集任务");
try {
joinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}else{
LOGGER.info("CollectAspect-->doAround----禁止执行采集");
}
}
}
3、在切点上使用增强
@Service
public class CollectService {
private final static Logger LOGGER= LoggerFactory.getLogger(CollectService.class);
@CollectEnable(isCollect = true)
public void collect360(){
LOGGER.info("CollectService---->collect360()-------开始采集了");
}
@CollectEnable
public void collectHuaWei(){
LOGGER.info("CollectService---->collectHuaWei()----开始采集了");
}
}