国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁 > news >正文

生鮮電商網(wǎng)站建設(shè)百度指數(shù)查詢官方網(wǎng)

生鮮電商網(wǎng)站建設(shè),百度指數(shù)查詢官方網(wǎng),做網(wǎng)站站長交加盟費(fèi),西安做網(wǎng)站選哪家好🚩本文已收錄至專欄:Spring家族學(xué)習(xí) 一.引入 (1) 概述 ? 關(guān)于bean的加載方式,spring提供了各種各樣的形式。因?yàn)閟pring管理bean整體上來說就是由spring維護(hù)對象的生命周期,所以bean的加載可以從大的方面劃分成2種形式&#xff…

🚩本文已收錄至專欄:Spring家族學(xué)習(xí)

一.引入

(1) 概述

? 關(guān)于bean的加載方式,spring提供了各種各樣的形式。因?yàn)閟pring管理bean整體上來說就是由spring維護(hù)對象的生命周期,所以bean的加載可以從大的方面劃分成2種形式

  • 已知類通過(類名.class)交給spring管理
  • 已知類名通過(類名字符串)并交給spring管理。

兩種形式內(nèi)部其實(shí)都一樣,都是通過spring的BeanDefinition對象初始化spring的bean。

  1. bean的定義由前期xml配置逐步演化成注解配置,本質(zhì)是一樣的,都是通過反射機(jī)制加載類名后創(chuàng)建對象,對象就是spring管控的bean
  2. @Import注解可以指定加載某一個(gè)類作為spring管控的bean,如果被加載的類中還具有@Bean相關(guān)的定義,會(huì)被一同加載
  3. spring開放出了若干種可編程控制的bean的初始化方式,通過分支語句由固定的加載bean轉(zhuǎn)成了可以選擇bean是否加載或者選擇加載哪一種bean

本文介紹八種常見的bean加載方式:

  1. xml
  2. xml+注解
  3. 注解
  4. @Import導(dǎo)入
  5. 使用register方法編程形式注冊
  6. @Import導(dǎo)入實(shí)現(xiàn)ImportSelector接口的類
  7. @Import導(dǎo)入實(shí)現(xiàn)ImportBeanDefinitionRegistrar接口的類
  8. @Import導(dǎo)入實(shí)現(xiàn)BeanDefinitionRegistryPostProcessor接口的類

此外還介紹一些相關(guān)涉及知識(shí)

  1. @Bean定義FactoryBean接口
  2. @ImportResource
  3. @Configuration注解的proxyBeanMethods屬性

(2) 環(huán)境搭建

在開始講解之前,我們需要先介紹一下測試所用的環(huán)境。

  1. 創(chuàng)建Maven工程,可以選擇導(dǎo)入如下Spring坐標(biāo)用于測試
		<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.9</version></dependency>
<!--     演示加載第三方bean--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.16</version></dependency>
  1. 創(chuàng)建一些用于后續(xù)示例演示的bean
    在這里插入圖片描述

二.八種加載方式

(1) XML方式

? 最初級(jí)的bean的加載方式其實(shí)可以直擊spring管控bean的核心思想,就是提供類名,然后spring就可以管理了。所以第一種方式就是給出bean的類名,至于內(nèi)部就是通過反射機(jī)制加載成class。

  1. 創(chuàng)建Spring的xml配置文件,通過其中的 <bean/>標(biāo)簽加載bean,我們可以在其中聲明加載自己創(chuàng)建的bean,也可以加載第三方開發(fā)的bean
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd"><!--xml方式聲明 自己 開發(fā)的bean--><bean class="com.guanzhi.bean.Cat"/><bean class="com.guanzhi.bean.Dog"/><!--xml方式聲明 第三方 開發(fā)的bean--><bean class="com.alibaba.druid.pool.DruidDataSource"/></beans>
  1. 我們可以測試一下是否成功加載了這些bean
public class App {public static void main(String[] args) {// 加載配置文件ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");// 獲取所有已加載bean的名稱String[] names = ctx.getBeanDefinitionNames();// 打印查看for (String name : names) {System.out.println(name);}}
}
  1. 啟動(dòng)我們可以發(fā)現(xiàn)成功加載到了上述配置的三個(gè)bean
    在這里插入圖片描述

(2) XML+注解方式

? 由于方式一種需要將spring管控的bean全部寫在xml文件中,對于程序員來說非常不友好,所以就有了第二種方式。哪一個(gè)類要受到spring管控加載成bean,就在這個(gè)類的上面加一個(gè)注解,還可以順帶起一個(gè)bean的名字(id)。這里可以使用的注解有@Component以及三個(gè)衍生注解@Service、@Controller、@Repository。

