相關背景及資源:html
曹工說Spring Boot源碼系列開講了(1)-- Bean Definition究竟是什麼,附spring思惟導圖分享java
工程結構圖:spring
選擇bean definition實現類,並實例化bean definition框架
get bean查看是否workide
此次,先說目的:咱們要經過代碼方式手動生成bean definition並註冊到bean factory。函數
個人思路是這樣的,既然前面兩節,分析了bean definition接口中的各個方法,也算對其有了基本的瞭解了。但spring-boot
org.springframework.beans.factory.config.BeanDefinition
只是一個接口,接口是不能實例化的,也無從談起註冊了。ui
咱們從bean definition的實現類中選一個吧:this
非抽象的實現類主要有如下三個:
org.springframework.beans.factory.support.GenericBeanDefinition
:幸運兒,被咱們選中的,也是官方推薦的,註釋裏提到能夠動態設置GenericBeanDefinition
的parent bean definition的名稱;
這個呢,org.springframework.beans.factory.support.RootBeanDefinition
和org.springframework.beans.factory.support.ChildBeanDefinition
也能實現bean的繼承關係,可是可能這種預先定義一個bean爲child/parent
的方式,太死了。
官方本身在ChildBeanDefinition
的註釋裏寫到:
NOTE: Since Spring 2.5, the preferred way to register bean definitions programmatically is the {@link GenericBeanDefinition} class, which allows to dynamically define parent dependencies through the* {@link GenericBeanDefinition#setParentName} method. This effectively supersedes the ChildBeanDefinition class for most use cases.
注意最後那句話,supresede這個單詞我還他麼不太認識,專門查了下詞典,意思是取代、代替
,那這句話意
思就是,大部分時候,GenericBeanDefinition
取代了ChildBeanDefinition
的做用。
這個下面有兩個子類,以前也提過,主要是供那種經過註解方式,好比@controller
這種掃描進來的bean definition。
org.springframework.beans.factory.support.ChildBeanDefinition
,官方都不建議用了,直接跳過吧;
org.springframework.beans.factory.support.RootBeanDefinition
,在@configuration
中有用,後面再講
基於上面的思路,咱們選了GenericBeanDefinition
,這個類能夠直接new,new了以後再經過set方法設置beanClassName等。
public class GenericBeanDefinition extends AbstractBeanDefinition { private String parentName; /** * 無參構造函數,可是你看到下面那一堆set方法了吧,就是讓你本身設 * Create a new GenericBeanDefinition, to be configured through its bean * properties and configuration methods. * @see #setBeanClass * @see #setBeanClassName * @see #setScope * @see #setAutowireMode * @see #setDependencyCheck * @see #setConstructorArgumentValues * @see #setPropertyValues */ public GenericBeanDefinition() { super(); } }
還有一個方式是,咱們看看框架裏怎麼用的,通過我一番搜索,
發現框架裏,主要使用了org.springframework.beans.factory.support.BeanDefinitionBuilder
和
org.springframework.beans.factory.support.BeanDefinitionReaderUtils
,並且,框架裏,仍是前者用的多,也比較方便(後面有示例代碼)。
而後,知道怎麼構造GenericBeanDefinition
了,那麼要怎麼註冊呢,這個也簡單,咱們看看beanFactory
,
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable
不僅實現了ConfigurableListableBeanFactory
,還實現了BeanDefinitionRegistry
。
public interface BeanDefinitionRegistry extends AliasRegistry { /** * 註冊beanDefinition,要本身指定beanName * Register a new bean definition with this registry. * Must support RootBeanDefinition and ChildBeanDefinition. * @param beanName the name of the bean instance to register * @param beanDefinition definition of the bean instance to register * @throws BeanDefinitionStoreException if the BeanDefinition is invalid * or if there is already a BeanDefinition for the specified bean name * (and we are not allowed to override it) * @see RootBeanDefinition * @see ChildBeanDefinition */ void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException; ... }
因此,咱們只要調用org.springframework.beans.factory.support.DefaultListableBeanFactory
的註冊方法便可。
這裏說下beanNameGenerator
,一開始我用的org.springframework.beans.factory.support.DefaultBeanNameGenerator
,結果生成的bean的名稱是這樣的:
org.springframework.simple.TestService#0
,這和咱們平時使用autowired方式,生成的beanName不同啊,不習慣。因而改爲了org.springframework.context.annotation.AnnotationBeanNameGenerator
,就對了!
這裏先介紹兩種方式,分別是構造器注入和property注入。對了,先不要和我提什麼autowired
哈,那個是自動,這個呢,手動。也許,後面你會更懂autowired
,也更懂自動。
核心代碼:
@ToString public class TestControllerByConstructor { TestService testService; /** * 基本類型依賴 */ private String name; public TestControllerByConstructor(TestService testService, String name) { this.testService = testService; this.name = name; } public TestService getTestService() { return testService; } public String getName() { return name; } }
package org.springframework.simple; import lombok.ToString; @ToString public class TestService implements ITestService{ }
/** * 2. 構造bean definition,並在bean definition中表達bean之間的依賴關係 */ GenericBeanDefinition iTestServiceBeanDefinition = (GenericBeanDefinition) BeanDefinitionBuilder .genericBeanDefinition(TestService.class).getBeanDefinition(); log.info("iTestServiceBeanDefinition:{}",iTestServiceBeanDefinition); GenericBeanDefinition iTestControllerBeanDefinition = (GenericBeanDefinition) BeanDefinitionBuilder .genericBeanDefinition(TestControllerByConstructor.class) // 這裏,看這裏,這裏在表達依賴了 .addConstructorArgReference("testService") .addConstructorArgValue("wire by constructor") .getBeanDefinition();
完整代碼:
package org.springframework.simple.byconstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.support.*; import org.springframework.context.annotation.AnnotationBeanNameGenerator; import org.springframework.simple.ITestService; import org.springframework.simple.TestService; import org.springframework.util.Assert; @Slf4j public class ManualRegisterBeanDefinitionDemoByConstructor { public static void main(String[] args) { wireDependencyByConstructor(); } /** * 經過構造器的方式來注入依賴 */ private static void wireDependencyByConstructor() { /** * 1:生成bean factory */ DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); /** * 2. 構造bean definition,並在bean definition中表達bean之間的依賴關係 */ GenericBeanDefinition iTestServiceBeanDefinition = (GenericBeanDefinition) BeanDefinitionBuilder .genericBeanDefinition(TestService.class).getBeanDefinition(); log.info("iTestServiceBeanDefinition:{}",iTestServiceBeanDefinition); GenericBeanDefinition iTestControllerBeanDefinition = (GenericBeanDefinition) BeanDefinitionBuilder .genericBeanDefinition(TestControllerByConstructor.class) .addConstructorArgReference("testService") .addConstructorArgValue("wire by constructor") .getBeanDefinition(); /** * 3. 註冊bean definition */ // DefaultBeanNameGenerator generator = new DefaultBeanNameGenerator(); AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator(); String beanNameForTestService = generator.generateBeanName(iTestServiceBeanDefinition, factory); factory.registerBeanDefinition(beanNameForTestService, iTestServiceBeanDefinition); String beanNameForTestController = generator.generateBeanName(iTestControllerBeanDefinition, factory); factory.registerBeanDefinition(beanNameForTestController, TestControllerBeanDefinition); /** * 4. 獲取bean */ TestControllerByConstructor bean = factory.getBean(TestControllerByConstructor.class); log.info("TestControllerByConstructor:{}",bean); ITestService testService = factory.getBean(ITestService.class); log.info("testService bean:{}",testService); Assert.isTrue(bean.getTestService() == testService); } }
原理相似,核心代碼不一樣之處以下:
GenericBeanDefinition iTestControllerBeanDefinition = (GenericBeanDefinition) BeanDefinitionBuilder .genericBeanDefinition(TestControllerWireByProperty.class) // 這裏是調用的property相關方法 .addPropertyReference("t","testService") .addPropertyValue("name","just test") .getBeanDefinition();
今天就到這裏,有問題請指出哈,歡迎你們和我一塊兒閱讀spring boot源碼。
源碼地址: