引言
Java 注解(Annotation)又稱 Java 標注,是 JDK5.0 引入的一種注釋機制。
Java 語言中的類、方法、變量、參數和包等都可以被標注。和 Javadoc 不同,Java 標注可以通過反射獲取標注內容。在編譯器生成類文件時,標注可以被嵌入到字節碼中。Java 虛擬機可以保留標注內容,在運行時可以獲取到標注內容 。 當然它也支持自定義 Java 標注。
Spring支持使用注解的方式配置bean和注入屬性依賴關系,可以極大的減少XML配置文件的數量,特別是在Spirng Boot 和 Spring Cloud中,基本上都是使用注解來使用內置和自定義的bean對象,對開發人員而言,減少了繁瑣的配置。
Component派生性
Component源碼
/**
* Indicates that an annotated class is a "component".
* Such classes are considered as candidates for auto-detection
* when using annotation-based configuration and classpath scanning.
*
* <p>Other class-level annotations may be considered as identifying
* a component as well, typically a special kind of component:
* e.g. the {@link Repository @Repository} annotation or AspectJ's
* {@link org.aspectj.lang.annotation.Aspect @Aspect} annotation.
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component {
/**
* The value may indicate a suggestion for a logical component name,
* to be turned into a Spring bean in case of an autodetected component.
* @return the suggested component name, if any (or empty String otherwise)
*/
String value() default "";
}
通過閱讀Component注解我們得知
Component注解是作用於Class類上的,同時它在運行期有效(有一些注解是在編譯時有效,比如一些編譯插件lombak)
@Indexed是Spirng5.0出來的,用於編譯譯處理,加快Spring啟動速度
通過查看其它bean組件注解(Configuration、Controller、Service、Repository等)的源碼,我們發現這些能夠標識bean組件的注解都是被Component注解了的
所以我們可以認為,Configuration等注解實際上都是Component的派生注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
@AliasFor(annotation = Component.class)
String value() default "";
boolean proxyBeanMethods() default true;
}
這是因為Spring在處理這些注解的時候都對標注在注解上的元注解進行了遞歸的處理,所有也就有了Component的派生性
通過這一點我們也可以利用Component的派生性,自定義一個由我們自己命名的注解
自定義基於Component的派生注解
需求:實現一個能夠被spring識別的標注bean組件的注解,被這個注解標注了的bean是單例
實現SingletonComponent
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
//標注bean為單例bean
@Scope("singleton")
@Component
public @interface SingletonComponent {
//讓這里的value值對應到Component中的value值,可以定義bean名稱
@AliasFor(annotation = Component.class, attribute = "value")
String value() default "";
}
使用SingletonComponent
@SingletonComponent("xxstudent")
public class Student {
public Student() {
this.name = "xxxx" + new Random().nextInt();
}
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
'}';
}
}
測試
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Student.class);
Object xx1student = applicationContext.getBean("xxstudent");
if (xx1student instanceof Student) {
Student student = (Student) xx1student;
System.out.println(student);
}
Object xx2student = applicationContext.getBean("xxstudent");
if (xx2student instanceof Student) {
Student student = (Student) xx2student;
System.out.println(student);
}
}
輸出
Student{name='xxxx289881135'}
Student{name='xxxx289881135'}
可以看到:通過名稱已經能夠獲取到bean對象了,同時這個對象也是單例的對象。