中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Spring創建bean的方法及使用場景是什么

發布時間:2023-05-05 14:26:49 來源:億速云 閱讀:88 作者:iii 欄目:開發技術

本篇內容介紹了“Spring創建bean的方法及使用場景是什么”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

    創建bean,也可以叫組件注冊,就是把單例bean放到spring容器中。我們定義如下工程結構:

    sping
    --src
    ----main
          java
            com.xk.spring (包路徑)
            --bean (普通類所在的包名)
            --config   (用來寫各種配置類)
            --service   (用來編寫服務層)
          resources
            --(本目錄下用于存放各類資源配置文件,后面測試會用到)
    ----test
    --pom.xml

    在bean包下面定義Person類,用于演示

    package com.xk.spring.bean;
    /**
     * @author xk
     * @since 2023.04.28 8:44
     */
    public class Person {
        private Integer id;
        private String name;
        private Integer age;
        public Person(){}
        public Person(String name, Integer age) {
            this.name = name;
            this.age = age;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public Integer getAge() {
            return age;
        }
        public void setAge(Integer age) {
            this.age = age;
        }
        public Integer getId() {
            return id;
        }
        public void setId(Integer id) {
            this.id = id;
        }
        @Override
        public String toString() {
            return "name:"+this.name+" age:"+this.age+" id:"+this.id;
        }
    }

    另外再定義一個打印spring容器中bean名稱的方法,在單元測試中會使用。

     void printBeanNames(ApplicationContext applicationContext){
            String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
            for (String definitionName : beanDefinitionNames) {
                System.out.println("----"+definitionName);
            }
        }

    1、@Configuration注解

    首先我們先說下@Configuration這個注解,在springboot應用中,經常可以看到引用的各類jar包中定義的類中用到了這個注解。該注解只能作用于類上,在一個類上面加@Configuration注解,就說明該類是一個配置類,該配置類也會作為一個bean被存放到spring容器中,bean的名稱就是類的名稱(首字母小寫)。如下所示,MyConfig是個配置類,spring容器中就擁有了一個bean名稱為myConfig的bean。

    package com.xk.spring.config;
    import org.springframework.context.annotation.Configuration;
    @Configuration
    public class MyConfig {
    }

    我們編寫一個單元測試,來打印下spring容器中bean的名稱。

        @Test
        public void testMyConfig(){
            AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
            printBeanNames(applicationContext);
        }

    執行testMyConfig單元測試,得到結果如下:

    ----org.springframework.context.annotation.internalConfigurationAnnotationProcessor ----org.springframework.context.annotation.internalAutowiredAnnotationProcessor ----org.springframework.context.annotation.internalCommonAnnotationProcessor ----org.springframework.context.event.internalEventListenerProcessor ----org.springframework.context.event.internalEventListenerFactory ----myConfig

    前面幾個bean,是spring內置的bean,最后一個bean就是我們定義的這個配置類,bean名稱為myConfig.

    2、@Bean注解

    @Bean作用于配置類的方法上,要求該方法有返回值,返回的值就是spring容器中的bean,bean名稱默認就是取方法的名稱。比如下面的代碼說明創建一個名稱為onePerson的bean。

    package com.xk.spring.config;
    import com.xk.spring.bean.Person;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    @Configuration
    public class MyConfig {
        @Bean
        public Person onePerson(){
            return new Person("xx",12);
        }
    }

    我們再次執行上面的testMyConfig單元測試,會得到如下結果:

    ----org.springframework.context.annotation.internalConfigurationAnnotationProcessor ----org.springframework.context.annotation.internalAutowiredAnnotationProcessor ----org.springframework.context.annotation.internalCommonAnnotationProcessor ----org.springframework.context.event.internalEventListenerProcessor ----org.springframework.context.event.internalEventListenerFactory ----myConfig ----onePerson

    可以看到,相比于第1步中的結果,spring容器中多了一個叫onePerson的bean,而onePerson也就是方法onePerson的方法名稱。

    3、@Import注解

    @Import注解只能作用于類上面,可以導入標記有@Configuration的配置類、ImportSelector和ImportBeanDefinitionRegistrar的實現類,還能導入普通的類(不含spring注解),所謂導入,就是將類的實例注冊到spring容器中。該注解必須和@Configuration注解結合使用,而且正常情況下,只有當某個組件不會被spring自動注冊時(比如當我們使用ComponentScan指定了某個包掃描路徑),才會使用該注解。spring-boot-autoconfigure.jar包大量使用了該注解,感興趣的可以去參考下。

    3.1、導入標記有@Configuration的配置類

    通過@Import注解導入配置類,會把該配置類中定義的bean都注冊到spring容器中,同時spring也會該該配置類創建一個bean,bean的名稱就是該類的全路徑名。

    我們定義一個ImportConfig配置類,內容如下:

    package com.xk.spring.config;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Import;
    /**
     * @author xk
     * @since 2023.04.28 20:03
     */
    @Import({MyConfig.class})
    @Configuration
    public class ImportConfig {
    }

    我們在配置類上通過@Import注解導入另外的配置類MyConfig,會把MyConfig配置類以及在MyConfig類中定義(注冊)的bean都導入到spring容器中。

    我們編寫一個單元測試,來打印下spring容器中bean的名稱。

    ----org.springframework.context.annotation.internalConfigurationAnnotationProcessor ----org.springframework.context.annotation.internalAutowiredAnnotationProcessor ----org.springframework.context.annotation.internalCommonAnnotationProcessor ----org.springframework.context.event.internalEventListenerProcessor ----org.springframework.context.event.internalEventListenerFactory ----importConfig ----com.xk.spring.config.MyConfig ----onePerson

    注意,此時容器中不僅有importConfig這個bean,也有MyConfig配置類中定義的onePerson這個bean。而導入的MyConfig配置類在spring容器中對應的bean名稱是MyConfig類的全路徑名com.xk.spring.config.MyConfig。特別提醒,由于MyConfig本身是個配置類,如果spring本身能自動掃描注冊該類(比如配置了@ComponentScan包含config包路徑),那么我們再通過@Import這種方式導入MyConfig,MyConfig在spring容器中對應的名稱就變成了myConfig,也就是bean的名稱是類名(首字母小寫)。當然,正如前面所說,如果我們的配置類能被spring自動掃描注冊,我們就不會使用@Import這種方式導入配置類。

    另外,需要格外注意的是,我們通過@Import導入的類本身會被當做配置類,所以即使此處MyConfig類沒有加@Configuration注解,通過配置@Import({Myconfig.class}),也會把MyConfig類里面定義的bean注冊到spring容器,此時MyConfig類對應的bean名稱就是類的全路徑名。但我們一般不這么做,如果一個類中定義了bean,我們很自然會為該類加上@Configuration注解。

    3.2、導入ImportSelector的實現類

    ImportSelector是個接口,它的定義如下:

    public interface ImportSelector {
    	/**
    	 * 返回需要導入的類的字符串數組,數組中的元素就是類的全路徑名。
    	 * @param importingClassMetadata 當前標記@Import注解的類的元數據信息
    	 */
    	String[] selectImports(AnnotationMetadata importingClassMetadata);
    	/**
    	 * 定義一個斷言,用來對上面selectImports返回的類名數組進行過濾,如果某個元素被斷言判定為true,則該元素不會被spring注冊為bean。此處我們先不關注該方法。
    	 */
    	@Nullable
    	default Predicate<String> getExclusionFilter() {
    		return null;
    	}
    }

    我們定義一個MyImportSelector類,實現該接口,內容如下:

    package com.xk.spring.importselector;
    import org.springframework.context.annotation.ImportSelector;
    import org.springframework.core.type.AnnotationMetadata;
    /**
     * @author xk
     * @since 2023.04.28 21:32
     */
    public class MyImportSelector implements ImportSelector {
        @Override
        public String[] selectImports(AnnotationMetadata importingClassMetadata) {
            return new String[]{"com.xk.spring.bean.Person"};
        }
    }

    然后我們修改下我們的ImportConfig類,通過@Import導入MyImportSelector類,內容如下:

    package com.xk.spring.config;
    import com.xk.spring.importselector.MyImportSelector;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Import;
    /**
     * @author xk
     * @since 2023.04.28 20:03
     */
    @Import({MyImportSelector.class})
    @Configuration
    public class ImportConfig {
    }

    最后我們執行上面的testImportConfig單元測試,可以得到下面的結果:

    ----org.springframework.context.annotation.internalConfigurationAnnotationProcessor ----org.springframework.context.annotation.internalAutowiredAnnotationProcessor ----org.springframework.context.annotation.internalCommonAnnotationProcessor ----org.springframework.context.event.internalEventListenerProcessor ----org.springframework.context.event.internalEventListenerFactory ----importConfig ----com.xk.spring.bean.Person

    可以看到,通過導入MyImportSelector類,spring自動幫我們生成了Person的bean實例,而Person對應的bean的名稱就是Person類的全路徑名。

    3.3、導入ImportBeanDefinitionRegistrar的實現類

    ImportBeanDefinitionRegistrar也是個接口,它的定義如下:

    public interface ImportBeanDefinitionRegistrar {
    	/**
    	 * 基于標記@Import注解的類的元數據信息來注冊bean定義信息(最終spring會根據這些bean定義信息生成bean)。注意:由于spring bean生命周期的約束,BeanDefinitionRegistryPostProcessor類型的bean不會在此處被注冊。后面我們再來討論bean的生命周期。
    	 * @param importingClassMetadata 當前標記@Import注解的類的元數據信息
    	 * @param registry bean定義注冊中心,所有的bean定義信息都會被注冊到這里
    	 * @param importBeanNameGenerator 被導入的bean名稱的生成策略 
    	 */
    	default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,
    			BeanNameGenerator importBeanNameGenerator) {
    		registerBeanDefinitions(importingClassMetadata, registry);
    	}
    	/**
    	 * 基于標記@Import注解的類的元數據信息來注冊bean定義信息(最終spring會根據這些bean定義信息生成bean)。注意:由于spring bean生命周期的約束,BeanDefinitionRegistryPostProcessor類型的bean不會在此處被注冊。后面我們再來討論bean的生命周期。
    	 * @param importingClassMetadata 當前標記@Import注解的類的元數據信息
    	 * @param registry bean定義注冊中心,所有的bean定義信息都會被注冊到這里
    	 */
    	default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    	}
    }

    我們定義一個MyImportBeanDefinitionRegistrar類,實現ImportBeanDefinitionRegistrar接口,定義如下:

    package com.xk.spring.importbeandefinitionregistrar;
    import com.xk.spring.bean.Person;
    import org.springframework.beans.factory.support.BeanDefinitionRegistry;
    import org.springframework.beans.factory.support.RootBeanDefinition;
    import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
    import org.springframework.core.type.AnnotationMetadata;
    /**
     * @author xk
     * @since 2023.04.28 21:45
     */
    public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
        @Override
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            boolean flag = registry.containsBeanDefinition("com.xk.spring.bean.Person");
            if(!flag){
                RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Person.class);
                //注冊person,并且自定義bean的名稱為myPerson
                registry.registerBeanDefinition("myPerson",rootBeanDefinition);
            }
        }
    }

    然后我們修改下我們的ImportConfig配置類,使用@Import導入MyImportBeanDefinitionRegistrar類,內容如下:

    package com.xk.spring.config;
    import com.xk.spring.importbeandefinitionregistrar.MyImportBeanDefinitionRegistrar;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Import;
    /**
     * @author xk
     * @since 2023.04.28 20:03
     */
    @Import({MyImportBeanDefinitionRegistrar.class})
    @Configuration
    public class ImportConfig {
    }

    最后我們執行testImportConfig單元測試,會得到如下的結果:

    ----org.springframework.context.annotation.internalConfigurationAnnotationProcessor ----org.springframework.context.annotation.internalAutowiredAnnotationProcessor ----org.springframework.context.annotation.internalCommonAnnotationProcessor ----org.springframework.context.event.internalEventListenerProcessor ----org.springframework.context.event.internalEventListenerFactory ----importConfig ----myPerson

    可以看到,我們通過這種方式成功的導入Person類對應的bean,而且bean的名稱就是我們自定義的myPerson。

    3.4、導入普通的類

    我們還可以通過@Import導入普通類到spring容器,導入之后的bean的名稱就是類名的全路徑。這些普通類可以什么注解都不加,比如沒有@Component注解,也沒有@Configuration注解。就拿我們的Person類來說,我們可以通過@Import({Person.class})的方式直接將其導入spring容器,。

    修改ImportConfig配置類,內容如下:

    package com.xk.spring.config;
    import com.xk.spring.bean.Person;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Import;
    /**
     * @author xk
     * @since 2023.04.28 20:03
     */
    @Import({Person.class})
    @Configuration
    public class ImportConfig {
    }

    最后執行testImportConfig單元測試,會得出如下結果:

    ----org.springframework.context.annotation.internalConfigurationAnnotationProcessor ----org.springframework.context.annotation.internalAutowiredAnnotationProcessor ----org.springframework.context.annotation.internalCommonAnnotationProcessor ----org.springframework.context.event.internalEventListenerProcessor ----org.springframework.context.event.internalEventListenerFactory ----importConfig ----com.xk.spring.bean.Person

    可以看到,Person類被導入到spring容器,并且對應的bean名稱是Person類的全路徑名。

    4、@ImportResource注解

    傳統的spring項目通過使用xml配置文件來定義bean信息,然后在web.xml中聲明我們的spring的xml配置文件。現在我們換種方式,我們可以通過使用@ImportResource注解,將整個的xml配置文件導入到配置類,進而由spring替我們生成對應的bean。

    我們在工程的resources資源目錄下創建application-beans.xml文件(文件名隨便起),內容如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd">
        <!--定義person-->
        <bean id="person" class="com.xk.spring.bean.Person">
            <!-- collaborators and configuration for this bean go here -->
        </bean>
    </beans>

    然后我們修改ImportConfig配置類,內容如下:

    package com.xk.spring.config;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.ImportResource;
    /**
     * @author xk
     * @since 2023.04.28 20:03
     */
    @ImportResource({"classpath:/application-beans.xml"})
    @Configuration
    public class ImportConfig {
    }

    最后執行testImportResource單元測試,得出結果如下:

    ----org.springframework.context.annotation.internalConfigurationAnnotationProcessor ----org.springframework.context.annotation.internalAutowiredAnnotationProcessor ----org.springframework.context.annotation.internalCommonAnnotationProcessor ----org.springframework.context.event.internalEventListenerProcessor ----org.springframework.context.event.internalEventListenerFactory ----importConfig ----person

    可以看到,通過@ImportResource的方式,我們把在xml配置文件中定義的person這個bean注冊到了spring容器中。

    5、@ComponentScan注解

    @ComponentScan注解可以讓spring方便地識別標記了@Component注解的組件,需要和@Configuration注解一起使用。我們在web開發時,經常會使用@Service、@Repository、@Controller、@Configuration、@Component等注解,用來表示MVC不同層次的組件bean。其實前面四種注解的元注解上面都標記了@Component,說明被這四種注解標記的類通過配置@ComponentScan指令,就可以被注冊到spring容器中,而它們對應的bean的名稱就是類名(首字母小寫)。

    我們拿@Service為例,在service包下面創建PersonService類,內容如下:

    package com.xk.spring.service;
    import org.springframework.stereotype.Service;
    /**
     * 人員服務層
     * @author xk
     * @since 2023.04.29 7:25
     */
    @Service
    public class PersonService {
    }

    內容很簡單,就簡單的通過@Service將該類標記為一個組件。接下來我們修改MyConfig類,在它上面加上@ComponentScan注解,內容如下:

    package com.xk.spring.config;
    import com.xk.spring.bean.Person;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    @ComponentScan("com.xk.spring.service")
    @Configuration
    public class MyConfig {
        @Bean
        public Person onePerson(){
            return new Person("xx",18);
        }
    }

    最后我們執行下先前定義的testMyConfig單元測試,得到結果如下:

    ----org.springframework.context.annotation.internalConfigurationAnnotationProcessor ----org.springframework.context.annotation.internalAutowiredAnnotationProcessor ----org.springframework.context.annotation.internalCommonAnnotationProcessor ----org.springframework.context.event.internalEventListenerProcessor ----org.springframework.context.event.internalEventListenerFactory ----myConfig ----personService ----onePerson

    可以看到,容器中多了一個personService的bean,而該bean就是對應被我們標記了@Service注解的PersonService。雖然我們config包下面的ImportConfig類也加了@Configuration注解,但由于它不在包掃描的范圍,所以spring無法將其自動注冊到容器中。

    “Spring創建bean的方法及使用場景是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    承德市| 衡南县| 大庆市| 泰宁县| 昌黎县| 长武县| 余江县| 陆川县| 乌兰浩特市| 周宁县| 岚皋县| 连南| 静安区| 邓州市| 个旧市| 明星| 香港| 靖西县| 万山特区| 区。| 尼木县| 永春县| 紫云| 永德县| 新野县| 万全县| 丹巴县| 张家港市| 攀枝花市| 滁州市| 周至县| 砀山县| 南宁市| 襄垣县| 聊城市| 襄汾县| 崇义县| 社旗县| 屏山县| 永寿县| 合水县|