Spring的切面编程(AOP)概念与使用
一、面向切面编程
定义:面向切面编程(AOP)是通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。
作用:利用AOP对业务逻辑的各个部分进行隔离,降低逻辑部分之间的耦合度,提高代码复用和效率。
应用场景:日志记录、性能统计、安全控制、事务处理、异常处理等
二、AOP的概念
- 切面(aspect):在AOP中,切面一般使用@Aspect注解来标识。
- 连接点(Join Point):在Spring AOP,一个连接点总是代表一次方法的执行。
- 增强(Advice):在连接点执行的动作。
- 切入点(Pointcout):说明如何匹配到连接点。
- 引介(Introduction):为现有类型声明额外的方法和属性。
- 目标对象(Target Object):由一个或者多个切面建议的对象,由于Spring AOP是通过动态代理来实现的,这个对象永远是一个代理对象。
- AOP代理(AOP proxy):一个被AOP框架创建的对象,用于实现切面约定(增强方法的执行等)。在Spring Framework中,一个AOP代理是一个JDK动态代理或者CGLIB代理。
- 织入(Weaving):连接切面和目标对象或类型创建代理对象的过程。它能在编译时(例如使用AspectJ编译器)、加载时或者运行时完成。Spring AOP与其他的纯Java AOP框架一样是在运行时进行织入的。
AOP的增强类型
- 前置增强(Before advice):在连接点之前运行
- 返回增强(After returning advice):在连接点正常完成后运行的增强
- 异常增强(After thorwing advice):方法抛出异常退出需要执行的增强
- 后置增强(After (finally) Advice):无论连接点是正常或者异常退出,都会执行该增强
- 环绕增强(Around advice):围绕连接点的增强,例如方法的调用。环绕增强能在方法的调用之前和调用之后自定义行为。它还可以选择方法是继续执行或者去缩短方法的执行通过返回自己的值或者抛出异常。
三、AOP的实现
AOP的实现方式有两种方式:静态织入(以AspectJ为代表)和动态代理(Spring AOP实现)
AspectJ是一个采用Java实现的AOP框架,它能够对代码进行编译(在编译期进行),让代码具有AspectJ的AOP功能,当然它也可支持动态代理的方式;
Spring AOP实现:通过动态代理技术来实现,Spring2.0集成了AspectJ,主要用于PointCut的解析和匹配,底层的技术还是使用的Spring1.x中的动态代理来实现。
Spring AOP动态代理实现
使用Spring AOP实现日志记录的功能。并获取使用了织入点的方法的参数。使用注解作为切面的切入点,实现在方法处加入切面增强。
定义日志注解,注解中定义日志类型和描述,在使用改日志注解时可自定义日志类型和描述
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ApiLog {
int type() default 1;
String describe() default "";
}
定义切面的类、切入点、增强方法。代码中定义的是连接点后的增强方法和异常增强方法,分别用于记录连接点方法顺利执行完成的日志结果和异常日志结果。
@Aspect
@Component
public class AipLogAspect {
@Autowired
private JwtTokenUtils jwtTokenUtils;
@Autowired
private SysLogsService sysLogsService;
@Autowired
private TenantDoMapper tenantDoMapper;
@Pointcut("@annotation(com.richstonedt.cmgdprd.viaas.common.annotation.ApiLog)")
public void Pointcut() {
}
@AfterReturning(value = "Pointcut()")
public void saveOperLog(JoinPoint joinPoint) {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
HttpServletRequest request = (HttpServletRequest) requestAttributes
.resolveReference(RequestAttributes.REFERENCE_REQUEST);
String ip=request.getRemoteAddr();
SysLogs sysLog = new SysLogs();
try {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Object paramNames= null;
try {
paramNames = joinPoint.getArgs()[0];
}catch (Exception paramse){
paramNames = joinPoint.getArgs();
}
ApiLog annotation = signature.getMethod().getAnnotation(ApiLog.class);
Integer logType=annotation.type();
String describe=annotation.describe();
sysLog.setIpAddress(ip);
sysLog.setStatus(1);
sysLog.setUri(request.getRequestURI());
sysLog.setMethod(request.getMethod());
sysLog.setDescribe(describe);
sysLog.setLogType(logType);
sysLogsService.save(sysLog);
} catch (Exception e) {
e.printStackTrace();
}
}
@AfterThrowing(pointcut = "Pointcut()", throwing = "e")
public void saveExceptionLog(JoinPoint joinPoint, Throwable e) {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
HttpServletRequest request = (HttpServletRequest) requestAttributes
.resolveReference(RequestAttributes.REFERENCE_REQUEST);
SysLogs sysLog = new SysLogs();
String ip=request.getRemoteAddr();
try {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Object paramNames= null;
try {
paramNames = joinPoint.getArgs()[0];
}catch (Exception paramse){
paramNames = joinPoint.getArgs();
}
ApiLog annotation = signature.getMethod().getAnnotation(ApiLog.class);
Integer logType=annotation.type();
String describe=annotation.describe();
sysLog.setIpAddress(ip);
sysLog.setStatus(0);
sysLog.setUri(request.getRequestURI());
sysLog.setMethod(request.getMethod());
sysLog.setDescribe(describe);
sysLog.setLogType(logType);
sysLog.setException(e.getMessage());
sysLogsService.save(sysLog);
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
参考文章Spring之面向切面编程(AOP)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)