深入分析Spring BeanDefinition的構(gòu)造元信息
Spring BeanDefinition元信息定義方式
Bean Definition是一個(gè)包含Bean元數(shù)據(jù)的對(duì)象。它描述了如何創(chuàng)建Bean實(shí)例、Bean屬性的值以及Bean之間的依賴關(guān)系。可以使用多種方式來(lái)定義 Bean Definition 元信息,包括:
- XML 配置文件:使用
<bean>標(biāo)簽定義 Bean 元數(shù)據(jù),可以指定Bean類型、屬性值和依賴項(xiàng)等信息。 - 注解:使用
@Component、@Service、@Repository等注解標(biāo)記Bean類,并使用@Autowired注解注入依賴項(xiàng)。 - Java 配置類:使用
@Configuration和@Bean注解定義Bean元數(shù)據(jù),可以指定Bean類型、屬性值和依賴項(xiàng)等信息。
除此之外,還可以通過(guò)實(shí)現(xiàn) BeanDefinitionRegistryPostProcessor 接口來(lái)自定義 Bean Definition 的生成過(guò)程。這個(gè)接口有一個(gè)方法 postProcessBeanDefinitionRegistry(),允許開(kāi)發(fā)人員動(dòng)態(tài)地添加、修改或刪除Bean Definition元信息。
XML配置文件定義Bean的元數(shù)據(jù)
<bean id="user" class="org.thinging.in.spring.ioc.overview.domain.User"> <property name="id" value="1"/> <property name="name" value="Liutx"/> </bean>
注解定義Bean的元數(shù)據(jù)
@Service(value = "HelloService")
public class HelloService {
private final Logger logger = LoggerFactory.getLogger(HelloService.class);
private final HelloAsyncService helloAsyncService;
public HelloService(HelloAsyncService helloAsyncService) {
this.helloAsyncService = helloAsyncService;
}
}
value = "HelloService" 即為Bean:HelloService的元數(shù)據(jù),在構(gòu)造方法中的依賴關(guān)系同樣屬于元數(shù)據(jù)。
Java 配置類定義Bean的元數(shù)據(jù)
@Component(value = "balanceRedisProcessor")
public class BalanceRedisProcessorService implements EntryHandler<Balance>, Runnable {
@Autowired(required = true)
public BalanceRedisProcessorService(RedisUtils redisUtils,
CanalConfig canalConfig,
@Qualifier("ownThreadPoolExecutor") Executor executor, RocketMQProducer rocketMqProducer) {
this.redisUtils = redisUtils;
this.canalConfig = canalConfig;
this.executor = executor;
this.rocketMQProducer = rocketMqProducer;
}
}
@Component(value = "balanceRedisProcessor") 是Bean:BalanceRedisProcessorService的元數(shù)據(jù),在構(gòu)造方法中的依賴關(guān)系同樣屬于元數(shù)據(jù)。
BeanDefinition的元數(shù)據(jù)解析
在Spring中,無(wú)論是通過(guò)XML、注解、Java配置類定義Bean元數(shù)據(jù),最終都是需要轉(zhuǎn)換成BeanDefinition對(duì)象,然后被注冊(cè)到Spring容器中。
而BeanDefinition的創(chuàng)建過(guò)程,確實(shí)是通過(guò)AbstractBeanDefinition及其派生類、``等一系列工具類實(shí)現(xiàn)的。
- 當(dāng)我們使用
XML配置時(shí),Spring會(huì)解析XML文件,將其中的Bean元數(shù)據(jù)信息轉(zhuǎn)換成對(duì)應(yīng)的BeanDefinition對(duì)象,然后注冊(cè)到Spring容器中。在這個(gè)過(guò)程中,Spring內(nèi)部會(huì)使用XmlBeanDefinitionReader等相關(guān)工具類,將XML文件中定義的Bean元數(shù)據(jù)轉(zhuǎn)換成BeanDefinition對(duì)象。 - 當(dāng)我們使用注解方式或Java配置類方式定義Bean元數(shù)據(jù)時(shí),
Spring會(huì)掃描相應(yīng)的注解或Java配置類,然后根據(jù)其定義生成對(duì)應(yīng)的BeanDefinition對(duì)象,并注冊(cè)到Spring容器中。在這個(gè)過(guò)程中,Spring內(nèi)部會(huì)使用AnnotationConfigApplicationContext等相關(guān)工具類,將注解或Java配置類中定義的Bean元數(shù)據(jù)轉(zhuǎn)換成BeanDefinition對(duì)象。
源碼分析XML是如何轉(zhuǎn)化為Spring BeanDefinition的
將xml文件中的配置轉(zhuǎn)為為BeanDefinition需要依賴自XmlBeanDefinitionReader類中的loadBeanDefinitions方法。
選自:Spring Framework 5.2.20 RELEASE版本的XmlBeanDefinitionReader。
private final ThreadLocal<Set<EncodedResource>> resourcesCurrentlyBeingLoaded =
new NamedThreadLocal<Set<EncodedResource>>("XML bean definition resources currently being loaded"){
@Override
protected Set<EncodedResource> initialValue() {
return new HashSet<>(4);
}
};
/**
* Load bean definitions from the specified XML file.
* @param encodedResource the resource descriptor for the XML file,
* allowing to specify an encoding to use for parsing the file
* @return the number of bean definitions found
* @throws BeanDefinitionStoreException in case of loading or parsing errors
*/
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isTraceEnabled()) {
logger.trace("Loading XML bean definitions from " + encodedResource);
}
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
// 實(shí)際上從指定的 XML 文件加載 Bean 定義
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
//實(shí)際上從指定的 XML 文件加載 Bean 定義
/**
* Actually load bean definitions from the specified XML file.
* @param inputSource the SAX InputSource to read from
* @param resource the resource descriptor for the XML file
* @return the number of bean definitions found
* @throws BeanDefinitionStoreException in case of loading or parsing errors
* @see #doLoadDocument
* @see #registerBeanDefinitions
*/
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
Document doc = doLoadDocument(inputSource, resource);
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}
}
- 使用
ThreadLocal線程級(jí)別的變量存儲(chǔ)帶有編碼資源的集合,保證每個(gè)線程都可以訪問(wèn)到XmlBeanDefinitionReader在加載XML配置文件時(shí)當(dāng)前正在加載的資源,以確保加載過(guò)程中的完整性和正確性。 - 在
ThreadLocal中獲取到當(dāng)前正在加載的xml資源,轉(zhuǎn)換為輸入流 - 開(kāi)始執(zhí)行
doLoadBeanDefinitions,實(shí)際上從指定的 XML 文件加載 Bean 定義,該方法會(huì)返回加載的Bean定義數(shù)量。 doLoadBeanDefinitions方法中,首先調(diào)用doLoadDocument方法加載XML文件并生成一個(gè)Document對(duì)象。- 然后,調(diào)用
registerBeanDefinitions方法來(lái)注冊(cè)Bean定義,將其放入Spring容器中。該方法會(huì)返回注冊(cè)的Bean定義數(shù)量。 - 最后,根據(jù)需要記錄日志信息,并返回加載的Bean定義數(shù)量。
源碼分析配置類、注解是如何轉(zhuǎn)化為Spring BeanDefinition的
在Spring中,配置類和注解都可以被轉(zhuǎn)換為Bean定義(BeanDefinition)。下面是關(guān)于如何將配置類和注解轉(zhuǎn)換為Bean定義的簡(jiǎn)要源碼分析:
- 配置類轉(zhuǎn)換為Bean定義:
- 當(dāng)使用Java配置類時(shí),Spring會(huì)通過(guò)解析配置類中的注解來(lái)生成相應(yīng)的Bean定義。主要實(shí)現(xiàn)是通過(guò)
ConfigurationClassParser類完成的。 ConfigurationClassParser會(huì)解析配置類上的注解,包括@Configuration、@ComponentScan、@Bean等,然后將其轉(zhuǎn)換為對(duì)應(yīng)的Bean定義。- 在解析過(guò)程中,Spring會(huì)創(chuàng)建一個(gè)
ConfigurationClass對(duì)象表示配置類,并根據(jù)不同的注解類型生成相應(yīng)的Bean定義,包括RootBeanDefinition和MethodMetadata。 RootBeanDefinition代表配置類本身,而MethodMetadata代表配置類中的方法上的注解,例如@Bean注解。- 最終,這些生成的Bean定義會(huì)被注冊(cè)到
DefaultListableBeanFactory中,以供后續(xù)的Bean實(shí)例化和依賴注入。
- 當(dāng)使用Java配置類時(shí),Spring會(huì)通過(guò)解析配置類中的注解來(lái)生成相應(yīng)的Bean定義。主要實(shí)現(xiàn)是通過(guò)
- 注解轉(zhuǎn)換為
Bean定義:
- 當(dāng)使用注解方式配置
Bean時(shí),Spring會(huì)掃描指定的包或類,并解析其中的注解來(lái)生成Bean定義。 - Spring提供了
AnnotationBeanDefinitionReader類用于處理注解,它會(huì)掃描指定的包路徑或類,并根據(jù)注解生成相應(yīng)的Bean定義。 - 在掃描過(guò)程中,
AnnotationBeanDefinitionReader會(huì)解析常見(jiàn)的注解,比如@Component、@Controller、@Service、@Repository等,然后生成相應(yīng)的Bean定義。 - 注解生成的Bean定義同樣會(huì)被注冊(cè)到DefaultListableBeanFactory中,以供后續(xù)的Bean實(shí)例化和依賴注入。
- 當(dāng)使用注解方式配置
總而言之,無(wú)論是配置類還是注解,Spring都會(huì)通過(guò)解析注解并生成對(duì)應(yīng)的Bean定義,最終將這些Bean定義注冊(cè)到DefaultListableBeanFactory中。這樣,在容器啟動(dòng)時(shí),Spring就能夠根據(jù)這些Bean定義來(lái)實(shí)例化Bean并進(jìn)行依賴注入。
配置類、注解轉(zhuǎn)換為Spring BeanDefition源碼后續(xù)博客中展示,敬請(qǐng)期待。
如何手動(dòng)構(gòu)造BeanDefinition
Bean定義
public class User {
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + ''' +
'}';
}
}
通過(guò)BeanDefinitionBuilder構(gòu)建
//通過(guò)BeanDefinitionBuilder構(gòu)建
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
//通過(guò)屬性設(shè)置
beanDefinitionBuilder.addPropertyValue("id", 1L)
.addPropertyValue("name","公眾號(hào):種棵代碼技術(shù)樹(shù)");
//獲取BeanDefinition實(shí)例
BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
// BeanDefinition 并非 Bean 終態(tài),可以自定義修改
System.out.println(beanDefinition);
通過(guò)AbstractBeanDefinition以及派生類
// 2. 通過(guò) AbstractBeanDefinition 以及派生類
GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
//設(shè)置Bean類型
genericBeanDefinition.setBeanClass(User.class);
//通過(guò) MutablePropertyValues 批量操作屬性
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("id",1L)
.add("name","公眾號(hào):種棵代碼技術(shù)樹(shù)");
// 通過(guò) set MutablePropertyValues 批量操作屬性
genericBeanDefinition.setPropertyValues(propertyValues);
最后
以上就是深入分析Spring BeanDefinition的構(gòu)造元信息的詳細(xì)內(nèi)容,更多關(guān)于Spring BeanDefinition構(gòu)造元信息的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java中讀取YAML文件配置信息常見(jiàn)問(wèn)題及解決方法
這篇文章主要介紹了Java中讀取YAML文件配置信息常見(jiàn)問(wèn)題及解決方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2025-07-07
SpringBoot整合Security實(shí)現(xiàn)權(quán)限控制框架(案例詳解)
Spring Security是一個(gè)能夠?yàn)榛赟pring的企業(yè)應(yīng)用系統(tǒng)提供聲明式的安全訪問(wèn)控制解決方案的安全框,是一個(gè)重量級(jí)的安全管理框架,本文給大家介紹的非常詳細(xì),需要的朋友參考下吧2021-08-08
SpringBoot使用iText7實(shí)現(xiàn)將HTML轉(zhuǎn)成PDF并添加頁(yè)眉頁(yè)腳水印
這篇文章主要為大家詳細(xì)介紹了SpringBoot使用iText7實(shí)現(xiàn)將HTML轉(zhuǎn)成PDF并添加頁(yè)眉頁(yè)腳水印的相關(guān)知識(shí),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-03-03
mybatis-plus使用xml自定義sql語(yǔ)句方式
這篇文章主要介紹了mybatis-plus使用xml自定義sql語(yǔ)句方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07
關(guān)于SpringBoot微服務(wù)發(fā)布與部署的三種方式
SpringBoot 框架只提供了一套基于可執(zhí)行 jar 包(executable jar)格式的標(biāo)準(zhǔn)發(fā)布形式,但并沒(méi)有對(duì)部署做過(guò)多的界定,而且為了簡(jiǎn)化可執(zhí)行 jar 包的生成,SpringBoot 提供了相應(yīng)的 Maven 項(xiàng)目插件,需要的朋友可以參考下2023-05-05
詳解Spring中@Valid和@Validated注解用法
本文將以新增一個(gè)員工為功能切入點(diǎn),以常規(guī)寫法為背景,慢慢烘托出?@Valid?和?@Validated?注解用法詳解,文中的示例代碼講解詳細(xì),感興趣的可以了解一下2022-07-07
Java中一個(gè)線程執(zhí)行死循環(huán)有什么后果
這篇文章主要為大家詳細(xì)介紹了Java中一個(gè)線程執(zhí)行死循環(huán)有什么后果,當(dāng)一個(gè)線程在執(zhí)行死循環(huán)時(shí)會(huì)影響另外一個(gè)線程嗎,下面為大家揭曉2016-05-05
Java 中 System.load 和 System.loadLibrary&
在Java開(kāi)發(fā)中,有時(shí)候我們需要調(diào)用本地代碼(如 C、C++ 編寫的代碼)來(lái)實(shí)現(xiàn)一些特定的功能,比如提高性能、訪問(wèn)底層硬件等,本文給大家介紹Java中System.load和System.loadLibrary方法使用舉例,感興趣的朋友一起看看吧2025-08-08

