开发中有时会遇到一些需求,需要记录一些方法的执行时间、地点、及操作内容。我们需要在用户操作时获取用户的日志信息,然后做持久化。如果在本次方法中处理的话,就会有很多重复代码,也容易发生遗漏,使用注解式aop,就能很优雅的实现这个功能。
aop步骤:
1.创建一个切面类
2.在类中定义增强方法,通过注解确定增强类型
3.在注解中配置切入点
切方法
"execution(* com.xst.service..*.*(..))"
第一个 * 表示任意返回值
com.xst.service 定义包 业务层 表示在com.xst.service包下
第二个 * 表示任意类
第三个 * 表示任意方法
(..)表示任意形参
连起来就是 切入点为在com.xst.service包下 任意类 任意方法 任意形参 任意返回值 的方法
/**
* @Aspect 声明当前类为切面类
* 会自动编织类中的切点和增强
* @Configuration 声明当前类为配置类
*/
@Aspect
@Configuration
public class LogAop {
/**
* 创建增强方法
* @After() 后置增强
* @Before()前置增强
* @Around()环绕增强
* @AfterThrowing 异常
* 切入点表达式("execution(* com.xst.service..*.*(..))"
*/
@After("execution(* com.xst.service..*.*(..))")
public void testAfter() {
System.out.println("后置增强AOEUIDHTN");
}
}
4.环绕增强
上面方法是在符合切入点的方法执行之后执行,前置和后置增强都很好理解,那么我们来看一下ta们和环绕增强之间的区别
区别:
1.需要形参 ProceedingJoinPoint joinPoint
2.需要对目标方法执行放行操作 手动调用
3.需要将业务层方法执行结果返回
@Around("execution(* com.xst.service..*.*(..))")
public Object testAround(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("执行环绕增强前pyfgcrl");
/**
* 放行
*执行目标方法
* proceed 执行业务层方法
*/
Object proceed = joinPoint.proceed();
System.out.println("执行环绕增强后qjkxbmwvz");
return proceed;
}
自定义注解步骤
1.创建自定义注解类
2.定义元注解
3.定义自定义注解的属性
/**
* 元注解 加在自定义注解上的注解
*
* @Target("ElementType.METHOD")定义当前注解可以加在什么地方 METHOD 方法上
* TYPE 类上
* FIELD 属性上
* @Retention(RetentionPolicy.RUNTIME) 定义注解生效时间
* SOURCE 注解只保留在源文件,当代码编译成class文件 注解会被jvm删除
* CLASS 注解被保留到class文件,但jvm加载class文件时候被删除,这是默认的生命
* RUNTIME 一直生效
* .java文件 ---> .class文件 ---> 内存中的字节码
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogAnnotation {
/**
* 操作内容 content();
* 操作类型 type();
*/
String content();
String type();
}
4.业务方法添加自定义注解
@LogAnnotation(content = "充值", type = "update")
public void serviceImplMethod() {
System.out.println("充值到账100元");
}
下面我们只需要在业务方法上添加自定义注解,然后在切面类的增强方法中获取日志信息(当前用户、ip地址、操作时间、操作内容、操作类型等等),然后做持久化。
很明显,日志记录比较适合使用后置增强类型,所以我们可以在后置增强方法内通过下面代码获取自定义注解的属性。
// 1.获取方法签名对象
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
// 2.获取方法对象
Method method = signature.getMethod();
// 3.获取方法上的注解 LogAnnotation为自定义注解类
LogAnnotation annotation = method.getAnnotation(LogAnnotation.class);
// 4.获取注解的值
String content = annotation.content();
String type = annotation.type();
可能会有一些不完善的地方,我想起来会更新。