您好,登錄后才能下訂單哦!
這篇文章主要講解了“Spring中的BeanDefinition是什么”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Spring中的BeanDefinition是什么”吧!
在 Spring 容器中,我們廣泛使用的是一個一個的 Bean,BeanDefinition 從名字上就可以看出是關于 Bean 的定義。
事實上就是這樣,我們在 XML 文件中配置的 Bean 的各種屬性,這些屬性不僅僅是和對象相關,Spring 容器還要解決 Bean 的生命周期、銷毀、初始化等等各種操作,我們定義的關于 Bean 的生命周期、銷毀、初始化等操作總得有一個對象來承載,那么這個對象就是 BeanDefinition。
XML 中定義的各種屬性都會先加載到 BeanDefinition 上,然后通過 BeanDefinition 來生成一個 Bean,從這個角度來說,BeanDefinition 和 Bean 的關系有點類似于類和對象的關系。
要理解 BeanDefinition,我們從 BeanDefinition 的繼承關系開始看起。
BeanDefinition 是一個接口,繼承自 BeanMetadataElement 和 AttributeAccessor 接口。
我們來看下 AttributeAccessor:
public interface AttributeAccessor {
void setAttribute(String name, @Nullable Object value);
@Nullable
Object getAttribute(String name);
@Nullable
Object removeAttribute(String name);
boolean hasAttribute(String name);
String[] attributeNames();
}
這里定義了元數據的訪問接口,具體的實現則是 AttributeAccessorSupport,這些數據采用 LinkedHashMap 進行存儲。
這是 BeanDefinition 所繼承的兩個接口。接下來我們來看下 BeanDefinition 接口:
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
int ROLE_APPLICATION = 0;
int ROLE_SUPPORT = 1;
int ROLE_INFRASTRUCTURE = 2;
void setParentName(@Nullable String parentName);
@Nullable
String getParentName();
void setBeanClassName(@Nullable String beanClassName);
@Nullable
String getBeanClassName();
void setScope(@Nullable String scope);
@Nullable
String getScope();
void setLazyInit(boolean lazyInit);
boolean isLazyInit();
void setDependsOn(@Nullable String... dependsOn);
@Nullable
String[] getDependsOn();
void setAutowireCandidate(boolean autowireCandidate);
boolean isAutowireCandidate();
void setPrimary(boolean primary);
boolean isPrimary();
void setFactoryBeanName(@Nullable String factoryBeanName);
@Nullable
String getFactoryBeanName();
void setFactoryMethodName(@Nullable String factoryMethodName);
@Nullable
String getFactoryMethodName();
ConstructorArgumentValues getConstructorArgumentValues();
default boolean hasConstructorArgumentValues() {
return !getConstructorArgumentValues().isEmpty();
}
MutablePropertyValues getPropertyValues();
default boolean hasPropertyValues() {
return !getPropertyValues().isEmpty();
}
void setInitMethodName(@Nullable String initMethodName);
@Nullable
String getInitMethodName();
void setDestroyMethodName(@Nullable String destroyMethodName);
@Nullable
String getDestroyMethodName();
void setRole(int role);
int getRole();
void setDescription(@Nullable String description);
@Nullable
String getDescription();
ResolvableType getResolvableType();
boolean isSingleton();
boolean isPrototype();
boolean isAbstract();
@Nullable
String getResourceDescription();
@Nullable
BeanDefinition getOriginatingBeanDefinition();
}
BeanDefinition 中的方法雖然多,但是結合我們平時在 XML 中的配置,這些方法其實都很好理解:
<bean parent="">
配置。<bean class="">
配置。<bean lazy-init="">
配置。<bean depends-on="">
配置。<bean autowire-candidate="">
配置。<bean primary="">
配置。<bean factory-bean="">
配置。<bean factory-method="">
配置,不再贅述。這個就是 BeanDefinition 的定義以及它里邊方法的含義。
上面只是 BeanDefinition 接口的定義,BeanDefinition 還擁有諸多實現類,我們也來大致了解下。
先來看一張繼承關系圖:
這么多實現類看著有點眼花繚亂,不過搞清楚了每一個接口和類的作用,再看就很容易了。
AbstractBeanDefinition 是一個抽象類,它根據 BeanDefinition 中定義的接口提供了相應的屬性,并實現了 BeanDefinition 中定義的一部分方法。BeanDefinition 中原本只是定義了一系列的 get/set 方法,并沒有提供對應的屬性,在 AbstractBeanDefinition 中將所有的屬性定義出來了。
后面其他的實現類也基本上都是在 AbstractBeanDefinition 的基礎上完成的。
這是一個比較常用的實現類,對應了一般的元素標簽。
可以讓子 BeanDefinition 定義擁有從父 BeanDefinition 那里繼承配置的能力。
GenericBeanDefinition 是從 Spring2.5 以后新加入的 BeanDefinition 實現類。GenericBeanDefinition 可以動態設置父 Bean,同時兼具 RootBeanDefinition 和 ChildBeanDefinition 的功能。
表示注解類型 BeanDefinition,擁有獲取注解元數據和方法元數據的能力。
使用了 @Configuration 注解標記配置類會解析為 AnnotatedGenericBeanDefinition。
理論講了這么多,接下來我們通過幾行代碼來實踐下,驗證一下我們前面所說的對不對。
首先項目中添加 spring-context 依賴,如下:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
然后我們來創建一個 User 類,如下:
public class User {
private String username;
private String address;
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", address='" + address + '\'' +
'}';
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
接下來我們先來驗證 RootBeanDefinition。我們自己純手工定義一個 RootBeanDefinition,并且將之注冊到 Spring 容器中去。
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.add("username", "javaboy");
pvs.add("address", "www.javaboy.org");
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(User.class, null, pvs);
ctx.registerBeanDefinition("user",rootBeanDefinition);
ctx.refresh();
User bean = ctx.getBean(User.class);
System.out.println(bean);
MutablePropertyValues 是定義對象中的一個一個屬性,構造 RootBeanDefinition 的時候,我們傳入了類名稱和屬性集合,最終把 rootBeanDefinition 注冊到容器中去。剩下的事情由容器完成,然后我們就可以從容器中獲取到 User 對象了。
最終輸出結果如下:
User{username='javaboy', address='www.javaboy.org'}
看了這個例子,小伙伴們應該能夠大致明白,我們在 XML 中定義的各種屬性,就是先被解析到 BeanDefinition 中,然后再注冊到 Spring 容器中去,最后拿到我們需要的 Bean。
ChildBeanDefinition 具有從父 Bean 繼承數據的能力,我們來看下這個怎么用。
首先新建一個 Person 類,Person 類在 User 類的基礎上增加一個 nickname 屬性,這樣 Person 就可以繼承到 User 的 username 和 address 兩個屬性的值了:
public class Person {
private String username;
private String address;
private String nickname;
@Override
public String toString() {
return "Person{" +
"username='" + username + '\'' +
", address='" + address + '\'' +
", nickname='" + nickname + '\'' +
'}';
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
}
接下來自定義 ChildBeanDefinition:
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.add("username", "javaboy");
pvs.add("address", "www.javaboy.org");
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(User.class, null, pvs);
ctx.registerBeanDefinition("user",rootBeanDefinition);
ChildBeanDefinition childBeanDefinition = new ChildBeanDefinition("user");
childBeanDefinition.setBeanClass(Person.class);
childBeanDefinition.getPropertyValues().add("nickname", "江南一點雨");
ctx.registerBeanDefinition("person", childBeanDefinition);
ctx.refresh();
User user = ctx.getBean(User.class);
Person person = ctx.getBean(Person.class);
System.out.println("user = " + user);
System.out.println("person = " + person);
首先定義 RootBeanDefinition 并注冊到 Spring 容器中,然后再定義 ChildBeanDefinition,ChildBeanDefinition 繼承了 RootBeanDefinition 中現有的屬性值。
最后我們從 Spring 容器中獲取 User 和 Person,打印結果如下:
user = User{username='javaboy', address='www.javaboy.org'}
person = Person{username='javaboy', address='www.javaboy.org', nickname='江南一點雨'}
可以看到,Person 確實繼承了 User 的屬性值。
RootBeanDefinition 和 ChildBeanDefinition 都可以被 GenericBeanDefinition 代替,效果一樣,如下:
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.add("username", "javaboy");
pvs.add("address", "www.javaboy.org");
GenericBeanDefinition rootBeanDefinition = new GenericBeanDefinition();
rootBeanDefinition.setBeanClass(User.class);
rootBeanDefinition.setPropertyValues(pvs);
ctx.registerBeanDefinition("user",rootBeanDefinition);
GenericBeanDefinition childBeanDefinition = new GenericBeanDefinition();
childBeanDefinition.setParentName("user");
childBeanDefinition.setBeanClass(Person.class);
childBeanDefinition.getPropertyValues().add("nickname", "江南一點雨");
ctx.registerBeanDefinition("person", childBeanDefinition);
ctx.refresh();
User user = ctx.getBean(User.class);
Person person = ctx.getBean(Person.class);
System.out.println("user = " + user);
System.out.println("person = " + person);
運行結果如下:
user = User{username='javaboy', address='www.javaboy.org'}
person = Person{username='javaboy', address='www.javaboy.org', nickname='江南一點雨'}
可以看到,和前面的運行效果一致。
在我們本系列前面文章(Spring 源碼第一篇開整!配置文件是怎么加載的?)的案例中,默認使用的也是 GenericBeanDefinition,如下:
現在 Spring Boot 廣泛流行之后,Java 配置使用越來越多,以 @Configuration 注解標記配置類會被解析為 AnnotatedGenericBeanDefinition;以 @Bean 注解標記的 Bean 會被解析為 ConfigurationClassBeanDefinition。
我們新建一個 MyConfig 配置類,如下:
@Configuration
public class MyConfig {
@Bean
User user() {
return new User();
}
}
查看獲取到的 BeanDefinition 結果如下:
而其他 @Service、@Controller、@Repository 以及 @Component 等注解標記的 Bean 則會被識別為 ScannedGenericBeanDefinition。
感謝各位的閱讀,以上就是“Spring中的BeanDefinition是什么”的內容了,經過本文的學習后,相信大家對Spring中的BeanDefinition是什么這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。