面向切面编程
首先
面向切面编程 AOP 即 Aspect Oriented Program
首先,在面向切面编程的思想里面,把功能分为核心业务功能,和周边功能。
所谓的核心业务,比如登陆,增加数据,删除数据都叫核心业务
所谓的周边功能,比如性能统计,日志,事务管理等等
周边功能在Spring的面向切面编程AOP思想里,即被定义为切面
在面向切面编程AOP的思想里面,核心业务功能和切面功能分别独立进行开发
然后把切面功能和核心业务功能 "编织" 在一起,这就叫AOP
DEMO
一最近写的北京公交为例子吧,完成 操作日志
的功能
依赖
<!-- aop 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
定义日志注解
@Retention(RetentionPolicy.RUNTIME)
什么时候使用该注解,我们定义为运行时;@Target({ ElementType.METHOD })
注解用于什么地方,我们定义为作用于方法上;- 注解名为 OptLogAnnotation;
- 定义一个属性
日志描述信息
,默认为空字符串;
package cn.yiidii.panel.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 日志注解
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface OptLogAnnotation {
String desc() default "";//日志描述信息
}
定义操作日志切面
aspectj
相关注解的作用
@Aspect
:声明该类为一个注解类;
@Pointcut
:定义一个切点,后面跟随一个表达式,表达式可以定义为切某个注解,也可以切某个 package 下的方法;
切点定义好后,就是围绕这个切点做文章了:
@Before
: 在切点之前,织入相关代码;
@After
: 在切点之后,织入相关代码;
@AfterReturning
: 在切点返回内容后,织入相关代码,一般用于对返回值做些加工处理的场景;
@AfterThrowing
: 用来处理当织入的代码抛出异常后的逻辑处理;
@Around
: 环绕,可以在切入点前后织入代码,并且可以自由的控制何时执行切点;
package cn.yiidii.panel.advice;
import cn.yiidii.panel.annotation.OptLogAnnotation;
import cn.yiidii.panel.common.utils.IPUtil;
import cn.yiidii.panel.pojo.OptLog;
import cn.yiidii.panel.pojo.User;
import cn.yiidii.panel.service.impl.OptLogService;
import cn.yiidii.panel.shiro.util.SecurityUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.Objects;
/**
* 操作日志切面
*/
@Aspect
@Component
@Slf4j
public class OptLogAdvice {
@Autowired
private HttpServletRequest request;
@Autowired
private OptLogService optLogService;
@Around(value = "@annotation(cn.yiidii.panel.annotation.OptLogAnnotation)")//已注解 @OptLogAnnotation 为切点
public void insertOptLog(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();//注解的方法
OptLogAnnotation logAnnotation = method.getAnnotation(OptLogAnnotation.class);//注解
OptLog optLog = packageOptLog(logAnnotation.desc(), "NO_MODULE");
optLogService.insert(optLog);
}
private OptLog packageOptLog(String content, String module) {
OptLog optLog = new OptLog();
User user = SecurityUtil.getCurrUser();
if (!Objects.isNull(user)) {
optLog.setUid(user.getId());
optLog.setSubject(user.getUsername());
}
String ip = IPUtil.getIpAddr(request);
optLog.setIp(ip);
optLog.setLocationInfo(IPUtil.getLocationByIP(ip));
optLog.setModule(module);
optLog.setContent(content);
optLog.setCreateTime(new Date());
return optLog;
}
}