深入分析Spring BeanDefinition的構(gòu)造元信息
Spring BeanDefinition元信息定義方式
Bean Definition
是一個包含Bean
元數(shù)據(jù)的對象。它描述了如何創(chuàng)建Bean
實例、Bean
屬性的值以及Bean
之間的依賴關(guān)系??梢允褂枚喾N方式來定義 Bean Definition 元信息,包括:
- XML 配置文件:使用
<bean>
標(biāo)簽定義 Bean 元數(shù)據(jù),可以指定Bean
類型、屬性值和依賴項等信息。 - 注解:使用
@Component
、@Service
、@Repository
等注解標(biāo)記Bean
類,并使用@Autowired
注解注入依賴項。 - Java 配置類:使用
@Configuration
和@Bean
注解定義Bean
元數(shù)據(jù),可以指定Bean
類型、屬性值和依賴項等信息。
除此之外,還可以通過實現(xiàn) BeanDefinitionRegistryPostProcessor
接口來自定義 Bean Definition
的生成過程。這個接口有一個方法 postProcessBeanDefinitionRegistry()
,允許開發(fā)人員動態(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中,無論是通過XML、注解、Java配置類定義Bean元數(shù)據(jù),最終都是需要轉(zhuǎn)換成BeanDefinition
對象,然后被注冊到Spring容器中。
而BeanDefinition
的創(chuàng)建過程,確實是通過AbstractBeanDefinition
及其派生類、``等一系列工具類實現(xiàn)的。
- 當(dāng)我們使用
XML
配置時,Spring會解析XML
文件,將其中的Bean元數(shù)據(jù)信息轉(zhuǎn)換成對應(yīng)的BeanDefinition
對象,然后注冊到Spring容器中。在這個過程中,Spring內(nèi)部會使用XmlBeanDefinitionReader
等相關(guān)工具類,將XML文件中定義的Bean元數(shù)據(jù)轉(zhuǎn)換成BeanDefinition
對象。 - 當(dāng)我們使用注解方式或Java配置類方式定義Bean元數(shù)據(jù)時,
Spring
會掃描相應(yīng)的注解或Java配置類,然后根據(jù)其定義生成對應(yīng)的BeanDefinition
對象,并注冊到Spring
容器中。在這個過程中,Spring內(nèi)部會使用AnnotationConfigApplicationContext
等相關(guān)工具類,將注解或Java配置類中定義的Bean元數(shù)據(jù)轉(zhuǎn)換成BeanDefinition
對象。
源碼分析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()); } // 實際上從指定的 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(); } } } //實際上從指定的 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
線程級別的變量存儲帶有編碼資源的集合,保證每個線程都可以訪問到XmlBeanDefinitionReader
在加載XML配置文件時當(dāng)前正在加載的資源,以確保加載過程中的完整性和正確性。 - 在
ThreadLocal
中獲取到當(dāng)前正在加載的xml資源,轉(zhuǎn)換為輸入流 - 開始執(zhí)行
doLoadBeanDefinitions
,實際上從指定的 XML 文件加載 Bean 定義,該方法會返回加載的Bean定義數(shù)量。 doLoadBeanDefinitions
方法中,首先調(diào)用doLoadDocument
方法加載XML文件并生成一個Document對象。- 然后,調(diào)用
registerBeanDefinitions
方法來注冊Bean
定義,將其放入Spring容器中。該方法會返回注冊的Bean定義數(shù)量。 - 最后,根據(jù)需要記錄日志信息,并返回加載的Bean定義數(shù)量。
源碼分析配置類、注解是如何轉(zhuǎn)化為Spring BeanDefinition的
在Spring中,配置類和注解都可以被轉(zhuǎn)換為Bean
定義(BeanDefinition
)。下面是關(guān)于如何將配置類和注解轉(zhuǎn)換為Bean
定義的簡要源碼分析:
- 配置類轉(zhuǎn)換為Bean定義:
- 當(dāng)使用Java配置類時,Spring會通過解析配置類中的注解來生成相應(yīng)的Bean定義。主要實現(xiàn)是通過
ConfigurationClassParser
類完成的。 ConfigurationClassParser
會解析配置類上的注解,包括@Configuration
、@ComponentScan
、@Bean
等,然后將其轉(zhuǎn)換為對應(yīng)的Bean
定義。- 在解析過程中,Spring會創(chuàng)建一個
ConfigurationClass
對象表示配置類,并根據(jù)不同的注解類型生成相應(yīng)的Bean
定義,包括RootBeanDefinition
和MethodMetadata
。 RootBeanDefinition
代表配置類本身,而MethodMetadata
代表配置類中的方法上的注解,例如@Bean
注解。- 最終,這些生成的Bean定義會被注冊到
DefaultListableBeanFactory
中,以供后續(xù)的Bean實例化和依賴注入。
- 當(dāng)使用Java配置類時,Spring會通過解析配置類中的注解來生成相應(yīng)的Bean定義。主要實現(xiàn)是通過
- 注解轉(zhuǎn)換為
Bean
定義:
- 當(dāng)使用注解方式配置
Bean
時,Spring會掃描指定的包或類,并解析其中的注解來生成Bean定義。 - Spring提供了
AnnotationBeanDefinitionReader
類用于處理注解,它會掃描指定的包路徑或類,并根據(jù)注解生成相應(yīng)的Bean定義。 - 在掃描過程中,
AnnotationBeanDefinitionReader
會解析常見的注解,比如@Component
、@Controller
、@Service
、@Repository
等,然后生成相應(yīng)的Bean定義。 - 注解生成的Bean定義同樣會被注冊到DefaultListableBeanFactory中,以供后續(xù)的Bean實例化和依賴注入。
- 當(dāng)使用注解方式配置
總而言之,無論是配置類還是注解,Spring都會通過解析注解并生成對應(yīng)的Bean定義,最終將這些Bean定義注冊到DefaultListableBeanFactory
中。這樣,在容器啟動時,Spring就能夠根據(jù)這些Bean
定義來實例化Bean
并進(jìn)行依賴注入。
配置類、注解轉(zhuǎn)換為Spring BeanDefition源碼后續(xù)博客中展示,敬請期待。
如何手動構(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 + ''' + '}'; } }
通過BeanDefinitionBuilder構(gòu)建
//通過BeanDefinitionBuilder構(gòu)建 BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class); //通過屬性設(shè)置 beanDefinitionBuilder.addPropertyValue("id", 1L) .addPropertyValue("name","公眾號:種棵代碼技術(shù)樹"); //獲取BeanDefinition實例 BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition(); // BeanDefinition 并非 Bean 終態(tài),可以自定義修改 System.out.println(beanDefinition);
通過AbstractBeanDefinition以及派生類
// 2. 通過 AbstractBeanDefinition 以及派生類 GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition(); //設(shè)置Bean類型 genericBeanDefinition.setBeanClass(User.class); //通過 MutablePropertyValues 批量操作屬性 MutablePropertyValues propertyValues = new MutablePropertyValues(); propertyValues.add("id",1L) .add("name","公眾號:種棵代碼技術(shù)樹"); // 通過 set MutablePropertyValues 批量操作屬性 genericBeanDefinition.setPropertyValues(propertyValues);
最后
以上就是深入分析Spring BeanDefinition的構(gòu)造元信息的詳細(xì)內(nèi)容,更多關(guān)于Spring BeanDefinition構(gòu)造元信息的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
SpringBoot整合RabbitMQ實現(xiàn)延遲隊列和死信隊列
RabbitMQ的死信隊列用于接收其他隊列中的“死信”消息,所謂“死信”,是指滿足一定條件而無法被消費者正確處理的消息,死信隊列通常與RabbitMQ的延遲隊列一起使用,本文給大家介紹了SpringBoot整合RabbitMQ實現(xiàn)延遲隊列和死信隊列,需要的朋友可以參考下2024-06-06SpringBoot后端接收參數(shù)優(yōu)化代碼示例(統(tǒng)一處理前端參數(shù))
使用Spring Boot開發(fā)API的時候,讀取請求參數(shù)是服務(wù)端編碼中最基本的一項操作,下面這篇文章主要給大家介紹了關(guān)于SpringBoot后端接收參數(shù)優(yōu)化(統(tǒng)一處理前端參數(shù))的相關(guān)資料,需要的朋友可以參考下2024-07-07Spring-Cloud-Function-Spel?漏洞環(huán)境搭建
這篇文章主要介紹了Spring-Cloud-Function-Spel?漏洞復(fù)現(xiàn)及搭建方法,搭建方法也很簡單,首先需要安裝maven jdk,具體安裝過程跟隨小編一起看看吧2022-03-03