注解的语法
通过 @interface 声明一个注解
public @interface RequestMapping {
}
注解的属性
public @interface RequestMapping {
String value() default "";
}
属性的数据类型包括:
- 基本数据类型: byte, char, short, int, long, float, double, boolean
- String类型
- Class类型
- enum类型
- Annotation类型
- 以上所有类型的数组
注解的属性定义在语法上类似于接口中的方法, 通过 default 可以设置默认值.
元注解
元注解, 字面上的意思是注解的注解, 就是加在自定义注解上的基础注解. 常用的元注解有以下四种:
(1) @Target
@Target 说明了自定义注解的作用范围, 其取值如下:
- ElementType.TYPE
可以注解类、接口或枚举 - ElementType.FIELD
可以注解属性 - ElementType.METHOD
可以注解方法 - ElementType.PARAMETER
可以注解方法内的参数 - ElementType.CONSTRUCTOR
可以注解构造方法 - ElementType.LOCAL_VARIABLE
可以注解局部变量 - ElementType.ANNOTATION_TYPE
可以对另一个一个注解进行注解
我们可以看下Spring中 @Autowired 注解的定义, 它的 @Target 取值有五种.
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
boolean required() default true;
}
(2) @Retention
@Retention 说明了自定义注解的生命周期, 其取值如下:
- RetentionPolicy.SOURCE
注解只存活在源码阶段, 在编译期会被丢弃. - RetentionPolicy.CLASS
注解只会被保留到编译期, 不会被加载到 JVM 中(在运行期被丢弃). - RetentionPolicy.RUNTIME
注解会被加载到 JVM 中, 在程序运行时可以通过反射获取.
Spring中 @Autowired 注解的生命周期就是到运行期, 可以看到它的取值是 RetentionPolicy.RUNTIME.
(3) @Documented
@Documented 指将自定义注解中的属性包含到 Javadoc 中.
(4) @Inherited
@Inherited 说明了自定义注解可以被继承, 当Son类继承了Father类时, 也会继承Father类的注解.
注解的常用API
注解要通过反射来操作. 在开发中一般通过 Class, Field, Method 这三个对象操作注解.
(1) isAnnotationPresent(Class<? extends Annotation> annotationClass)
判断是否存在某个注解.
(2) getAnnotation(Class annotationClass)
获取某个注解.
(3) getAnnotations()
获取所有注解.
注解实例
我们来手动实现下Spring的 @Autowired 注解(简化版), 也就是Spring的 IOC 功能. 如果不熟悉Java反射可以看下这篇博客: https://blog.csdn.net/litianxiang_kaola/article/details/78634822
(1) 定义注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
}
(2) Service
public class UserService {
public String getUserName(){
return "Tyshawn";
}
}
(3) Controller
public class UserController {
@Autowired
private UserService userService;
public static void main(String[] args) throws IllegalAccessException, InstantiationException {
//定义bean容器, 在Spring中是在应用启动时, 将应用中所有bean实例都存储在bean容器中
Map<Class<?>, Object> beanMap = new HashMap<>();
beanMap.put(UserController.class, UserController.class.newInstance());
beanMap.put(UserService.class, UserService.class.newInstance());
//实现IOC
//遍历bean容器, 如果存在成员变量且带有@Autowired注解, 则为成员变量注入实例
for (Map.Entry<Class<?>, Object> beanEntry : beanMap.entrySet()) {
Class<?> beanClass = beanEntry.getKey();
Object beanInstance = beanEntry.getValue();
//获取bean的成员变量
Field[] beanFields = beanClass.getDeclaredFields();
//遍历bean的成员变量
if (beanFields != null && beanFields.length !=0) {
for (Field beanField : beanFields) {
if (beanField.isAnnotationPresent(Autowired.class)) { //判断是否带Autowired注解
Class<?> beanFieldClass = beanField.getType();
Object beanFieldInstance = beanMap.get(beanFieldClass);
//为成员变量注入实例
beanField.set(beanInstance, beanFieldInstance);
}
}
}
}
//调用Controller里的Service成员变量
UserController userController = (UserController) beanMap.get(UserController.class);
System.out.println(userController.userService.getUserName()); //Tyshawn
}
}