转载

java自定义注解

  • 表示需要在什么级别保存该注解信息 。分为如下三类:
    @Retention(RetentionPolicy.SOURCE)
    @Retention(RetentionPolicy.CLASS)
    @Retention(RetentionPolicy.RUNTIME)
    

@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

  • 注解包含在javadoc中

@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 "";  //操作
}
  • 定义一个注解的实现类,使用aop实现该注解
@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;
}
  • 完整的项目截图如下:

java自定义注解

性能监控

  • 可以定义一个注解实现性能监控,设置一个环绕通知即可,在程序执行开始和结束之后统计时间即可
  • 定义一个注解,如下:
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));   //输出程序执行的时间,秒位单位
	}
}

参考文章

  • aop的相关知识点
  • spring aop
原文  https://chenjiabing666.github.io/2018/11/03/java自定义注解/
正文到此结束
Loading...