<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          驚呆了,spring中竟然有12種定義bean的方法

          共 18932字,需瀏覽 38分鐘

           ·

          2021-07-06 21:43

          前言

          在龐大的java體系中,spring有著舉足輕重的地位,它給每位開發(fā)者帶來了極大的便利和驚喜。我們都知道spring是創(chuàng)建和管理bean的工廠,它提供了多種定義bean的方式,能夠滿足我們?nèi)粘9ぷ髦械亩喾N業(yè)務(wù)場景。

          那么問題來了,你知道spring中有哪些方式可以定義bean?

          我估計(jì)很多人會(huì)說出以下三種:

          沒錯(cuò),但我想說的是以上三種方式只是開胃小菜,實(shí)際上spring的功能遠(yuǎn)比你想象中更強(qiáng)大。

          各位看官如果不信,請(qǐng)繼續(xù)往下看。

          1. xml文件配置bean

          我們先從xml配置bean開始,它是spring最早支持的方式。后來,隨著springboot越來越受歡迎,該方法目前已經(jīng)用得很少了,但我建議我們還是有必要了解一下。

          1.1 構(gòu)造器

          如果你之前有在bean.xml文件中配置過bean的經(jīng)歷,那么對(duì)如下的配置肯定不會(huì)陌生:

          <bean id="personService" class="com.sue.cache.service.test7.PersonService">
          </bean>

          這種方式是以前使用最多的方式,它默認(rèn)使用了無參構(gòu)造器創(chuàng)建bean。

          當(dāng)然我們還可以使用有參的構(gòu)造器,通過<constructor-arg>標(biāo)簽來完成配置。

          <bean id="personService" class="com.sue.cache.service.test7.PersonService">
             <constructor-arg index="0" value="susan"></constructor-arg>
             <constructor-arg index="1" ref="baseInfo"></constructor-arg>
          </bean>

          其中:

          • index表示下標(biāo),從0開始。
          • value表示常量值
          • ref表示引用另一個(gè)bean

          1.2 setter方法

          除此之外,spring還提供了另外一種思路:通過setter方法設(shè)置bean所需參數(shù),這種方式耦合性相對(duì)較低,比有參構(gòu)造器使用更為廣泛。

          先定義Person實(shí)體:

          @Data
          public class Person {
              private String name;
              private int age;
          }

          它里面包含:成員變量name和age,getter/setter方法。

          然后在bean.xml文件中配置bean時(shí),加上<property>標(biāo)簽設(shè)置bean所需參數(shù)。

          <bean id="person" class="com.sue.cache.service.test7.Person">
             <property name="name" value="susan"></constructor-arg>
             <property name="age" value="18"></constructor-arg>
          </bean>

          1.3 靜態(tài)工廠

          這種方式的關(guān)鍵是需要定義一個(gè)工廠類,它里面包含一個(gè)創(chuàng)建bean的靜態(tài)方法。例如:

          public class SusanBeanFactory {
              public static Person createPerson(String name, int age) {
                  return new Person(name, age);
              }
          }

          接下來定義Person類如下:

          @AllArgsConstructor
          @NoArgsConstructor
          @Data
          public class Person {
              private String name;
              private int age;
          }

          它里面包含:成員變量name和age,getter/setter方法,無參構(gòu)造器和全參構(gòu)造器。

          然后在bean.xml文件中配置bean時(shí),通過factory-method參數(shù)指定靜態(tài)工廠方法,同時(shí)通過<constructor-arg>設(shè)置相關(guān)參數(shù)。

          <bean class="com.sue.cache.service.test7.SusanBeanFactory" factory-method="createPerson">
             <constructor-arg index="0" value="susan"></constructor-arg>
             <constructor-arg index="1" value="18"></constructor-arg>
          </bean>

          1.4 實(shí)例工廠方法

          這種方式也需要定義一個(gè)工廠類,但里面包含非靜態(tài)的創(chuàng)建bean的方法。

          public class SusanBeanFactory {
              public Person createPerson(String name, int age) {
                  return new Person(name, age);
              }
          }

          Person類跟上面一樣,就不多說了。

          然后bean.xml文件中配置bean時(shí),需要先配置工廠bean。然后在配置實(shí)例bean時(shí),通過factory-bean參數(shù)指定該工廠bean的引用。

          <bean id="susanBeanFactory" class="com.sue.cache.service.test7.SusanBeanFactory">
          </bean>
          <bean factory-bean="susanBeanFactory" factory-method="createPerson">
             <constructor-arg index="0" value="susan"></constructor-arg>
             <constructor-arg index="1" value="18"></constructor-arg>
          </bean>

          1.5 FactoryBean

          不知道大家有沒有發(fā)現(xiàn),上面的實(shí)例工廠方法每次都需要?jiǎng)?chuàng)建一個(gè)工廠類,不方面統(tǒng)一管理。

          這時(shí)我們可以使用FactoryBean接口。

          public class UserFactoryBean implements FactoryBean<User{
              @Override
              public User getObject() throws Exception {
                  return new User();
              }

              @Override
              public Class<?> getObjectType() {
                  return User.class;
              }
          }

          在它的getObject方法中可以實(shí)現(xiàn)我們自己的邏輯創(chuàng)建對(duì)象,并且在getObjectType方法中我們可以定義對(duì)象的類型。

          然后在bean.xml文件中配置bean時(shí),只需像普通的bean一樣配置即可。

          <bean id="userFactoryBean" class="com.sue.async.service.UserFactoryBean">
          </bean>

          輕松搞定,so easy。

          注意:getBean("userFactoryBean");獲取的是getObject方法中返回的對(duì)象。而getBean("&userFactoryBean");獲取的才是真正的UserFactoryBean對(duì)象。

          我們通過上面五種方式,在bean.xml文件中把bean配置好之后,spring就會(huì)自動(dòng)掃描和解析相應(yīng)的標(biāo)簽,并且?guī)臀覀儎?chuàng)建和實(shí)例化bean,然后放入spring容器中。

          雖說基于xml文件的方式配置bean,簡單而且非常靈活,比較適合一些小項(xiàng)目。但如果遇到比較復(fù)雜的項(xiàng)目,則需要配置大量的bean,而且bean之間的關(guān)系錯(cuò)綜復(fù)雜,這樣久而久之會(huì)導(dǎo)致xml文件迅速膨脹,非常不利于bean的管理。

          2. Component注解

          為了解決bean太多時(shí),xml文件過大,從而導(dǎo)致膨脹不好維護(hù)的問題。在spring2.5中開始支持:@Component@Repository@Service@Controller等注解定義bean。

          如果你有看過這些注解的源碼的話,就會(huì)驚奇得發(fā)現(xiàn):其實(shí)后三種注解也是@Component

          @Component系列注解的出現(xiàn),給我們帶來了極大的便利。我們不需要像以前那樣在bean.xml文件中配置bean了,現(xiàn)在只用在類上加Component、Repository、Service、Controller,這四種注解中的任意一種,就能輕松完成bean的定義。

          @Service
          public class PersonService {
              public String get() {
                  return "data";
              }
          }

          其實(shí),這四種注解在功能上沒有特別的區(qū)別,不過在業(yè)界有個(gè)不成文的約定:

          • Controller 一般用在控制層
          • Service 一般用在業(yè)務(wù)層
          • Repository 一般用在數(shù)據(jù)層
          • Component 一般用在公共組件上

          太棒了,簡直一下子解放了我們的雙手。

          不過,需要特別注意的是,通過這種@Component掃描注解的方式定義bean的前提是:需要先配置掃描路徑

          目前常用的配置掃描路徑的方式如下:

          1. 在applicationContext.xml文件中使用<context:component-scan>標(biāo)簽。例如:
          <context:component-scan base-package="com.sue.cache" />
          1. 在springboot的啟動(dòng)類上加上@ComponentScan注解,例如:
          @ComponentScan(basePackages = "com.sue.cache")
          @SpringBootApplication
          public class Application {

              public static void main(String[] args) {
                  new SpringApplicationBuilder(Application.class).web(WebApplicationType.SERVLET).run(args);
              }
          }
          1. 直接在SpringBootApplication注解上加,它支持ComponentScan功能:
          @SpringBootApplication(scanBasePackages = "com.sue.cache")
          public class Application {
              
              public static void main(String[] args) {
                  new SpringApplicationBuilder(Application.class).web(WebApplicationType.SERVLET).run(args);
              }
          }

          當(dāng)然,如果你需要掃描的類跟springboot的入口類,在同一級(jí)或者子級(jí)的包下面,無需指定scanBasePackages參數(shù),spring默認(rèn)會(huì)從入口類的同一級(jí)或者子級(jí)的包去找。

          @SpringBootApplication
          public class Application {
              
              public static void main(String[] args) {
                  new SpringApplicationBuilder(Application.class).web(WebApplicationType.SERVLET).run(args);
              }
          }

          此外,除了上述四種@Component注解之外,springboot還增加了@RestController注解,它是一種特殊的@Controller注解,所以也是@Component注解。

          @RestController還支持@ResponseBody注解的功能,即將接口響應(yīng)數(shù)據(jù)的格式自動(dòng)轉(zhuǎn)換成json。

          @Component系列注解已經(jīng)讓我們愛不釋手了,它目前是我們?nèi)粘9ぷ髦凶疃嗟亩xbean的方式。

          3. JavaConfig

          @Component系列注解雖說使用起來非常方便,但是bean的創(chuàng)建過程完全交給spring容器來完成,我們沒辦法自己控制。

          spring從3.0以后,開始支持JavaConfig的方式定義bean。它可以看做spring的配置文件,但并非真正的配置文件,我們需要通過編碼java代碼的方式創(chuàng)建bean。例如:

          @Configuration
          public class MyConfiguration {

              @Bean
              public Person person() {
                  return new Person();
              }
          }

          在JavaConfig類上加@Configuration注解,相當(dāng)于配置了<beans>標(biāo)簽。而在方法上加@Bean注解,相當(dāng)于配置了<bean>標(biāo)簽。

          此外,springboot還引入了一些列的@Conditional注解,用來控制bean的創(chuàng)建。

          @Configuration
          public class MyConfiguration {

              @ConditionalOnClass(Country.class)
              @Bean
              public Person person() 
          {
                  return new Person();
              }
          }

          @ConditionalOnClass注解的功能是當(dāng)項(xiàng)目中存在Country類時(shí),才實(shí)例化Person類。換句話說就是,如果項(xiàng)目中不存在Country類,就不實(shí)例化Person類。

          這個(gè)功能非常有用,相當(dāng)于一個(gè)開關(guān)控制著Person類,只有滿足一定條件才能實(shí)例化。

          spring中使用比較多的Conditional還有:

          • ConditionalOnBean
          • ConditionalOnProperty
          • ConditionalOnMissingClass
          • ConditionalOnMissingBean
          • ConditionalOnWebApplication

          如果你對(duì)這些功能比較感興趣,可以看看《spring中那些讓你愛不釋手的代碼技巧(續(xù)集)》,這是我之前寫的一篇文章,里面做了更詳細(xì)的介紹。

          下面用一張圖整體認(rèn)識(shí)一下@Conditional家族:

          nice,有了這些功能,我們終于可以告別麻煩的xml時(shí)代了。

          4. Import注解

          通過前面介紹的@Configuration和@Bean相結(jié)合的方式,我們可以通過代碼定義bean。但這種方式有一定的局限性,它只能創(chuàng)建該類中定義的bean實(shí)例,不能創(chuàng)建其他類的bean實(shí)例,如果我們想創(chuàng)建其他類的bean實(shí)例該怎么辦呢?

          這時(shí)可以使用@Import注解導(dǎo)入。

          4.1 普通類

          spring4.2之后@Import注解可以實(shí)例化普通類的bean實(shí)例。例如:

          先定義了Role類:

          @Data
          public class Role {
              private Long id;
              private String name;
          }

          接下來使用@Import注解導(dǎo)入Role類:

          @Import(Role.class)
          @Configuration
          public class MyConfig 
          {
          }

          然后在調(diào)用的地方通過@Autowired注解注入所需的bean。

          @RequestMapping("/")
          @RestController
          public class TestController {

              @Autowired
              private Role role;

              @GetMapping("/test")
              public String test() {
                  System.out.println(role);
                  return "test";
              }
          }

          聰明的你可能會(huì)發(fā)現(xiàn),我沒有在任何地方定義過Role的bean,但spring卻能自動(dòng)創(chuàng)建該類的bean實(shí)例,這是為什么呢?

          這也許正是@Import注解的強(qiáng)大之處。

          此時(shí),有些朋友可能會(huì)問:@Import注解能定義單個(gè)類的bean,但如果有多個(gè)類需要定義bean該怎么辦呢?

          恭喜你,這是個(gè)好問題,因?yàn)?code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">@Import注解也支持。

          @Import({Role.classUser.class})
          @Configuration
          public class MyConfig 
          {
          }

          甚至,如果你想偷懶,不想寫這種MyConfig類,springboot也歡迎。

          @Import({Role.class, User.class})
          @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class,
                  DataSourceTransactionManagerAutoConfiguration.class})
          public class Application {

              public static void main(String[] args) {
                  new SpringApplicationBuilder(Application.class).web(WebApplicationType.SERVLET).run(args);
              }
          }

          可以將@Import加到springboot的啟動(dòng)類上。

          這樣也能生效?

          springboot的啟動(dòng)類一般都會(huì)加@SpringBootApplication注解,該注解上加了@SpringBootConfiguration注解。

          而@SpringBootConfiguration注解,上面又加了@Configuration注解所以,springboot啟動(dòng)類本身帶有@Configuration注解的功能。

          意不意外?驚不驚喜?

          4.2 Configuration類

          上面介紹了@Import注解導(dǎo)入普通類的方法,它同時(shí)也支持導(dǎo)入Configuration類。

          先定義一個(gè)Configuration類:

          @Configuration
          public class MyConfig2 {

              @Bean
              public User user() {
                  return  new User();
              }

              @Bean
              public Role role() {
                  return new Role();
              }
          }

          然后在另外一個(gè)Configuration類中引入前面的Configuration類:

          @Import({MyConfig2.class})
          @Configuration
          public class MyConfig 
          {
          }

          這種方式,如果MyConfig2類已經(jīng)在spring指定的掃描目錄或者子目錄下,則MyConfig類會(huì)顯得有點(diǎn)多余。因?yàn)镸yConfig2類本身就是一個(gè)配置類,它里面就能定義bean。

          但如果MyConfig2類不在指定的spring掃描目錄或者子目錄下,則通過MyConfig類的導(dǎo)入功能,也能把MyConfig2類識(shí)別成配置類。這就有點(diǎn)厲害了喔。

          其實(shí)下面還有更高端的玩法

          swagger作為一個(gè)優(yōu)秀的文檔生成框架,在spring項(xiàng)目中越來越受歡迎。接下來,我們以swagger2為例,介紹一下它是如何導(dǎo)入相關(guān)類的。

          眾所周知,我們引入swagger相關(guān)jar包之后,只需要在springboot的啟動(dòng)類上加上@EnableSwagger2注解,就能開啟swagger的功能。

          其中@EnableSwagger2注解中導(dǎo)入了Swagger2DocumentationConfiguration類。

          該類是一個(gè)Configuration類,它又導(dǎo)入了另外兩個(gè)類:

          • SpringfoxWebMvcConfiguration
          • SwaggerCommonConfiguration

          SpringfoxWebMvcConfiguration類又會(huì)導(dǎo)入新的Configuration類,并且通過@ComponentScan注解掃描了一些其他的路徑。

          SwaggerCommonConfiguration同樣也通過@ComponentScan注解掃描了一些額外的路徑。

          如此一來,我們通過一個(gè)簡單的@EnableSwagger2注解,就能輕松的導(dǎo)入swagger所需的一系列bean,并且擁有swagger的功能。

          還有什么好說的,狂起點(diǎn)贊,簡直完美。

          4.3 ImportSelector

          上面提到的Configuration類,它的功能非常強(qiáng)大。但怎么說呢,它不太適合加復(fù)雜的判斷條件,根據(jù)某些條件定義這些bean,根據(jù)另外的條件定義那些bean。

          那么,這種需求該怎么實(shí)現(xiàn)呢?

          這時(shí)就可以使用ImportSelector接口了。

          首先定義一個(gè)類實(shí)現(xiàn)ImportSelector接口:

          public class DataImportSelector implements ImportSelector {
              @Override
              public String[] selectImports(AnnotationMetadata importingClassMetadata) {
                  return new String[]{"com.sue.async.service.User""com.sue.async.service.Role"};
              }
          }

          重寫selectImports方法,在該方法中指定需要定義bean的類名,注意要包含完整路徑,而非相對(duì)路徑。

          然后在MyConfig類上@Import導(dǎo)入這個(gè)類即可:

          @Import({DataImportSelector.class})
          @Configuration
          public class MyConfig 
          {
          }

          朋友們是不是又發(fā)現(xiàn)了一個(gè)新大陸?

          不過,這個(gè)注解還有更牛逼的用途。

          @EnableAutoConfiguration注解中導(dǎo)入了AutoConfigurationImportSelector類,并且里面包含系統(tǒng)參數(shù)名稱:spring.boot.enableautoconfigurationAutoConfigurationImportSelector類實(shí)現(xiàn)了ImportSelector接口。

          并且重寫了selectImports方法,該方法會(huì)根據(jù)某些注解去找所有需要?jiǎng)?chuàng)建bean的類名,然后返回這些類名。其中在查找這些類名之前,先調(diào)用isEnabled方法,判斷是否需要繼續(xù)查找。該方法會(huì)根據(jù)ENABLED_OVERRIDE_PROPERTY的值來作為判斷條件。而這個(gè)值就是spring.boot.enableautoconfiguration

          換句話說,這里能根據(jù)系統(tǒng)參數(shù)控制bean是否需要被實(shí)例化,優(yōu)秀。

          我個(gè)人認(rèn)為實(shí)現(xiàn)ImportSelector接口的好處主要有以下兩點(diǎn):

          1. 把某個(gè)功能的相關(guān)類,可以放到一起,方面管理和維護(hù)。
          2. 重寫selectImports方法時(shí),能夠根據(jù)條件判斷某些類是否需要被實(shí)例化,或者某個(gè)條件實(shí)例化這些bean,其他的條件實(shí)例化那些bean等。我們能夠非常靈活的定制化bean的實(shí)例化。

          4.4 ImportBeanDefinitionRegistrar

          我們通過上面的這種方式,確實(shí)能夠非常靈活的自定義bean。

          但它的自定義能力,還是有限的,它沒法自定義bean的名稱和作用域等屬性。

          有需求,就有解決方案。

          接下來,我們一起看看ImportBeanDefinitionRegistrar接口的神奇之處。

          先定義CustomImportSelector類實(shí)現(xiàn)ImportBeanDefinitionRegistrar接口:

          public class CustomImportSelector implements ImportBeanDefinitionRegistrar {

              @Override
              public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
                  RootBeanDefinition roleBeanDefinition = new RootBeanDefinition(Role.class);
                  registry.registerBeanDefinition("role", roleBeanDefinition);

                  RootBeanDefinition userBeanDefinition = new RootBeanDefinition(User.class);
                  userBeanDefinition.setScope(ConfigurableBeanFactory.SCOPE_PROTOTYPE);
                  registry.registerBeanDefinition("user", userBeanDefinition);
              }
          }

          重寫registerBeanDefinitions方法,在該方法中我們可以獲取BeanDefinitionRegistry對(duì)象,通過它去注冊bean。不過在注冊bean之前,我們先要?jiǎng)?chuàng)建BeanDefinition對(duì)象,它里面可以自定義bean的名稱、作用域等很多參數(shù)。

          然后在MyConfig類上導(dǎo)入上面的類:

          @Import({CustomImportSelector.class})
          @Configuration
          public class MyConfig 
          {
          }

          我們所熟悉的fegin功能,就是使用ImportBeanDefinitionRegistrar接口實(shí)現(xiàn)的:具體細(xì)節(jié)就不多說了,有興趣的朋友可以加我微信找我私聊。

          5. PostProcessor

          除此之外,spring還提供了專門注冊bean的接口:BeanDefinitionRegistryPostProcessor

          該接口的方法postProcessBeanDefinitionRegistry上有這樣一段描述:修改應(yīng)用程序上下文的內(nèi)部bean定義注冊表標(biāo)準(zhǔn)初始化。所有常規(guī)bean定義都將被加載,但是還沒有bean被實(shí)例化。這允許進(jìn)一步添加在下一個(gè)后處理階段開始之前定義bean。

          如果用這個(gè)接口來定義bean,我們要做的事情就變得非常簡單了。只需定義一個(gè)類實(shí)現(xiàn)BeanDefinitionRegistryPostProcessor接口。

          @Component
          public class MyRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
              @Override
              public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
                  RootBeanDefinition roleBeanDefinition = new RootBeanDefinition(Role.class);
                  registry.registerBeanDefinition("role", roleBeanDefinition);

                  RootBeanDefinition userBeanDefinition = new RootBeanDefinition(User.class);
                  userBeanDefinition.setScope(ConfigurableBeanFactory.SCOPE_PROTOTYPE);
                  registry.registerBeanDefinition("user", userBeanDefinition);
              }

              @Override
              public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
              }
          }

          重寫postProcessBeanDefinitionRegistry方法,在該方法中能夠獲取BeanDefinitionRegistry對(duì)象,它負(fù)責(zé)bean的注冊工作。

          不過細(xì)心的朋友可能會(huì)發(fā)現(xiàn),里面還多了一個(gè)postProcessBeanFactory方法,沒有做任何實(shí)現(xiàn)。

          這個(gè)方法其實(shí)是它的父接口:BeanFactoryPostProcessor里的方法。

          在應(yīng)用程序上下文的標(biāo)準(zhǔn)bean工廠之后修改其內(nèi)部bean工廠初始化。所有bean定義都已加載,但沒有bean將被實(shí)例化。這允許重寫或添加屬性甚至可以初始化bean。

          @Component
          public class MyPostProcessor implements BeanFactoryPostProcessor {

              @Override
              public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
                  DefaultListableBeanFactory registry = (DefaultListableBeanFactory)beanFactory;
                  RootBeanDefinition roleBeanDefinition = new RootBeanDefinition(Role.class);
                  registry.registerBeanDefinition("role", roleBeanDefinition);

                  RootBeanDefinition userBeanDefinition = new RootBeanDefinition(User.class);
                  userBeanDefinition.setScope(ConfigurableBeanFactory.SCOPE_PROTOTYPE);
                  registry.registerBeanDefinition("user", userBeanDefinition);
              }
          }

          既然這兩個(gè)接口都能注冊bean,那么他們有什么區(qū)別?

          • BeanDefinitionRegistryPostProcessor 更側(cè)重于bean的注冊
          • BeanFactoryPostProcessor 更側(cè)重于對(duì)已經(jīng)注冊的bean的屬性進(jìn)行修改,雖然也可以注冊bean。

          此時(shí),有些朋友可能會(huì)問:既然拿到BeanDefinitionRegistry對(duì)象就能注冊bean,那通過BeanFactoryAware的方式是不是也能注冊bean呢?

          從下面這張圖能夠看出DefaultListableBeanFactory就實(shí)現(xiàn)了BeanDefinitionRegistry接口。

          這樣一來,我們?nèi)绻軌颢@取DefaultListableBeanFactory對(duì)象的實(shí)例,然后調(diào)用它的注冊方法,不就可以注冊bean了?

          說時(shí)遲那時(shí)快,定義一個(gè)類實(shí)現(xiàn)BeanFactoryAware接口:

          @Component
          public class BeanFactoryRegistry implements BeanFactoryAware {
              @Override
              public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
                  DefaultListableBeanFactory registry = (DefaultListableBeanFactory) beanFactory;
                  RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(User.class);
                  registry.registerBeanDefinition("user", rootBeanDefinition);

                  RootBeanDefinition userBeanDefinition = new RootBeanDefinition(User.class);
                  userBeanDefinition.setScope(ConfigurableBeanFactory.SCOPE_PROTOTYPE);
                  registry.registerBeanDefinition("user", userBeanDefinition);
              }
          }

          重寫setBeanFactory方法,在該方法中能夠獲取BeanFactory對(duì)象,它能夠強(qiáng)制轉(zhuǎn)換成DefaultListableBeanFactory對(duì)象,然后通過該對(duì)象的實(shí)例注冊bean。

          當(dāng)你滿懷喜悅的運(yùn)行項(xiàng)目時(shí),發(fā)現(xiàn)竟然報(bào)錯(cuò)了:

          為什么會(huì)報(bào)錯(cuò)?

          spring中bean的創(chuàng)建過程順序大致如下:BeanFactoryAware接口是在bean創(chuàng)建成功,并且完成依賴注入之后,在真正初始化之前才被調(diào)用的。在這個(gè)時(shí)候去注冊bean意義不大,因?yàn)檫@個(gè)接口是給我們獲取bean的,并不建議去注冊bean,會(huì)引發(fā)很多問題。

          此外,ApplicationContextRegistry和ApplicationListener接口也有類似的問題,我們可以用他們獲取bean,但不建議用它們注冊bean。

          最后說一句(求關(guān)注,別白嫖我)

          如果這篇文章對(duì)您有所幫助,或者有所啟發(fā)的話,幫忙掃描下發(fā)二維碼關(guān)注一下,您的支持是我堅(jiān)持寫作最大的動(dòng)力。

          求一鍵三連:點(diǎn)贊、轉(zhuǎn)發(fā)、在看。

          關(guān)注公眾號(hào):【蘇三說技術(shù)】,在公眾號(hào)中回復(fù):面試、代碼神器、開發(fā)手冊、時(shí)間管理有超贊的粉絲福利,另外回復(fù):加群,可以跟很多BAT大廠的前輩交流和學(xué)習(xí)。


          瀏覽 123
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  青娱乐精品视觉盛宴 | 一几毛片 | 欧美成人三级 | 色天堂在线 | 久久国产免费娱乐视频 |