  1. 例如我們可以在上述Cat類和Mouse類中加上注解
package com.guanzhi.bean;@Component("tom")
public class Cat {
}
package com.guanzhi.bean;@Service
public class Mouse {
}

? 當(dāng)然,由于我們無法在第三方提供的技術(shù)源代碼中去添加上述4個(gè)注解,因此當(dāng)你需要加載第三方開發(fā)的bean的時(shí)候可以使用下列方式定義注解式的bean。@Bean定義在一個(gè)方法上方,當(dāng)前方法的返回值就可以交給spring管控,注意,這個(gè)方法所在的類一定要定義在@Configuration修飾的類中。

package com.guanzhi.config;@Configuration
public class DbConfig {@Beanpublic DruidDataSource dataSource(){DruidDataSource ds = new DruidDataSource();return ds;}
}

? 2. 僅僅如此還是不夠,上面提供的只是bean的聲明,spring并沒有感知到這些東西。想讓spring感知到這些聲明,必須設(shè)置spring去檢查這些類。我們可以通過下列xml配置設(shè)置spring去檢查哪些包,發(fā)現(xiàn)定了對應(yīng)注解,就將對應(yīng)的類納入spring管控范圍,聲明成bean。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!--指定掃描加載bean的位置--><context:component-scan base-package="com.guanzhi.bean,com.guanzhi.config"/>
</beans>

在這里插入圖片描述

  1. 同樣我們可以測試一下是否成功加載了這些bean
public class App {public static void main(String[] args) {// 加載配置文件ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");// 獲取所有已加載bean的名稱String[] names = ctx.getBeanDefinitionNames();// 打印查看for (String name : names) {System.out.println(name);}}
}
  1. 啟動(dòng)我們可以發(fā)現(xiàn)成功加載到了上述配置的三個(gè)bean
    在這里插入圖片描述

方式二聲明bean的方式是目前企業(yè)中較為常見的bean的聲明方式,但是也有缺點(diǎn)。方式一中,通過一個(gè)配置文件,你可以查閱當(dāng)前spring環(huán)境中定義了多少個(gè)或者說多少種bean,但是方式二沒有任何一個(gè)地方可以查閱整體信息,只有當(dāng)程序運(yùn)行起來才能感知到加載了多少個(gè)bean。

(3) 注解方式聲明配置類

? 方式二已經(jīng)完美的簡化了bean的聲明,以后再也不用寫茫茫多的配置信息了。仔細(xì)觀察xml配置文件,會(huì)發(fā)現(xiàn)這個(gè)文件中只剩了掃描包這句話,于是就有人提出,使用java類替換掉這種固定格式的配置,所以下面這種格式就出現(xiàn)了。

