java注解概述
Java 注解用于为 Java 代码提供元数据。作为元数据,注解不直接影响你的代码执行,但也有一些类型的注解实际上可以用于这一目的。Java 注解是从 Java5 开始添加到 Java 的。
java中常见的注解
- @Override 表示方法打算重写抽象类或接口里的方法声明,如果方法有此注解但没有重写方法,则编译器会报错。
- @Deprecated 注释的程序元素,不鼓励程序员使用这样的元素,通常是因为它已经过时了,编译器会发出警告。
- @SuppressWarnings(“deprecation”) 指示程序取消指定的编译器警告。如取消@Deprecated 产生的警告。
- @Autowired
- @Service
- @Repository
注解分类
- 按运行机制分:源码注解、编译时注解、运行时注解
- 按来源分:JDK的注解、第三方的注解、自定义注解
- 元注解(注解的注解)
源码注解:注解只在源码中存在,编译成.class文件就不存在了。
编译时注解:注解在源码和.class文件中都存在(例如JDK注解:@Override、@Deprecated、@Suppvisewarnings)。
运行时注解:运行阶段还起作用,甚至会影响运行逻辑的注解(例如:Spirng提供的@Autowired注解,程序运行时,把成员变量自动注入)。
自定义注解
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Description {
String desc();
String author();
int age() default 18;
}
@Target 表示注解作用域
public enum ElementType {
TYPE,//用于描述类、接口(包括注解类型) 或enum声明
FIELD, //用于描述成员变量;
METHOD,//用于描述方法
PARAMETER,//用于描述参数
CONSTRUCTOR,//用于描述构造器
LOCAL_VARIABLE,//用于描述局部变量;
ANNOTATION_TYPE,//注解类型声明 该注解可用于描述注解
PACKAGE,//用于描述包
TYPE_PARAMETER,//这个是jdk1.8后加入的类型 表示这个 Annotation 可以用在 Type 的声明式前
TYPE_USE//表示这个 Annotation 可以用在所有使用 Type 的地方(如:泛型,类型转换等)
}
@Retention 表示注解生命周期
public enum RetentionPolicy {
SOURCE,//表示描述程序编译时
CLASS,//在class文件中有效(即class保留
RUNTIME//在运行时有效(即运行时保留)
}
@Inherited 允许子类继承。如果在父类上标识该注解,解析一个子类,子类也可以获取该注解
@Documented 生成javadoc时会包含注解
补充:1、注解成员类型是受限的,合法的类型包括原始类型及String、Class、Annotation、Enumeration
2、如果注解只有一个成员,则成员名必须取名为value(),
基于反射解析注解
@Description("I am interface")
public class Person {
@Description("I am interface method")
public String name() {
return null;
}
}
解析步骤:
- 使用类加载器加载类
Class c=Class.forName("com.ann.test.Child");
- 找到类上面的注解
boolean isExist=c.isAnnotationPresent(Description.class);
- 获取类上自定义注解实例,需要强制类型转换。
Description d=(Description)c.getAnnotation(Description.class);
- 获取方法上的注解,首先,遍历所有方法,通过方法对象的isAnnotation查看是否有自定义注解,如果存在则输出方法的自定义注解的信息。
实战-自定义注解实现token验证
注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IgnoreToken {
}
AOP
@Component
@Aspect
public class TokenAspect {
@Autowired
private HttpServletRequest request;
@Autowired
private HttpServletResponse response;
@Autowired
private AnnotationController controller;
@Pointcut("within(com.timing.controller..*)")
public void checkToken () {}
/**
* 拦截请求,判断是否带有token
* @param joinPoint
* @throws IOException
*/
@Before("checkToken()")
public void checkToken (JoinPoint joinPoint) throws IOException {
MethodSignature signature = (MethodSignature)joinPoint.getSignature();
//获取当前访问的类方法
Method targetMethod = signature.getMethod();
//判断是否是注解修饰的类,如果是则不需要校验token
if(!targetMethod.isAnnotationPresent(IgnoreToken.class)){
String token = request.getParameter("token");
if (StringUtils.isEmpty(token)) {
response.setCharacterEncoding("utf-8");
response.setContentType("application/json; charset=utf-8");
PrintWriter out = response.getWriter();
out.print("token不能为空");
out.flush();
out.close();
} else {
if (!controller.checkToken(token)) {
response.setCharacterEncoding("utf-8");
response.setContentType("application/json; charset=utf-8");
PrintWriter out = response.getWriter();
out.print("token不合法");
out.flush();
out.close();
}
}
}
}
}
Controller
@RestController
@RequestMapping(value = "/annotation")
public class AnnotationController {
public static Map<String,String> map = new HashMap<>();
public static List<String> logList = new ArrayList<>();
public static Set<String> tokenSet = new HashSet<>();
@RequestMapping(value = "login")
@IgnoreToken
@Log
public String login(String userName,String password) {
map.put(userName,password);
//保存token
tokenSet.add(userName+password);
//返回token
return userName+password;
}
@RequestMapping(value = "query")
@Log(name = "获取密码")
public String getPassword(String userName) {
//获取用户密码
return map.get(userName);
}
@RequestMapping(value = "logs")
@Log(name = "获取日志信息")
public String getLogMap() {
return new Gson().toJson(logList);
}
/**
* 验证token合法性
* @param token
* @return
*/
public boolean checkToken(String token) {
//TOTO:根据实际需求来
return true;
}
}