JDK1.5开始引入了注解,Spring框架也正好把Java注解发挥得淋漓尽致,以下通过自定义一个日志注解@LogAnnotation,在被注解的方法执行前后打印日志,来深入了解Spring注解。
一、创建自定义注解
创建注解类LogAnnotation
package com.ztesoft.bss.prod.cust.service.impl.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface LogAnnotation {
}
自定义的注解类上添加的几个注解,依次解释说明下:
1、Target:指明注解支持的使用范围,取值可以参考枚举ElementType。
- ElementType.TYPE //类、接口、枚举
- ElementType.FIELD //属性
- ElementType.METHOD//方法
- ElementType.PARAMETER //参数
- ElementType.CONSTRUCTOR //构造器
- ElementType.LOCAL_VARIABLE //局部变量
- ElementType.ANNOTATION_TYPE //注解
- ElementType.PACKAGE //包
2、Retention:指明注解保留的的时间长短,取值参考枚举RetentionPolicy,一下:
- SOURCE //源文件中保留
- CLASS //class编译时保留
- RUNTIME //运行时保留
3、Documented:指明拥有这个注解的元素可以被javadoc此类的工具文档化。
4、Inherited:指明该注解类型被自动继承。如果一个annotation注解被@Inherited修饰,那么该注解作用于的类 的子类也会使用该annotation注解。
二、创建切面类
package com.ztesoft.bss.prod.cust.service.impl.annotation;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LogAspect {
// 指定切点-被@LogAnnotation注解修饰的方法
@Pointcut(value = "@annotation(com.ztesoft.bss.prod.cust.service.impl.annotation.LogAnnotation)")
private void servicePointcut() {
}
// 切面通知-环绕通知
@Around(value = "servicePointcut() && @annotation(LogAnnotation)")
public void after(JoinPoint joinPoint) {
System.out.println("==========开始执行日志打印===============");
try {
// 执行被拦截的方法
((ProceedingJoinPoint) joinPoint).proceed();
}
catch (Throwable e) {
System.out.println(e);
}
System.out.println("==========结束执行日志打印===============");
}
}
从上述切面通知的代码了解到,所执行的切面逻辑很简单,就是在方法执行前后打印下日志。
三、使用自定义注解
接下来就是给需要使用注解的方法上添加@LogAnnotation:
@LogAnnotation
public List<CustAttrDto> getCustAttrListByCustId(Long custId) {
return custAttrMapper.getCustAttrListByCustId(custId);
}
最后就是执行getCustAttrListByCustId()方法,查看日志打印:
==========开始执行日志打印===============
APPLICATION|DEBUG|||2021-02-26 13:26:02:160|||JakartaCommonsLoggingImpl.java:54|debug||1|||==> Preparing: SELECT A.CUST_ATTR_ID, A.ATTR_VALUE, A.ATTR_ID, A.STATUS_CD, A.CREATE_STAFF, A.UPDATE_STAFF, A.CUST_ID, C.ATTR_VALUE_ID, A.REMARK, B.ATTR_NBR FROM CUST_ATTR A JOIN ATTR_SPEC B ON A.ATTR_ID = B.ATTR_ID LEFT JOIN ATTR_VALUE C ON A.ATTR_ID = C.ATTR_ID AND A.ATTR_VALUE = C.ATTR_VALUE WHERE A.CUST_ID = ?
APPLICATION|DEBUG|||2021-02-26 13:26:02:162|||JakartaCommonsLoggingImpl.java:54|debug||1|||==> Parameters: 111(Long)
APPLICATION|DEBUG|||2021-02-26 13:26:02:166|||JakartaCommonsLoggingImpl.java:54|debug||1|||<== Total: 0
==========结束执行日志打印===============
由上图打印的日志可知,目标方法已成功织入切面逻辑!当然具体在Spring中,自定义注解是如何拦截目标方法,并织入切面逻辑的,可以看下《Spring源码阅读(六)-AOP》这篇会有详细介绍。