  1. 定義一個(gè)類并使用@ComponentScan替代原始xml配置中的包掃描這個(gè)動(dòng)作,其實(shí)功能基本相同。
@ComponentScan({"com.guanzhi.bean","com.guanzhi.config"})
public class SpringConfig {
}
  1. 同樣我們可以測試一下是否成功加載了這些bean
public class App {public static void main(String[] args) {// 加載配置文件ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);// 獲取所有已加載bean的名稱String[] names = ctx.getBeanDefinitionNames();// 打印查看for (String name : names) {System.out.println(name);}}
}
  1. 啟動(dòng)我們可以發(fā)現(xiàn)成功加載了這些bean
    在這里插入圖片描述

(4) @Import注解注入

? 使用掃描的方式加載bean是企業(yè)級(jí)開發(fā)中常見的bean的加載方式,但是由于掃描的時(shí)候不僅可以加載到你要的東西,還有可能加載到各種各樣的亂七八糟的東西。

? 有人就會(huì)奇怪,會(huì)有什么問題呢?比如你掃描了com.guanzhi.service包,后來因?yàn)闃I(yè)務(wù)需要,又掃描了com.guanzhi.dao包,你發(fā)現(xiàn)com.guanzhi包下面只有service和dao這兩個(gè)包,這就簡單了,直接掃描com.guanzhi就行了。但是萬萬沒想到,十天后你加入了一個(gè)外部依賴包,里面也有com.guanzhi包,這下便加載了許多不需要的東西。

? 所以我們需要一種精準(zhǔn)制導(dǎo)的加載方式,使用@Import注解就可以解決你的問題。它可以加載所有的一切,只需要在注解的參數(shù)中寫上加載的類對應(yīng)的.class即可。有人就會(huì)覺得,還要自己手寫,多麻煩,不如掃描好用。 但是他可以指定加載啊,好的命名規(guī)范配合@ComponentScan可以解決很多問題,但是@Import注解擁有其重要的應(yīng)用場景。有沒有想過假如你要加載的bean沒有使用@Component修飾呢?這下就無解了,而@Import就無需考慮這個(gè)問題。

@Import({Dog.class})
public class SpringConfig {
}

被導(dǎo)入的bean無需使用注解聲明為bean

public class Dog {
}

此形式可以有效的降低源代碼與Spring技術(shù)的耦合度,在spring技術(shù)底層及諸多框架的整合中大量使用

除了加載bean,還可以使用@Import注解加載配置類。其實(shí)本質(zhì)上是一樣的。

@Import(Dbconfig.class)
public class SpringConfig {
}

(5) 編程形式注冊bean

? 前面介紹的加載bean的方式都是在容器啟動(dòng)階段完成bean的加載,下面這種方式就比較特殊了,可以在容器初始化完成后手動(dòng)加載bean。通過這種方式可以實(shí)現(xiàn)編程式控制bean的加載。

public class App {public static void main(String[] args) {AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);//上下文容器對象已經(jīng)初始化完畢后,手工加載beanctx.register(Mouse.class);ctx.register(Dog.class);ctx.register(Cat.class);}
}

? 其實(shí)這種方式坑還是挺多的,比如容器中已經(jīng)有了某種類型的bean,再加載會(huì)不會(huì)覆蓋呢?這都是要思考和關(guān)注的問題。

public class App {public static void main(String[] args) {AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);//上下文容器對象已經(jīng)初始化完畢后,手工加載beanctx.registerBean("tom", Cat.class,0);ctx.registerBean("tom", Cat.class,1);ctx.registerBean("tom", Cat.class,2);System.out.println(ctx.getBean(Cat.class));}
}

運(yùn)行可以發(fā)現(xiàn),后加載的覆蓋了之前加載的
在這里插入圖片描述

(6) 導(dǎo)入實(shí)現(xiàn)ImportSelector接口的類

? 在方式五中,我們感受了bean的加載可以進(jìn)行編程化的控制,添加if語句就可以實(shí)現(xiàn)bean的加載控制了。但是畢竟是在容器初始化后實(shí)現(xiàn)bean的加載控制,那是否可以在容器初始化過程中進(jìn)行控制呢?答案是必須的。實(shí)現(xiàn)ImportSelector接口的類可以設(shè)置加載的bean的全路徑類名,記得一點(diǎn),只要能編程就能判定,能判定意味著可以控制程序的運(yùn)行走向,進(jìn)而控制一切。

public class MyImportSelector implements ImportSelector { @Overridepublic String[] selectImports(AnnotationMetadata metadata) {// 各種條件的判定,判定完畢后,決定是否裝載指定的bean// 判斷是否滿足xx條件,滿足則加載xx,否則xxboolean flag = metadata.hasAnnotation("org.springframework.context.annotation.Configuration");if(flag){return new String[]{"com.guanzhi.bean.Dog"};}return new String[]{"com.guanzhi.bean.Cat"};}
}

在配置類中導(dǎo)入

//@Configuration
@Import(MyImportSelector.class)
public class SpringConfig {
}

編寫測試類

public class App {public static void main(String[] args) {ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);String[] names = ctx.getBeanDefinitionNames();for (String name : names) {System.out.println(name);}System.out.println("----------------------");}
}

運(yùn)行可以發(fā)現(xiàn),根據(jù)MyImportSelector中的判斷條件,如果在SpringConfig加上Configuration注解得打印com.guanzhi.bean.Cat,否則打印com.guanzhi.bean.Dog。如此我們便實(shí)現(xiàn)了Bean的動(dòng)態(tài)加載。

(7) 導(dǎo)入實(shí)現(xiàn)ImportBeanDefinitionRegistrar接口的類

? 方式六中提供了給定類全路徑類名控制bean加載的形式,如果對spring的bean的加載原理比較熟悉的小伙伴知道,其實(shí)bean的加載不是一個(gè)簡簡單單的對象,spring中定義了一個(gè)叫做BeanDefinition的東西,它才是控制bean初始化加載的核心。BeanDefinition接口中給出了若干種方法,可以控制bean的相關(guān)屬性。說個(gè)最簡單的,創(chuàng)建的對象是單例還是非單例,在BeanDefinition中定義了scope屬性就可以控制這個(gè)。

如果你感覺方式六沒有給你開放出足夠的對bean的控制操作,那么方式七你值得擁有。我們可以通過定義一個(gè)類,然后實(shí)現(xiàn)ImportBeanDefinitionRegistrar接口的方式定義bean,并且還可以讓你對bean的初始化進(jìn)行更加細(xì)粒度的控制.

在這里插入圖片描述

public class MyRegistrar implements ImportBeanDefinitionRegistrar {@Overridepublic void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {BeanDefinition beanDefinition = 	BeanDefinitionBuilder.rootBeanDefinition(Dog.class).getBeanDefinition();registry.registerBeanDefinition("dog",beanDefinition);}
}

在配置類中導(dǎo)入

@Import(MyRegistrar.class)
public class SpringConfig {
}

測試

public class App {public static void main(String[] args) {ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);String[] names = ctx.getBeanDefinitionNames();for (String name : names) {System.out.println(name);}}
}

(8) 導(dǎo)入實(shí)現(xiàn)BeanDefinitionRegistryPostProcessor接口的類

? 上述七種方式都是在容器初始化過程中進(jìn)行bean的加載或者聲明,但是這里有一個(gè)bug。這么多種方式,它們之間如果有沖突怎么辦?誰能有最終裁定權(quán)?這是個(gè)好問題,當(dāng)某種類型的bean被接二連三的使用各種方式加載后,在你對所有加載方式的加載順序沒有完全理解清晰之前,你還真不知道最后誰說了算。

? BeanDefinitionRegistryPostProcessor,看名字知道,BeanDefinition意思是bean定義,Registry注冊的意思,Post后置,Processor處理器,全稱bean定義后處理器,在所有bean注冊都加載完后,它是最后一個(gè)運(yùn)行的,實(shí)現(xiàn)對容器中bean的最終裁定.

public class MyPostProcessor implements BeanDefinitionRegistryPostProcessor {@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {BeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(Dog.class).getBeanDefinition();registry.registerBeanDefinition("Dog",beanDefinition);}
}

使用與上述一致

三.相關(guān)補(bǔ)充

(1) FactroyBean接口

? spring提供了一個(gè)接口FactoryBean,也可以用于聲明bean,只不過實(shí)現(xiàn)了FactoryBean接口的類造出來的對象不是當(dāng)前類的對象,而是FactoryBean接口泛型指定類型的對象。如下列,造出來的bean并不是DogFactoryBean,而是Dog。這有什么用呢?它可以幫助我們在對象初始化前做一些事情。

// 創(chuàng)建一個(gè)類實(shí)現(xiàn)FactoryBean接口
public class DogFactoryBean implements FactoryBean<Dog> {@Overridepublic Dog getObject() throws Exception {Dog dog = new Dog();// 擴(kuò)展要做的其他事情.....return dog;}@Overridepublic Class<?> getObjectType() {return Dog.class;}// 是否為單例@Overridepublic boolean isSingleton() {return true;}
}

? 有人說,注釋中的代碼寫入Dog的構(gòu)造方法不就行了嗎?干嘛這么費(fèi)勁轉(zhuǎn)一圈,還寫個(gè)類,還要實(shí)現(xiàn)接口,多麻煩啊。還真不一樣,你可以理解為Dog是一個(gè)抽象后剝離的特別干凈的模型,但是實(shí)際使用的時(shí)候必須進(jìn)行一系列的初始化動(dòng)作。只不過根據(jù)情況不同,初始化動(dòng)作不同而已。如果寫入Dog,或許初始化動(dòng)作A當(dāng)前并不能滿足你的需要,這個(gè)時(shí)候你就要做一個(gè)DogB的方案了。如此,你就要做兩個(gè)Dog類。而使用FactoryBean接口就可以完美解決這個(gè)問題。

? 通常實(shí)現(xiàn)了FactoryBean接口的類使用@Bean的形式進(jìn)行加載,當(dāng)然也可以使用@Component去聲明DogFactoryBean,只要被掃描加載到即可。

@ComponentScan({"com.guanzhi.bean","com.guanzhi.config"})
public class SpringConfig {@Beanpublic DogFactoryBean dog(){return new DogFactoryBean();}
}

(2) 注解導(dǎo)入XML配置的bean

? 由于早起開發(fā)的系統(tǒng)大部分都是采用xml的形式配置bean,現(xiàn)在的企業(yè)級(jí)開發(fā)基本上不用這種模式了。但是如果你特別幸運(yùn),需要基于之前的系統(tǒng)進(jìn)行二次開發(fā),這就尷尬了。新開發(fā)的用注解格式,之前開發(fā)的是xml格式。這個(gè)時(shí)候可不是讓你選擇用哪種模式的,而是兩種要同時(shí)使用。spring提供了一個(gè)注解可以解決這個(gè)問題,@ImportResource,在配置類上直接寫上要被融合的xml配置文件名即可,算的上一種兼容性解決方案。

@Configuration
@ComponentScan("com.guanzhi")
@ImportResource("applicationContext.xml")
public class SpringConfig {
}

(3) proxyBeanMethods屬性

? 前面的例子中用到了@Configuration這個(gè)注解,它可以保障配置類中使用方法創(chuàng)建的bean的唯一性,使我們得到的對象是從容器中獲取的而不是重新創(chuàng)建的。只需為@Configuration注解設(shè)置proxyBeanMethods屬性值為true即可,由于此屬性默認(rèn)值為true,所以很少看見明確書寫的,除非想放棄此功能。

@Configuration(proxyBeanMethods = true)
public class SpringConfig {@Beanpublic Cat cat(){return new Cat();}
}

? 下面通過容器再調(diào)用上面的cat方法時(shí),得到的就是同一個(gè)對象了。注意,必須使用spring容器對象調(diào)用此方法才有保持bean唯一性的特性。此特性在很多底層源碼中有應(yīng)用,在MQ中也應(yīng)用了此特性。

public class App {public static void main(String[] args) {ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);SpringConfig springConfig = ctx.getBean("springConfig", SpringConfig.class);System.out.println(springConfig.cat());System.out.println(springConfig.cat());System.out.println(springConfig.cat());}
}

在這里插入圖片描述

http://aloenet.com.cn/news/44427.html

相關(guān)文章:

