1、注解
注解英文称 Annotaion,是Java从1.5开始支持加入源码的特殊语法元数据,作为程序的元数据嵌入到程序当中。注解实现有一个重要的接口Annotation接口,利用@interface关键字,将所有使用该关键字的注解类都实现Annotation接口。Annontation像一种修饰符一样,应用于包、类型、构造方法、方法、成员变量、参数及本地变量的声明语句中。
2、优点
使用注解的好处:
1、帮助代码编译检查
2、提高代码的识别度,比如 @override @Deprecated
3、减少重复代码,简化代码
4、根据注解生成帮助文档,如 @Decument 等
3、元注解
基本语法:
@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface AnnotationName{ }
元注解就是注解的注解,用来描述注解的。
-
@Retention 定义该注解的生命周期
- RetentionPolicy.SOURCE :作用于源码阶段,比如常见的 @Override, @SuppressWarnings;
- RetentionPolicy.CLASS :作用于字节码阶段
- RetentionPolicy.RUNTIME :作用于运行阶段
-
@Target 定义该注解的作用范围
- ElementType.TYPE :用于注解到类,接口、枚举类
- ElementType.FIELD:字段,包括枚举类常量
- ElementType.METHOD:方法声明
- ElementType.PARAMETER:参数声明
- ElementType.CONSTRUCTOR:构造器声明
- ElementType.LOCAL_VARIABLE :局部变量声明
- ElementType.ANNOTATION_TYPE :用于注解声明,即注解的注解,元注解
- ElementType.PACKAGE :包声明
-
其他注解
- @Document 注解将生成到javadoc中
- @Deprecated 表示过时的类
- @Inherited 是否允许子类继承该注解
- @SuppressWarnings 编译器忽略掉无法识别的警告名
- @Override 标注的方法重载了父类的方法
4、自定义注解
import java.lang.annotation.*; /** * 打印出操作日志 * @author * @create 2019/11/4 */ //定义该注解的作用范围 @Target({ElementType.TYPE, ElementType.METHOD}) //定义该注解的生命周期 @Retention(RetentionPolicy.RUNTIME) //注解将生成到javadoc中 @Documented public @interface SystemLog { /** * 日志内容 * @return */ String message() default ""; }
注意:规定注解里面只能使用java基本数据类型和String、enum、Annotation、class
5、自定义注解示例
1> 定义注解接口
import java.lang.annotation.*; /** * 打印出操作日志 * @author * @create 2019/11/4 */ //定义该注解的作用范围 @Target({ElementType.TYPE, ElementType.METHOD}) //定义该注解的生命周期 @Retention(RetentionPolicy.RUNTIME) //注解将生成到javadoc中 @Documented public @interface SystemLog { /** * 日志内容 * @return */ String message() default ""; }
2>实现接口,
import com.example.shiro.config.SystemLog; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.*; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import java.lang.reflect.Method; /** * 日志拦截 * @author * @create 2019/11/4 */ @Slf4j //使用order属性,设置该类在spring容器中的加载顺序 @Order(10) //作用是把当前类标识为一个切面供容器读取 @Aspect //把普通类实例化到spring容器中 @Component public class OuterServiceAop { @Pointcut("@annotation(com.example.shiro.config.SystemLog)") public void serviceAop(){} @Before("serviceAop()") public void doBefore(JoinPoint joinPoint) { log.info("前置通知"); } @After("serviceAop()") public void doAfter(JoinPoint joinPoint) { log.info("后置通知"); } @AfterReturning(pointcut = "serviceAop()", returning = "res") public void doAfterReturning(JoinPoint joinPoint, Object res) { log.info("日志返回通知"); //请求方法 String method = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName(); log.info("method:"+ method); //日志描述 MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method1 = signature.getMethod(); SystemLog annotation = method1.getAnnotation(SystemLog.class); String message = annotation.message(); log.info(message); } @AfterThrowing(pointcut = "serviceAop()", throwing = "e") public void doAfterThrowing(JoinPoint joinPoint, Throwable e) { log.info("异常通知"); log.info("异常信息:" + e.getMessage()); } }
3>在需要的类或方法中增加注解
import com.example.shiro.config.SystemLog; import com.example.shiro.entity.User; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.subject.Subject; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.example.shiro.common.BaseController; /** * <p> * 前端控制器 * </p> * * @author * @since 2019-11-01 */ @RestController @RequestMapping("/user") public class UserController extends BaseController { @PostMapping("/login") @SystemLog(message = "用户登录") public String login(User user) { ... } }
4>效果