您的位置:首页 > 编程语言 > Java开发

spring之AOP(面向切面编程)

2016-12-26 00:00 459 查看
一、简介

何为AOP,通俗的将就是给某些方法执行之前、执行之后等动作发生的时候执行某些操作,在执行这些操作的时候可以获取执行方法的相关信息,简化程序开发中总是重复的东西,比如方法入参出参的日志打印,用户访问权限校验,事务控制等。

二、术语

通知(advice):切面的工作被称为通知。通俗点:什么时候怎么干啥事。

1.前置通知(before):在目标方法被调用之前调用通知功能。

2.后置通知(after):在目标方法完成之后调用通知,此事不会关心方法的输出是什么。

3.返回通知(after-returning):在目标方法成功执行之后调用通知。

4.异常通知(after-throwing):在目标方法跑出异常后调用通知。

5.环绕通知(around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。

连接点(joinpoint):使用通知的地方。

切点(pointcut):匹配通知所要织入的一个或多个连接点。

切面(aspect):通知和切点的结合定义切面的全部内容,它是什么,在何时何处完成其功能。

引入(introduction):可以向现有的类添加新方法和属性。

织入(weaving):把切面应用到目标对象并创建新的代理对象的过程。切面在制定的连接点被织入到目标对象中,在目标对象的生命周期里有多个点可以织入:

1.编译期:切面在目标类编译时织入,这种方式需要特殊的编译器,AspectJ的织入编辑器就是以这种方式织入切面的。

2.类加载期:切面在目标类加载到JVM时织入,这种方式需要特殊的类加载器(ClassLoader),它可以在目标类被引入应用之前增强该目标类的字节码。

3.运行期:切面在应用运行的某个时刻被织入,一般情况下,在织入切面时,AOP容器会为目标对象动态的创建一个代理对象,SpringAOP就是以这种方式织入切面的。

三、spring对AOP的支持

spring提供了4种类型的AOP支持:

1.基于代理的经典SpringAOP

2.纯POJO切面

3.@AspectJ注解驱动的切面

4.注入式AspectJ切面

前三种是springAOP实现的变体,SpringAOP构建在动态代理的基础之上,因此,spring对AOP的支持局限于方法拦截。

四、spring只支持方法界别的连接点

因为spring是基于动态代理,所以孩子恩能够支持方法级别的aop。AspectJ和JBoss,除了方法切点,还提供了字段和构造器接入点。spring缺少字段连接点的支持,无法让我们创建细粒度的通知,例如拦截对象字段的修改,而且他不支持构造器连接点,我们就无法再bean创建时应用通知。

五、切点表达式

execution(* sundsystem.CompactDisc.playTrack(int))

第一个* 返回任意类型

sundsystem.CompactDisc 方法所属的类型

playTrack 方法

int 接受int类型的参数

六、demo

注解:

package com.pz.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
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;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;

@Aspect
@Component
public class LogAspect {

private static Logger logger = LoggerFactory.getLogger(LogAspect.class);

@Pointcut("execution(public * com.pz.service..*.*(..))")
public void logPoint(){}

@Before("logPoint()")
public void logBefor(JoinPoint joinPoint){
String method = joinPoint.getSignature().getName();
Object [] args = joinPoint.getArgs();
String param = JSON.toJSONString(args);
logger.info("[前置通知][{}] param:{}", method, param);
}

@After("logPoint()")
public void logAfter(JoinPoint joinPoint){
String method = joinPoint.getSignature().getName();
Object [] args = joinPoint.getArgs();
String param = JSON.toJSONString(args);
logger.info("[后置通知][{}] result:{}", method, param);
}

@AfterReturning(pointcut="logPoint()", returning="result")
public void logAfterReturning(JoinPoint joinPoint, Object result){
String method = joinPoint.getSignature().getName();
String response = JSON.toJSONString(result);
logger.info("[返回通知][{}] return:{}", method, response);
}

@AfterThrowing(pointcut="logPoint()", throwing="e")
public void logAfterThrowing(JoinPoint joinPoint, Exception e){
String method = joinPoint.getSignature().getName();
logger.error("[异常通知][{}] exception:{}", method, e.getMessage());
}

@Around("logPoint()")
public Object logArount(ProceedingJoinPoint pjp) throws Throwable{
Object result = null;
String param = JSON.toJSONString(pjp.getArgs());
String method = pjp.getSignature().getName();
try{
logger.info("[环绕通知][{}] param:{}", method, param);
result = pjp.proceed();
logger.info("[环绕通知][{}] result:{}", method, JSON.toJSON(result));
}catch(Exception e){
logger.error("[环绕通知][{}] exception:{}", method, e.getMessage());
throw new RuntimeException(e);
}
logger.info("[环绕通知][{}] return:{}", method, JSON.toJSON(result));
return result;
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: