前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >java自定义注解

java自定义注解

作者头像
爱撒谎的男孩
发布2019-12-31 15:47:43
1K0
发布2019-12-31 15:47:43
举报
文章被收录于专栏:码猿技术专栏码猿技术专栏

文章目录

1. 自定义注解【Annotation】

1.1. 元注解

1.1.1. @Retention

1.1.2. @Target

1.1.3. @Document

1.1.4. @Inherited

1.2. 关于注解的反射方法

1.3. 五种通知

1.4. JoinPoint 对象

1.5. 实战

1.5.1. 日志

1.5.2. 性能监控

1.5.3. 输出错误日志到文件中

1.6. 参考文章

自定义注解【Annotation】

元注解

@Retention

  • 表示需要在什么级别保存该注解信息 。分为如下三类:
    • @Retention(RetentionPolicy.SOURCE):注解仅存在于源码中,在class字节码文件中不包含
    • @Retention(RetentionPolicy.CLASS):默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得
    • @Retention(RetentionPolicy.RUNTIME): 注解会在class字节码文件中存在,在运行时可以通过反射获取到

@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

  • 注解可以被继承

关于注解的反射方法

代码语言:javascript
复制
// 获取某个类型的注解
public <A extends Annotation> A getAnnotation(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相关的依赖,如下:
代码语言:javascript
复制
<!-- springBoot的aop功能启动器 -->
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-aop</artifactId>
	</dependency>

日志

  • 实际的生产环境中会对每个都记录日志,比如xxx用户执行了xxx操作,这些日志如果都使用一个方法的话,未免太不雅,此时我们可以定义一个注解,使用spring中的aop,在方法执行成功之后记录日志信息,步骤如下:
  • 定义一个注解,使用@Interface
代码语言:javascript
复制
import java.lang.annotation.*;
/**
 * 定义日志的注解,作用在方法上
 * @author 陈加兵 	
 * @since 2018年11月3日 上午11:53:59
 */
@Target({ElementType.PARAMETER, ElementType.METHOD})  //作用在方法上面
@Retention(RetentionPolicy.RUNTIME)   //程序运行  
@Documented  
public @interface InsertLog {
	String name() default "";   //用户名
	String operation() default "";  //操作
}
  • 定义一个注解的实现类,使用aop实现该注解
代码语言:javascript
复制
@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);  //添加到日志中
		
	}
  • 此时就已经完成了,我们只需要将该注解添加到需要记录日志的方法上即可,如下:
代码语言:javascript
复制
@InsertLog(name="陈加兵",operation="删除用户")  //使用日志注解,在程序执行成功之后记录日志
public Object deleteUserById(Integer userId) {
	System.out.println("删除成功");
	return null;
}
  • 完整的项目截图如下:
注解截图
注解截图

性能监控

  • 可以定义一个注解实现性能监控,设置一个环绕通知即可,在程序执行开始和结束之后统计时间即可
  • 定义一个注解,如下:
代码语言:javascript
复制
import java.lang.annotation.*;

/**
 * 性能监控的注解
 * @author 陈加兵 	
 * @since 2018年11月3日 下午1:08:30
 */
@Target({ElementType.PARAMETER, ElementType.METHOD})  //作用在方法上面
@Retention(RetentionPolicy.RUNTIME)   //程序运行  
@Documented
public @interface CapabilityMonitor {
}
  • 定义注解的实现类,使用切面的环绕通知
代码语言:javascript
复制
/**
 * 性能监控注解的实现类
 * @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));   //输出程序执行的时间,秒位单位
	}
}

输出错误日志到文件中

  • 定义日志注解,如下:
代码语言:javascript
复制
/**
 * 输出日志信息到日志文件的注解
 * @author 陈加兵 	
 * @since 2018年11月7日 下午5:52:55
 */
@Target({ElementType.PARAMETER, ElementType.METHOD})  //作用在方法上面
@Retention(RetentionPolicy.RUNTIME)   //程序运行  
@Documented
public @interface PrintLog {
}
  • 注解的实现类,结合aop实现
代码语言:javascript
复制
@Component
@Aspect
public class PrintLogAnnotationImpl {
	
	/**
	 * 定义切入点,凡是方法体上标注@PrintLog这个注解都会被增强
	 * @param printLog
	 */
	@Pointcut("@annotation(printLog)")
	public void printLog(PrintLog printLog){}
	
	/**
	 * 在程序之后执行并且在出现异常的时候才会执行
	 * @param point  JoinPoint对象,用于获取切入点的信息,比如被增加的类,被增强的方法名称、方法传入的参数等信息
	 * @param printLog  注解的接口信息,可以获取接口的信息
	 * @param message   异常信息
	 */
	@AfterThrowing(value="printLog(printLog)",throwing="message")
	public void excute(JoinPoint point,PrintLog printLog,Throwable message){
		Class targetCls=point.getTarget().getClass();  //获取目标类
		Logger logger = LoggerFactory.getLogger(targetCls);
		logger.error("异常信息:",message);
	}
}
  • 只需要在方法上标注这个注解,只要是遇到异常信息,就会自动写入日志文件中

参考文章

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-11-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 自定义注解【Annotation】
    • 元注解
      • @Retention
      • @Target
      • @Document
      • @Inherited
    • 关于注解的反射方法
      • 五种通知
        • JoinPoint 对象
          • 实战
            • 日志
            • 性能监控
            • 输出错误日志到文件中
          • 参考文章
          相关产品与服务
          应用性能监控
          应用性能监控(Application Performance Management,APM)是一款应用性能管理平台,基于实时多语言应用探针全量采集技术,为您提供分布式性能分析和故障自检能力。APM 协助您在复杂的业务系统里快速定位性能问题,降低 MTTR(平均故障恢复时间),实时了解并追踪应用性能,提升用户体验。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档