@Target
取值 |
作用域 |
@Target(ElementType.TYPE) |
接口、类、枚举、注解 |
@Target(ElementType.FIELD) |
字段、枚举的常量 |
@Target(ElementType.METHOD) |
方法 |
@Target(ElementType.PARAMETER) |
方法参数 |
@Target(ElementType.CONSTRUCTOR) |
构造函数 |
@Target(ElementType.LOCAL_VARIABLE) |
局部变量 |
@Target(ElementType.ANNOTATION_TYPE) |
注解 |
@Target(ElementType.PACKAGE) |
包 |
@Document
@Inherited
关于注解的反射方法
// 获取某个类型的注解
public <A extends Annotation> AgetAnnotation(Class<A> annotationClass);
// 获取所有注解(包括父类中被Inherited修饰的注解)
public Annotation[] getAnnotations();
// 获取声明的注解(但是不包括父类中被Inherited修饰的注解)
public Annotation[] getDeclaredAnnotations();
// 判断某个对象上是否被某个注解进行标注
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
// 获取某个类声明的所有字段
public Field[] getDeclaredFields() throws SecurityException;
// 获取某个方法
public Method getMethod(String name, Class<?>... parameterTypes);
五种通知
@Before
@After
@After-returning
@After-throwing
@Around
JoinPoint 对象
方法名 |
功能 |
Signature getSignature(); |
获取封装了署名信息的对象,在该对象中可以获取到目标方法名,所属类的Class等信息 |
Object[] getArgs(); |
获取传入目标方法的参数对象 |
Object getTarget(); |
获取被代理的对象 |
Object getThis(); |
获取代理对象 |
实战
- 使用springBoot,需要 添加aop相关的依赖,如下:
<!-- springBoot的aop功能启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
日志
@Interface
import java.lang.annotation.*;
/**
* 定义日志的注解,作用在方法上
* @author 陈加兵
* @since 2018年11月3日 上午11:53:59
*/
@Target({ElementType.PARAMETER, ElementType.METHOD}) //作用在方法上面
@Retention(RetentionPolicy.RUNTIME) //程序运行
@Documented
public @interface InsertLog {
Stringname()default ""; //用户名
Stringoperation()default ""; //操作
}
@Component //注入
@Aspect //切面
public class InsertLogAnnotation{
@Resource
private LogService logService; //日志的service,用来记录日志
/**
* 1、@pointCut:定义切入点,其中支持多种表达式来匹配切入点,这里的annotation是用来匹配注解的
* 2、@annotation的参数必须和这个方法的参数字段相同,因为这里表示的扫描的哪个注解
* 3、这个切入点的 意思:只要被`@InsertLog`这个注解标注的都会被扫描到成为切入点
* @param log 注解的对象
*/
@Pointcut("@annotation(log)")
public void insertLog(InsertLog log){}
/**
* `@AfterReturning`:定义后置通知,只有程序执行成功才会调用该注解,用来添加操作的日志
* `insertLog(log)`: 这里的log一定要和上面定义切入点(@Pointcut)中的参数字段一样
* @param point JoinPoint对象,可以获取一些切面信息,比如调用的类,调用的方法名称
* @param log 该注解的对象,可以获取注解中参数的内容
* @throws Exception
*/
@AfterReturning("insertLog(log)")
public void SystemLog(JoinPoint point,InsertLog log)throws Exception{
//获取注解中的参数内容
String name=log.name(); //姓名
String operation=log.operation(); //操作
Log log2=new Log();
log2.setName(name);
log2.setOperation(operation);
logService.addLog(log2); //添加到日志中
}
- 此时就已经完成了,我们只需要将该注解添加到需要记录日志的方法上即可,如下:
@InsertLog(name="陈加兵",operation="删除用户") //使用日志注解,在程序执行成功之后记录日志
public Object deleteUserById(Integer userId){
System.out.println("删除成功");
return null;
}
性能监控
- 可以定义一个注解实现性能监控,设置一个环绕通知即可,在程序执行开始和结束之后统计时间即可
- 定义一个注解,如下:
import java.lang.annotation.*;
/**
* 性能监控的注解
* @author 陈加兵
* @since 2018年11月3日 下午1:08:30
*/
@Target({ElementType.PARAMETER, ElementType.METHOD}) //作用在方法上面
@Retention(RetentionPolicy.RUNTIME) //程序运行
@Documented
public @interface CapabilityMonitor {
}
/**
* 性能监控注解的实现类
* @author 陈加兵
* @since 2018年11月3日 下午1:09:40
*/
@Aspect //切面
@Component //注入
public class CapabilityMonitorAnnotationImpl{
private Logger logger=LoggerFactory.getLogger(CapabilityMonitorAnnotationImpl.class); //selfj的日志信息
/**
* 定义切入点,只要方法体上有这个注解
* @param capabilityMonitor 注解的对象
*/
@Pointcut("@annotation(capabilityMonitor)")
public void capabilityMonitor(CapabilityMonitor capabilityMonitor){}
/**
* 环绕通知,在方法执行之前和之后都执行
* capabilityMonitor(capabilityMonitor):这里的参数一定要和切入点(`@Pointcut("@annotation(capabilityMonitor)")`)的参数相同
* @param point
* @param capabilityMonitor 注解的对象
* @throws Throwable
*/
@Around("capabilityMonitor(capabilityMonitor)")
public void execute(ProceedingJoinPoint point,CapabilityMonitor capabilityMonitor)throws Throwable{
Long startTime=System.currentTimeMillis(); //开始时间
Object[] args=point.getArgs(); //获取目标方法执行的参数数组
Object returnValues=point.proceed(args); //执行目标方法
Long endTime=System.currentTimeMillis(); //结束时间
logger.info("程序执行的时间:"+((endTime-startTime)/1000.0)); //输出程序执行的时间,秒位单位
}
}
参考文章
原文
https://chenjiabing666.github.io/2018/11/03/java自定义注解/