  • 網(wǎng)站做超鏈接薪資多少一個(gè)月如何創(chuàng)建網(wǎng)站
  • 做外銷網(wǎng)站關(guān)鍵詞密度
  • 高水平網(wǎng)站運(yùn)營托管百度seo優(yōu)化關(guān)鍵詞
  • 做集團(tuán)網(wǎng)站的營銷型網(wǎng)站的類型有哪些
  • 做網(wǎng)站可以提些什么意見seo標(biāo)題優(yōu)化的方法
  • 寺廟網(wǎng)站開發(fā)文案長春seo培訓(xùn)
  • 深圳網(wǎng)站建設(shè)公司設(shè)計(jì)推廣產(chǎn)品的方法和步驟
  • 企業(yè)有域名怎么做網(wǎng)站網(wǎng)頁seo是什么意思
  • 免費(fèi)建設(shè)網(wǎng)站制作品牌軟文案例
  • 做外貿(mào)在哪個(gè)網(wǎng)站凡科建站
  • 網(wǎng)站建設(shè)柳市手機(jī)百度2022年新版本下載
  • 門戶網(wǎng)站模板 html市場營銷的對象有哪些
  • 網(wǎng)站建設(shè)中其他可能的問題b站推出的短視頻app哪個(gè)好
  • 淘寶上做網(wǎng)站國際新聞直播
  • 手機(jī)網(wǎng)站用什么域名盤多多搜索引擎入口
  • 網(wǎng)站開發(fā)文件綜述網(wǎng)絡(luò)營銷企業(yè)網(wǎng)站
  • 軟件開發(fā)需要多久網(wǎng)站優(yōu)化有哪些技巧
  • 大良網(wǎng)站制作福建seo外包
  • 聊城網(wǎng)站建設(shè)泉州seo優(yōu)化
  • 如何免費(fèi)建一個(gè)wordpressseo文章生成器
  • 在線做熱圖的網(wǎng)站站長工具seo綜合查詢5g
  • 深一集團(tuán)的網(wǎng)站誰做的360開戶推廣
  • 武漢哪家網(wǎng)站建設(shè)公司好怎么用手機(jī)創(chuàng)建網(wǎng)站
  • 萍鄉(xiāng)做網(wǎng)站的百度云網(wǎng)盤資源搜索引擎入口
  • 卡姐的wap是什么意思百度seo站長工具
  • 網(wǎng)站怎么做搜索引擎才能收錄百度指數(shù)有什么參考意義
  • 做照片書的模板下載網(wǎng)站好惠州網(wǎng)站推廣排名
  • 沈陽網(wǎng)站建設(shè)專家seo營銷方案
  • 建站免費(fèi)加盟網(wǎng)絡(luò)營銷推廣的優(yōu)勢
  • 有哪些做普洱茶網(wǎng)站的女生讀網(wǎng)絡(luò)營銷與電商直播