使用自定义注解简易模拟Spring中的自动装配@Autowired
我们在学Spring的时候,常常需要配置大量的bean,由Spring进行管理,这就导致配置文件的膨胀,后来使用到@Autowired注解,才发现到注解的强大,那么底层是怎么实现的呢?碍于博主才疏学浅,不能带着大家深入源码进行探讨,今天我们就用自定义注解的方式来模拟一下@Autowired。
一、什么是注解
注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
JDK中自带了几个注解,比如@Override,这是一个标识注解,注解内部没有属性,用来标注此方法是重写方法。还有@Deprecated,同样也是标识注解,用来告知此方法已经过时。如果我们仍然使用此方法,又想消除编译器弹出的过时警告,可以写上@SuppressWarnings("deprecation"),就可以消除警告提示。
二、注解内部属性
以下是示例代码:
package day0829;
import java.lang.annotation.*;
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface TestAnnotation {
String name();
int age() default 18;
}
(1)使用@interface关键字来定义注解
(2)成员变量以无参数无异常的方式声明
(3)可以用default为成员变量指定默认值
(4)成员类型只能是原始数据类型、String、Class、Annotation、Enumeration
(5)注解可以没有成员,没有注解的成员称为标识注解
@Target、@Retention、@Inherited、@Documented等都是元注解。
元注解,即对注解的注解。要会自定义注解,必须了解注解头部的元注解。
(1)@Target,注解的作用域,即此注解应该被用在什么地方
属性名 | 声明地方 |
ElementType.CONSTRUCTOR
| 构造方法 |
ElementType.FIELD
| 字段 |
ElementType.LOCAL_VARIABLE
| 局部变量 |
ElementType.METHOD
| 方法 |
ElementType.PACKAGE
| 包 |
ElementType.PARAMETER
| 参数 |
ElementType.TYPE
| 类、接口 |
(2)@Retention,注解的生命周期,即注解在什么范围内有效
属性名 | 生命周期说明 |
RetentionPolicy.SOURCE
| 只在源码内显示,编译时则丢弃 |
RetentionPolicy.CLASS
| 编译时会记录到class文件中,运行时忽略 |
RetentionPolicy.RUNTIME
| 运行时存在,通过反射读取注解 |
(3)@Inherited,标识注解,允许子类继承
注意:此元注解所在的注解只能在放在类上,放在接口上则不起作用。
(4)@Documented,标识注解,生成javadoc文档时,会包含此注解
那么注解如何解析呢?我们把解析注解的过程放入到案例中来
三、使用自定义注解实现简易的自动装配
注解代码示例:
package day0829;
import java.lang.annotation.*;
//只用在字段上
@Target({ElementType.FIELD})
//运行时有效,这样可以通过反射解析注解
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
int value() default 0;
}
解析注解示例:
package day0829;
import java.lang.reflect.Field;
public class Test {
@TestAnnotation
private static int value;
private int a = 1;
public static void main(String args[]) throws IllegalAccessException {
//获取所有变量
Field[] fields = Test.class.getDeclaredFields();
for (Field field : fields) {
//允许访问私有变量
field.setAccessible(true);
//判断此变量是否使用了注解
boolean isUsedAnnotation = field.isAnnotationPresent(TestAnnotation.class);
if (isUsedAnnotation) {
TestAnnotation annotation = field.getAnnotation(TestAnnotation.class);
//按照指定的注解value,给变量赋值
field.set(annotation, annotation.value());
}
}
//输出变量的值
System.out.println("Test中变量a的值为"+value);
}
}
最后输出:
可见达到了预期的属性装配目的