AOP(参考百度百科):面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
在springboot中使用,加入依赖即可。
不需要再配置application或添加@EnableAspectJAutoProxy注解,加入依赖后,默认为true。
spring AOP的三个注意注解:@Aspect(使用在类上,表明为切面)、@Pointcut()、Advice(表示方法执行的时机,比如方法前@Before或方法后@After)
Advice的5种注解:@Before(之前)、@After(之后)、@AfterReturning(返回后)、@AfterThrowing(抛出异常)、@Around(环绕)
一个简单的例子:
/**
* @author yuan
* @date 2019/1/27
* @description 日志切面配置
*/
@Aspect // 声明为切面
@Component // 加入容器
@Slf4j
public class LogAspect {
@Autowired
private SysLogService sysLogService;
/**
* 声明切入点
*/
@Pointcut("@annotation(com.yuanshijia.common.config.Log)")
public void log(){
}
/**
* @Before在调用方法前执行
* @param point 获取上下文
* @return
*/
@Around("log()")
public Object around(ProceedingJoinPoint point) {
Object result =null;
long beginTime = System.currentTimeMillis();
try {
log.info("我在目标方法之前执行!");
result = point.proceed();
long endTime = System.currentTimeMillis();
insertLog(point,endTime-beginTime);
} catch (Throwable e) {
// TODO Auto-generated catch block throw
}finally {
log.info("方法执行完调用");
}
return result;
}
private void insertLog(ProceedingJoinPoint point ,long time) {
MethodSignature signature = (MethodSignature)point.getSignature();
Method method = signature.getMethod();
SysLog sLog = new SysLog();
Log userAction = method.getAnnotation(Log.class);
if (userAction != null) {
// 注解上的描述
sLog.setAction(userAction.value());
}
// 请求的类名
String className = point.getTarget().getClass().getName();
// 请求的方法名
String methodName = signature.getName();
// 请求的方法参数值
String args = Arrays.toString(point.getArgs());
// 获取登录的用户
User user = (User) SecurityUtils.getSubject().getPrincipal();
if (user == null) {
throw new UnknownAccountException("用户未登录");
}
sLog.setUserId(user.getId());
sLog.setCreateTime(new Date());
log.info("当前登陆人:{},类名:{},方法名:{},参数:{},执行时间:{}", user.getId(), className, methodName, args, time);
sysLogService.insert(sLog);
}
}
@Pointcut
Pointcut express(切面表达式)主要有三个部分:designators(指示器)、wildcads(通配符)、operators(操作符)。
designators(指示器,表示你要通过哪些方式匹配):
比如
- 匹配方法:execution()
- 匹配注解:@target()、@args()、@annotation()
- 匹配包/类型:within()
- 匹配对象:this()、bean()、target()
- 匹配参数:args()
wildcads(通配符):*(匹配任意数量)、..(匹配对应的包或参数) 、+(匹配指定类及其子类)
operators(操作符):&&、||、!,即与或非。
例如,使用within:
/**
* 匹配com.yuanshijia包及子包下所有类的方法
*/
@Pointcut("within(com.yuanshijia..*)")
public void matchPackage(){
}
/**
* 匹配UserService类的所有方法
*/
@Pointcut("within(com.yuanshijia.service.service.UserService)")
public void mathType(){
}
点击查看参考文章