Annotation
- 注解不是程序本身,但是可以对程序做出解释
- 注解可以被其他程序(比如:编译器)读取
Java注解分类
-
基本注解
-
@Override 重写@SuppressWarnings(value = "unchecked") 压制编辑器警告
-
-
元注解
-
自定义注解
元注解
元注解的作用就是负责注解其他注解
- @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) //包
- 注:可以指定多个位置,例如:
@Target({ElementType.METHOD, ElementType.TYPE}),也就是此注解可以在方法和类上面使用
- @Retention:描述注解的生命周期,表示在什么级别保存该注解的信息(3个取值:SOURCE<CLASS<RUNTIME)
- @Retention:定义注解的保留策略
- @Retention(RetentionPolicy.SOURCE) //注解仅存在于源码中,在class字节码文件中不包含
- @Retention(RetentionPolicy.CLASS) //默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得,
- @Retention(RetentionPolicy.RUNTIME) //注解会在class字节码文件中存在,在运行时可以通过反射获取到
- @Document:说明该注解可以被生成在Javadoc中
- @Inherited:指定被修饰的Annotation将具有继承性,说明子类可以继承父类中的该注解
其中最重要的
@Retention(RetentionPolicy.RUNTIME)
@Target:指定被修饰的Annotation可以放置的位置(被修饰的目标)
自定义注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@MyAnnotation(name = "张三")
class Demo {@MyAnnotation(name = "张三", age = 100)public static void main(String[] args) {}
}// @Target:描述该注解可以在什么地方使用
@Target({ElementType.TYPE, ElementType.METHOD})
// @Retention:描述注解的生命周期,该注解在哪个基表生效(3个取值:SOURCE<CLASS<RUNTIME)
@Retention(RetentionPolicy.RUNTIME)
// 定义一个注解
@interface MyAnnotation {String name();int age() default 1;
}
项目中spring集成自定义注解实现日志记录功能
1、自定义注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** 1、自定义注解*/
@Target(ElementType.METHOD) // 在方法上
@Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到
public @interface PrintLog {String desc();String name() default "张三";
}
2、定义切面类
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;import java.util.Arrays;
import java.util.List;/*** 2、定义切面类*/
@Component
@Aspect
public class MyLogAspect {/*** 只要用到了com.javaxl.p2.annotation.springAop.MyLog这个注解的,就是目标类*/@Pointcut("@annotation(com.nankang.institution.ann.PrintLog)")private void MyValid() {}@Around("MyValid()")public void around(ProceedingJoinPoint pjp) throws Throwable {try {System.out.println("==================1、切面类环绕通知开始==================");Object proceed = pjp.proceed();System.out.println("5、执行方式,这里是方法返回的数据" + proceed);System.out.println("==================6、环绕通知结束==================");} catch (Exception e) {System.out.println("==================切面类环绕通知异常==================");} finally {System.out.println("==================7、切面类环绕通知异常finally==================");}}@Before("MyValid()")public void before(JoinPoint joinPoint) {System.out.println("==================2.1、切面类前置通知开始==================");MethodSignature signature = (MethodSignature) joinPoint.getSignature();System.out.println("2.2、获取签名信息=>获取当前方法名" + signature.getName());PrintLog printLog = signature.getMethod().getAnnotation(PrintLog.class);//System.out.println("连接点方法为:" + signature.getName() + ",参数为:" + joinPoint.getArgs() );System.out.println("2.3、获取自定义注解信息=》" + printLog.desc());System.out.println("==================2.4、切面类前置通知结束==================");}@After("MyValid()")public void after() {System.out.println("==================4、切面类这是最终通知==================");}@AfterReturning("MyValid()")public void afterReturning(JoinPoint joinPoint) {System.out.println("==================3、切面类后置通知==================");}/*通过throwing属性指定连接点方法出现异常信息存储在ex变量中,在异常通知方法中就可以从ex变量中获取异常信息了*/@AfterThrowing(value="MyValid()",throwing="ex")public void afterReturning(JoinPoint point, Exception ex){String methodName = point.getSignature().getName();List<Object> args = Arrays.asList(point.getArgs());System.out.println("连接点方法为:" + methodName + ",参数为:" + args + ",异常为:" + ex);//连接点方法为:issue,参数为:[{oldhouseid=111 dwell=[]}}],异常为:java.lang.RuntimeException: 123System.out.println("==================异常通知,在目标方法抛出异常后执行==================");}}
3、定义目标方法
@PostMapping("/issue")
@PrintLog(desc = "这是打印日志描述")
public Object issue(@RequestBody Map<String,Object> param) throws Exception {//if(true){// throw new RuntimeException("123");//}System.out.println("================================这是方法中打印的数据================================");return "这是方法中返回的数据";
}
4、调用后返回数据
==================1、切面类环绕通知开始==================
==================2.1、切面类前置通知开始==================
2.2、获取签名信息=>获取当前方法名issue
2.3、获取自定义注解信息=》这是打印日志描述
==================2.4、切面类前置通知结束==================
================================这是方法中打印的数据================================
==================3、切面类后置通知==================
==================4、切面类这是最终通知==================
5、执行方式,这里是方法返回的数据这是方法中返回的数据
==================6、环绕通知结束==================
==================7、切面类环绕通知异常finally==================