中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

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

濮陽市建設(shè)分局網(wǎng)站百度賬號中心

濮陽市建設(shè)分局網(wǎng)站,百度賬號中心,鄭州的做網(wǎng)站公司哪家好,網(wǎng)站流量超了Java進(jìn)擊框架:Spring(一)前言創(chuàng)建Spring項(xiàng)目Spring IoC容器和Beans介紹Bean的概述Spring IoC配置元數(shù)據(jù)實(shí)例化Bean依賴注入循環(huán)依賴詳細(xì)配置生命周期回調(diào)Bean定義繼承基于注解的容器配置Component和進(jìn)一步的原型注解自動(dòng)檢測類和注冊Bean定義…

Java進(jìn)擊框架:Spring(一)

  • 前言
    • 創(chuàng)建Spring項(xiàng)目
    • Spring IoC容器和Beans介紹
      • Bean的概述
      • Spring IoC
    • 配置元數(shù)據(jù)
    • 實(shí)例化Bean
    • 依賴注入
      • 循環(huán)依賴
    • 詳細(xì)配置
    • 生命周期回調(diào)
    • Bean定義繼承
    • 基于注解的容器配置
    • @Component和進(jìn)一步的原型注解
    • 自動(dòng)檢測類和注冊Bean定義
    • 使用JSR 330標(biāo)準(zhǔn)注釋
    • ApplicationContext的附加功能

前言

Spring 誕生于 2003 年,輕量級的 Java 開源框架,是對早期 J2EE 規(guī)范復(fù)雜性的回應(yīng)。雖然有些人認(rèn)為Java EESpring是競爭,但Spring實(shí)際上是Java EE的補(bǔ)充。

在這里插入圖片描述

從整體上看Spring可以分為五個(gè)部分(從上到下、從左到右):Data Access/Integration、Web、AOPCore Container、Test

  • Data Access/Integration:數(shù)據(jù)訪問與集成,包括 JDBC、ORM、OXM、JMSTransactions 模塊,主要提供數(shù)據(jù)庫底層操作和事務(wù)控制等支持。
  • Web:提供了基本web集成特性,比如:多文件上傳功能、資源請求,數(shù)據(jù)綁定、通訊等支持。
  • AOP:面向切面編程。比如:日志記錄、權(quán)限控制、性能統(tǒng)計(jì)等通用功能和業(yè)務(wù)邏輯分離的技術(shù)。
  • Core Container:核心容器。提供控制反轉(zhuǎn)(IOC)和依賴注入(DI),上下文配置,表達(dá)式語言等支持。
  • Test:測試模塊。使用JunitTestNGSpring組件進(jìn)行測試。

除了Spring Framework之外,還有其他項(xiàng)目,例如Spring Boot,Spring Security,Spring Data,Spring Cloud,Spring Batch等。

創(chuàng)建Spring項(xiàng)目

(1)以idea為例,先創(chuàng)建Maven項(xiàng)目。在這里插入圖片描述(2)然后再main文件下創(chuàng)建resouces文件。在這里插入圖片描述
(3)找到idea最右側(cè),標(biāo)記為Resource文件。
在這里插入圖片描述
(4)然后引入依賴(spring5.3.23為例)。

    <dependencies><!-- https://mvnrepository.com/artifact/org.springframework/spring-context --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.23</version></dependency><!-- https://mvnrepository.com/artifact/org.springframework/spring-core --><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>5.3.23</version></dependency><!-- https://mvnrepository.com/artifact/org.springframework/spring-beans --><dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId><version>5.3.23</version></dependency><!-- https://mvnrepository.com/artifact/org.springframework/spring-expression --><dependency><groupId>org.springframework</groupId><artifactId>spring-expression</artifactId><version>5.3.23</version></dependency></dependencies>

(5)再resources文件下創(chuàng)建xml文件,文件名自定義。
在這里插入圖片描述
(6)寫入基本配置結(jié)構(gòu)

<?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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"></beans>

這樣就創(chuàng)建完成spring項(xiàng)目,后續(xù)通過此結(jié)構(gòu)進(jìn)行講解。

Spring IoC容器和Beans介紹

Spring 中,構(gòu)成應(yīng)用程序主干并由 Spring IoC 容器管理的對象稱為 Bean。 Bean 是由 Spring IoC 容器實(shí)例化,組裝和以其他方式管理的對象。Bean 及其之間的依賴關(guān)系反映在容器使用的配置元數(shù)據(jù)中。配置元數(shù)據(jù)用XML、Java注釋或Java代碼表示。它讓您能夠表達(dá)組成應(yīng)用程序的對象以及這些對象之間豐富的相互依賴關(guān)系。

Bean的概述

Spring IoC容器管理一個(gè)或多個(gè)beans。這些beans是用您提供給容器的配置元數(shù)據(jù)創(chuàng)建的(例如,以XML的形式<bean/>定義)。

在容器本身中,這些bean定義表示為BeanDefinition對象,這些對象包含以下元數(shù)據(jù)(以及其他信息):

  • 包限定類名:通常是正在定義的bean的實(shí)際實(shí)現(xiàn)類。

  • Bean行為配置元素,聲明bean在容器中的行為方式(范圍、生命周期回調(diào)等)。

  • bean完成其工作所需的其他bean的引用。這些引用也稱為協(xié)作者或依賴者。

  • 要在新創(chuàng)建的對象中設(shè)置的其他配置設(shè)置,例如,池的大小限制或在管理連接池的bean中使用的連接數(shù)。

這些元數(shù)據(jù)轉(zhuǎn)化為一組組成每個(gè)bean定義的屬性。下表描述了這些屬性:

屬性介紹
Class實(shí)例化bean
Name命名bean
Scopebean范圍
Constructor arguments構(gòu)造器參數(shù)
Dependency Injection依賴注入
Autowiring mode自動(dòng)裝配模式
Lazy initialization mode延遲初始化的bean
Initialization method初始化方法
Destruction method銷毀方法

Spring IoC

IoC(Inversion of Control)控制反轉(zhuǎn),也稱為依賴注入(DI)。

我們可以先來重溫一下,初學(xué)Java時(shí),當(dāng)某個(gè)類需要調(diào)用其它類的方法,直接new這個(gè)類,再調(diào)用方法,如代碼所示:

public class B {public void b(){}
}
public class A {public static void main(String[] args) {B b = new B();b.b();}
}

在這里插入圖片描述
這樣就很容易導(dǎo)致,耦合度太高,有了IOC容器后將主動(dòng)權(quán)交給了第三方進(jìn)行管理。

定義一個(gè)容器配置元數(shù)據(jù):

<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="a" class="com.example.A"><constructor-arg ref="b"></constructor-arg></bean><bean id="b" class="com.example.B"></bean>
</beans>

定義構(gòu)造類,進(jìn)行注入:

public class B {public void b(){}
}
public class A {private B b;public A(B b) { this.b = b; }public void getb(){ b.b(); }public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");A a = applicationContext.getBean("a", A.class);a.getb();}
}

在這里插入圖片描述

org.springframework.beansorg.springframework.context包是Spring FrameworkIoC容器的基礎(chǔ)。

org.springframework.context.ApplicationContext接口代表Spring IoC容器。

你可以創(chuàng)建ClassPathXmlApplicationContext或者FileSystemXmlApplicationContext來啟動(dòng)對元數(shù)據(jù)的支持。

通過使用IoC,這里通過構(gòu)造器注入(還有其它方法)使類與類之間耦合性減小,所以IoC不是一種技術(shù),更多的是一種思想,它能指導(dǎo)我們?nèi)绾卧O(shè)計(jì)出松耦合、更優(yōu)良的程序。

通俗點(diǎn)說IOC容器改變了依賴對象的創(chuàng)建方式,反向的向類注入所需要的其它對象 。

配置元數(shù)據(jù)

Spring IoC容器管理一個(gè)或多個(gè)beans。這些beans是用您提供給容器的配置元數(shù)據(jù)創(chuàng)建的(例如,以XML的形式<bean/>定義)?;?strong>XML的配置元數(shù)據(jù)將這些beans配置為<bean/>頂層中的元素<beans/>元素。

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><bean id="a" name="a,a1;a3" class="com.example.A" scope="singleton"></bean><alias name="a" alias="as-a"></alias>
</beans>
  • id屬性:標(biāo)識(shí)單個(gè)bean定義,唯一標(biāo)識(shí)。
    public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");A a = applicationContext.getBean("a", A.class);}
  • name屬性:標(biāo)識(shí)單個(gè)bean定義,唯一標(biāo)識(shí),可以與id相同,指定多個(gè)名稱可以使用逗號或者分號隔開。
    public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");A a = applicationContext.getBean("a1", A.class);}
  • alias屬性:有時(shí)需要為在別處定義的bean引入別名,在基于XML的配置元數(shù)據(jù)中,可以使用元素來實(shí)現(xiàn)這一點(diǎn)。
    public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");A a = applicationContext.getBean("as-a", A.class);}
  • class屬性:定義bean的類型,并使用完全限定的類名。如果idname都沒有想要獲取bean可以通過完全限定的類名。
    public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");A a = applicationContext.getBean("com.example.A", A.class);}
  • scope屬性:指定對象的作用范圍。最初只有兩種:singletonprototype,隨著版本的不斷更新,新增類型:requestsession、application、websocket。Bean的生命周期有三種:創(chuàng)建、運(yùn)行、銷毀。

(1)singleton:默認(rèn)值。Spring容器中只有一個(gè)實(shí)例。

創(chuàng)建:容器創(chuàng)建時(shí),對象創(chuàng)建。
運(yùn)行:容器存在,一直存活。
銷毀:容器銷毀,對象銷毀。

在這里插入圖片描述

示例代碼:

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><bean id="a" class="com.example.A" scope="singleton"></bean>
</beans>
public class A {public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");A a = applicationContext.getBean("a", A.class);System.out.println(a);a = applicationContext.getBean("a", A.class);System.out.println(a);/** Output:* com.example.A@ff5b51f* com.example.A@ff5b51f*/}
}

運(yùn)行后我們發(fā)現(xiàn),當(dāng)范圍為singleton時(shí),打印輸出的內(nèi)存地址相同,容器只創(chuàng)建了一個(gè)實(shí)例。

(2)prototype:每次請求Spring容器都會(huì)創(chuàng)建一個(gè)新的實(shí)例。

創(chuàng)建:使用時(shí),對象創(chuàng)建。
運(yùn)行:對象使用時(shí),一直存活。
銷毀:對象長時(shí)間不用,且沒有別的對象引用時(shí),由Java的垃圾回收機(jī)制回收。

在這里插入圖片描述

示例代碼:

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><bean id="a" class="com.example.A" scope="prototype"></bean>
</beans>
public class A {public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");A a = applicationContext.getBean("a", A.class);System.out.println(a);a = applicationContext.getBean("a", A.class);System.out.println(a);/** Output:* com.example.A@6e1567f1* com.example.A@5cb9f472*/}
}

運(yùn)行后我們發(fā)現(xiàn),當(dāng)范圍為prototype時(shí),打印輸出的內(nèi)存地址不相同,容器只創(chuàng)建了兩個(gè)實(shí)例。

(3)request:每個(gè)HTTP請求都有自己的bean實(shí)例,僅在web有效。

(4)session:將單個(gè)bean定義作用于HTTP Session的生命周期,僅在web有效。

(5)application:將單個(gè)bean定義作用于ServletContext的生命周期,僅在web有效。

(6)websocket:將單個(gè)bean定義作用于WebSocket的生命周期,僅在web有效。

(7)自定義范圍bean作用域機(jī)制是可擴(kuò)展的。您可以定義自己的作用域,甚至重新定義現(xiàn)有的作用域,盡管后者被認(rèn)為是不好的做法,您需要實(shí)現(xiàn)org.springframework.beans.factory.config.Scope接口。

public class NewScope implements Scope {public Object get(String s, ObjectFactory<?> objectFactory) { return null; }public Object remove(String s) { return null; }public void registerDestructionCallback(String s, Runnable runnable) { }public Object resolveContextualObject(String s) { return null; }public String getConversationId() { return null; }
}

實(shí)例化Bean

bean定義本質(zhì)上是創(chuàng)建一個(gè)或多個(gè)對象的方法。當(dāng)被訪問時(shí),容器查看命名bean的配方,并使用由該bean定義封裝的配置元數(shù)據(jù)來創(chuàng)建(或獲取)實(shí)際對象。

實(shí)例化 Bean 有四種方式:構(gòu)造函數(shù)實(shí)例化、靜態(tài)工廠方法實(shí)例化、實(shí)例工廠方法進(jìn)行實(shí)例化、接口實(shí)例化。

  • 構(gòu)造函數(shù)實(shí)例化

當(dāng)您通過構(gòu)造器方法創(chuàng)建一個(gè)bean時(shí),所有普通的類都可以被Spring使用并與之兼容。Spring IoC容器實(shí)際上可以管理您希望它管理的任何類。您還可以在容器中包含更多奇特的非bean樣式的類。

使用基于XML的配置元數(shù)據(jù),您可以按如下方式指定bean類::

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><bean id="a" class="com.example.A"></bean>
</beans>

示例代碼如下:

public class A {public A() {System.out.println("構(gòu)造方法實(shí)例化");}public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");A a = applicationContext.getBean("a", A.class);System.out.println(a);/** Output:*  構(gòu)造方法實(shí)例化*  com.example.A@462d5aee*/}
}
  • 靜態(tài)工廠方法實(shí)例化

通過factory-method屬性指定工廠方法,用靜態(tài)工廠方法創(chuàng)建的bean。在此示例中getInstance()方法必須是static方法。以下示例顯示了如何指定工廠方法:

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><bean id="a" class="com.example.A" factory-method="getInstance"></bean>
</beans>

示例代碼如下:

public class A {public static A getInstance(){System.out.println("靜態(tài)工廠實(shí)例");return new A();}public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");A a = applicationContext.getBean("a", A.class);System.out.println(a);/** Output:* 靜態(tài)工廠實(shí)例* com.example.A@148080bb*/}
}
  • 實(shí)例工廠方法進(jìn)行實(shí)例化

實(shí)例工廠方法是通過現(xiàn)有非靜態(tài)方法bean創(chuàng)建新的bean。要使用這種機(jī)制,將class屬性為空,并且在factory-bean屬性,指定當(dāng)前(或父或祖先)容器中bean的名稱,該容器包含創(chuàng)建對象時(shí)要調(diào)用的實(shí)例方法。屬性設(shè)置工廠方法本身的名稱factory-method屬性。以下示例顯示了如何配置這樣的bean

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><bean id="a" class="com.example.A"></bean><bean id="a2" factory-bean="a" factory-method="getInstance"></bean>
</beans>

示例代碼如下:

public class A {public A getInstance(){System.out.println("實(shí)例化工廠方法");return new A();}public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");A a = applicationContext.getBean("a2", A.class);System.out.println(a);/** Output:* 實(shí)例化工廠方法* com.example.A@6e1ec318*/}
}
  • 接口實(shí)例化

BeanFactory接口提供了能夠管理任何類型對象的高級配置機(jī)制。ApplicationContextBeanFactory的子接口。

BeanFactory定義了IOC容器的最基本形式,并提供了IOC容器應(yīng)遵守的的最基本的接口,也就是Spring IOC所遵守的最底層和最基本的編程規(guī)范。

public interface BeanFactory {String FACTORY_BEAN_PREFIX = "&";//省略部分代碼... ...Object getBean(String var1) throws BeansException;<T> ObjectProvider<T> getBeanProvider(Class<T> var1);boolean containsBean(String var1);boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;@NullableClass<?> getType(String var1) throws NoSuchBeanDefinitionException;String[] getAliases(String var1);
}

如果按照傳統(tǒng)的方式,則需要在中提供大量的配置信息。Spring提供了一個(gè)FactoryBean的工廠類接口,FactoryBean是個(gè)Bean,用戶可以通過實(shí)現(xiàn)該接口定制實(shí)例化Bean的邏輯。

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><bean id="a" class="com.example.A"></bean>
</beans>
public class A implements FactoryBean<A> {public A getObject() throws Exception {System.out.println("FactoryBean a");return new A();}public Class<?> getObjectType() {return A.class;}public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");A a = applicationContext.getBean("a", A.class);System.out.println(a);/** Output:* FactoryBean a* com.example.A@29ca901e*/}}

依賴注入

依賴注入(DI)是一個(gè)過程,通過構(gòu)造函數(shù)參數(shù)、工廠方法的參數(shù)等方式,在對象實(shí)例上設(shè)置的屬性來定義它們的依賴關(guān)系(即,它們使用的其他對象)。然后,容器在創(chuàng)建bean時(shí)注入這些依賴項(xiàng)。這個(gè)過程基本上是bean本身的逆過程(因此得名,控制反轉(zhuǎn))。

依賴注入(DI)有三種主要形式:基于構(gòu)造函數(shù)的依賴注入基于Setter的依賴注入、自動(dòng)注入

  • 基于構(gòu)造函數(shù)的依賴注入

基于構(gòu)造函數(shù)的依賴注入(DI)是通過容器調(diào)用一個(gè)帶有多個(gè)參數(shù)的構(gòu)造函數(shù)來實(shí)現(xiàn)的,每個(gè)參數(shù)代表一個(gè)依賴項(xiàng)。

通過<constructor-arg>標(biāo)簽進(jìn)行構(gòu)造函數(shù)注入;ref 屬性引用了另一個(gè)bean定義的名稱。id屬性和ref屬性之間的鏈接表示協(xié)作對象之間的依賴關(guān)系:

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><bean id="a" class="com.example.A"><constructor-arg ref="c"></constructor-arg><constructor-arg ref="b"></constructor-arg></bean><bean id="b" class="com.example.B"></bean><bean id="c" class="com.example.C"></bean>
</beans>

示例代碼如下:

public class B {public void b(){System.out.println("b");}
}
public class C {public void c(){System.out.println("c");}
}
public class A {private B b;private C c;public A(B b,C c) {this.b = b;this.c = c;}public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");A a = applicationContext.getBean("a", A.class);a.b.b();a.c.c();/** Output:*  b*  c*/}
}

Bean中定義的順序,就是實(shí)例化bean時(shí)提供給相應(yīng)構(gòu)造函數(shù)的順序。

如果構(gòu)造參數(shù)為基本類型的有參構(gòu)造時(shí),可以通過type屬性指定構(gòu)造函數(shù)參數(shù)的類型,value屬性指定參數(shù)值:

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><bean id="a" class="com.example.A"><constructor-arg type="Integer" value="123"></constructor-arg><constructor-arg type="String" value="c"></constructor-arg></bean>
</beans>

示例代碼如下:

public class A {private Integer b;private String c;public A(Integer b,String c) {this.b = b;this.c = c;}public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");A a = applicationContext.getBean("a", A.class);System.out.println(a.b);System.out.println(a.c);/** Output:*  123*  c*/}}

您也可以使用index屬性顯式指定構(gòu)造函數(shù)參數(shù)的索引,如下例所示:

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><bean id="a" class="com.example.A"><constructor-arg index="0" value="123"></constructor-arg><constructor-arg index="1" value="c"></constructor-arg></bean>
</beans>
  • 基于Setter的依賴注入(屬性注入)

基于setter依賴注入(DI)是由容器在調(diào)用無參數(shù)構(gòu)造函數(shù)或無參數(shù)構(gòu)造函數(shù)后調(diào)用bean上的setter方法來完成的。

下面的示例,通過<property>標(biāo)簽指定bean的一個(gè)或多個(gè)屬性,顯示了一個(gè)只能通過使用純setter注入進(jìn)行依賴注入的類。

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><bean id="a" class="com.example.A"><property name="b" ref="b"></property></bean><bean id="b" class="com.example.B"></bean>
</beans>

示例代碼如下:

public class A {private B b;public void setB(B b) {System.out.println("setter注入");this.b = b;}public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");A a = applicationContext.getBean("a", A.class);System.out.println(a.b);/** Output:*  setter注入*  com.example.B@1990a65e*/}
}
  • 自動(dòng)注入

你可以使用autowire屬性來達(dá)到自動(dòng)裝配。autowire屬性提供5中策略:

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><!--no和default:默認(rèn),不裝配。--><bean id="a" class="com.example.A" autowire="no"></bean><bean id="a" class="com.example.A" autowire="default"></bean><!--byType:通過屬性類型注入。--><bean id="a" class="com.example.A" autowire="byType"></bean><!--byName:通過屬性的名稱注入。--><bean id="a" class="com.example.A" autowire="byName"></bean><!--constructor:通過構(gòu)造函數(shù)注入。--><bean id="a" class="com.example.A" autowire="constructor"></bean>
</beans>

byTypebyName都是通過setter()方法注入,constructor通過構(gòu)造函數(shù)屬性的類型注入。

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><bean id="a" class="com.example.A" autowire="byType"></bean><bean id="b" class="com.example.B"></bean>
</beans>

示例代碼如下:

public class B{}
public class A{private B b;public void setB(B b) { this.b = b; }public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");A a = applicationContext.getBean("a", A.class);System.out.println(a.b);/** Output:*  com.example.B@4c762604*/}
}

如果未能匹配到類型或者名稱,則注入失敗:

public class A{private C c;public void setC(C c) { this.c = c; }public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");A a = applicationContext.getBean("a", A.class);System.out.println(a.c);/** Output:*  null*/}
}

你可以使用@Autowired注解減少指定屬性或構(gòu)造函數(shù)參數(shù)的需要。

示例代碼如下:

@Component
public class B {}
@Component
public class A{@Autowiredprivate B b;public static void main(String[] args) {ApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.example");A a = applicationContext.getBean("a", A.class);System.out.println(a.b);/** Output:*  com.example.B@3c419631*/}
}
  • 使用方法注入

Spring的方法注入可分為兩種:查找方法注入任意方法替換。

(1)查找方法注入

查找方法會(huì)導(dǎo)致IoC容器覆蓋給定的方法并返回bean屬性中給出的名稱。這是方法注入的一種形式。

<bean>標(biāo)簽里定義<lookup-method>標(biāo)簽:

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><bean id="a" class="com.example.A"><lookup-method name="getB" bean="b"></lookup-method></bean><bean id="b" class="com.example.B"></bean>
</beans>

name屬性指定方法名,bean為返回的類型

示例代碼如下:

public class B {public void b(){ System.out.println("b"); }
}
public class A{private B b;public B getB() { return b; }public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");A a = applicationContext.getBean("a", A.class);System.out.println(a.getB());/** Output:*  com.example.B@58c1c010*/}}

當(dāng)然你也可以使用注解@Lookup,示例代碼如下:

@Component
public class A{private B b;//    @Lookup("getB")查找指定bean方法@Lookuppublic B getB() {return b;}public static void main(String[] args) {ApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.example");A a = applicationContext.getBean(A.class);System.out.println(a.getB());/** Output:*  com.example.B@58c1c010*/}
}

@Autowired注解會(huì)將所有bean范圍改為單例,@Lookup可以保證被引入的組件保持prototype模式。

(2)任意方法替換

與查找方法注入相比,方法注入的一個(gè)不太有用的形式是用另一個(gè)方法實(shí)現(xiàn)替換受管bean中的任意方法的能力。

對于基于XML的配置元數(shù)據(jù),您可以使用replaced-method元素將現(xiàn)有的方法實(shí)現(xiàn)替換為另一個(gè)方法實(shí)現(xiàn)。

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><bean id="a" class="com.example.A"><replaced-method name="method" replacer="AReplace"><!--參數(shù)類型--><arg-type>String</arg-type></replaced-method></bean><bean id="AReplace" class="com.example.AReplace"></bean>
</beans>

你可以通過<arg-type/>指定多個(gè)重寫方法的參數(shù)類型。

示例代碼如下:

public class AReplace implements MethodReplacer {public Object reimplement(Object o, Method method, Object[] objects) throws Throwable {System.out.println("替換了:"+objects[0].toString());return null;}
}
public class A{public void method(String p){}public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");A a = applicationContext.getBean(A.class);a.method("123");/** Output:*  替換了:123*/}
}

大多數(shù)Spring用戶并不直接使用這些類(即以編程方式),而是使用XMLbean定義、帶注釋的組件。然后,這些源在內(nèi)部被轉(zhuǎn)換為BeanDefinition并用于加載整個(gè)Spring IoC容器實(shí)例。

循環(huán)依賴

如果您主要使用構(gòu)造函數(shù)注入,就有可能創(chuàng)建一個(gè)無法解析的循環(huán)依賴場景。

比如:A類通過構(gòu)造函數(shù)注入需要B類的一個(gè)實(shí)例,B類通過構(gòu)造函數(shù)注入需要A類的一個(gè)實(shí)例。如果將類ABbeans配置為相互注入,Spring IoC容器會(huì)在運(yùn)行時(shí)檢測到這種循環(huán)引用,并拋出一個(gè)BeanCurrentlyInCreationException。

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><bean id="a" class="com.example.A"><constructor-arg name="b" ref="b"></constructor-arg></bean><bean id="b" class="com.example.B"><constructor-arg name="a" ref="a"></constructor-arg></bean>
</beans>

示例代碼如下:

public class B {private A a;public B(A a) {this.a = a;}
}
public class A {private B b;public A(B b) {this.b = b;}public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");A a = applicationContext.getBean("a", A.class);System.out.println(a);/** Output: * Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?* 	... 29 more*/}
}

您可以使用setter注入配置循環(huán)依賴項(xiàng)。

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><bean id="a" class="com.example.A"><property name="b" ref="b"></property></bean><bean id="b" class="com.example.B"><constructor-arg name="a" ref="a"></constructor-arg></bean>
</beans>

示例代碼如下:

public class B {private A a;public B(A a) { this.a = a; }
}
public class A {private B b;public void setB(B b) { this.b = b; }public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");A a = applicationContext.getBean("a", A.class);System.out.println(a);/** Output:* com.example.A@2fd66ad3*/}
}

Spring容器在創(chuàng)建容器時(shí)驗(yàn)證每個(gè)bean的配置。它在容器加載時(shí)檢測配置問題,例如,bean由于缺少或無效的屬性而拋出一個(gè)異常。

詳細(xì)配置

下面介紹其它的配置標(biāo)簽、屬性等。

  • p命名空間

使用p名稱空間可以簡潔的XML配置,我們先看看原來的配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><bean id="a" class="com.example.A"><property name="id" value="123456"></property><property name="userName" value="張三"></property><property name="b" ref="b"></property></bean><bean id="b" class="com.example.B"></bean>
</beans>

使用p名稱空間,首先再<beans>標(biāo)簽中加入鏈接

xmlns:p=“http://www.springframework.org/schema/p”

然后我們就可以使用p命名空間來配置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"xmlns:p="http://www.springframework.org/schema/p"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="a" class="com.example.A"p:id="123456"p:userName="張三"p:b-ref="b"></bean><bean id="b" class="com.example.B"></bean>
</beans>

p:*-ref表示這不是一個(gè)直接的值,而是對另一個(gè)bean的引用。

示例代碼如下:

public class A {private int id;private String userName;private B b;public void setId(int id) { this.id = id; }public void setUserName(String userName) { this.userName = userName; }public void setB(B b) { this.b = b; }public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");A a = applicationContext.getBean("a", A.class);System.out.println(a.id+","+a.userName+","+a.b);/** Output:*  123456,張三,com.example.B@52525845*/}
}
  • c命名空間

我們先來看看原始的構(gòu)造函數(shù)注入方式:

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><beans><bean id="a" class="com.example.A"><constructor-arg ref="b"></constructor-arg><constructor-arg name="name" value="張三"></constructor-arg></bean><bean id="b" class="com.example.B"></bean></beans>
</beans>

p命名空間一樣,可以使用c命名空間來簡化配置構(gòu)造函數(shù)參數(shù),首先再<beans>標(biāo)簽中加入鏈接。

xmlns:c=“http://www.springframework.org/schema/c”

然后我們就可以使用c命名空間來配置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"xmlns:c="http://www.springframework.org/schema/c"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><beans><bean id="a" class="com.example.A"c:b-ref="b"c:name="張三"></bean><bean id="b" class="com.example.B"></bean></beans>
</beans>

c:*-ref表示對于另一個(gè)bean引用。

示例代碼如下:

public class A {private B b;private String name;public A(B b, String name) {this.b = b;this.name = name;}public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");A a = applicationContext.getBean("a", A.class);a.b.b();System.out.println(a.name);/** Output:*  b*  張三*/}
}
  • idref標(biāo)簽

idref標(biāo)簽只是傳遞id(一個(gè)字符串值,不是引用),配置文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><bean id="a" class="com.example.A"><property name="content"><idref bean="b"></idref></property></bean><bean id="b" class="com.example.B"></bean>
</beans>

示例代碼如下:

public class B {}
public class A {private String content;public String getContent() {return content;}public void setContent(String content) {this.content = content;}public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");A a = applicationContext.getBean("a", A.class);System.out.println(a.getContent());/** Output:*  b*/}
}

前面的bean定義片段完全等同于(在運(yùn)行時(shí))下面的片段:

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><bean id="a" class="com.example.A"><property name="content" value="b"/></bean><bean id="b" class="com.example.B"></bean>
</beans>

idref標(biāo)簽讓容器在部署時(shí)驗(yàn)證被引用的命名bean是否確實(shí)存在。

  • ref屬性(標(biāo)簽)

前面簡單介紹了ref屬性(標(biāo)簽),ref屬性(標(biāo)簽)是<constructor-arg/>標(biāo)簽或者<property/>標(biāo)簽定義的元素。您將bean的指定屬性值設(shè)置為由容器管理的另一個(gè)bean(協(xié)作者)的引用。

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><bean id="a" class="com.example.A"><!--<property name="b" ref="b"></property>--><property name="b"><ref bean="b"></ref></property></bean><bean id="b" class="com.example.B"></bean>
</beans>
  • Collections

依賴注入可以注入集合:<list/><set/><map/>,以及<props/>元素,以下示例顯示了如何使用它們:

(1)list

介紹兩種用法:字符串集合、對象集合

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><bean id="a" class="com.example.A"><!--字符串list--><property name="list"><list><value>qwe</value><value>asd</value></list></property><!--對象list--><property name="listObject"><list><!--引用其它對象--><ref bean="b"></ref><bean class="com.example.B"><property name="name" value="a"/><property name="age" value="01"/></bean></list></property></bean><bean id="b" class="com.example.B"><property name="name" value="b"/><property name="age" value="00"/></bean>
</beans>

示例代碼如下:

public class B {private String name;private Integer 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 class A {private List<String> list;private List<B> listObject;public void setList(List<String> list) { this.list = list; }public void setListObject(List<B> listObject) { this.listObject = listObject; }public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");A a = applicationContext.getBean("a", A.class);System.out.println(JSONObject.toJSONString(a.list));System.out.println(JSONObject.toJSONString(a.listObject));/** Output:*  ["qwe","asd"]*  [{"age":0,"name":"b"},{"age":1,"name":"a"}]*/}
}

(2)set

set也有兩種用法:字符串set、對象set

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><bean id="a" class="com.example.A"><!--字符串set--><property name="set"><set><value>qwe</value><value>asd</value></set></property><!--對象set--><property name="setObject"><set><!--引用其它對象--><ref bean="b"></ref><bean name="b" class="com.example.B"><property name="name" value="a"/><property name="age" value="01"/></bean></set></property></bean><bean id="b" class="com.example.B"><property name="name" value="b"/><property name="age" value="00"/></bean>
</beans>

示例代碼如下:

public class A {private Set<String> set;private Set<B> setObject;public void setSet(Set<String> set) { this.set = set; }public void setSetObject(Set<B> setObject) { this.setObject = setObject; }public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");A a = applicationContext.getBean("a", A.class);System.out.println(JSONObject.toJSONString(a.set));System.out.println(JSONObject.toJSONString(a.setObject));/** Output:*  ["qwe","asd"]*  [{"age":0,"name":"b"},{"age":1,"name":"a"}]*/}
}

(3)map

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><bean id="a" class="com.example.A"><property name="map"><map><entry key="name" value="a"></entry><entry key="age" value="01"></entry></map></property></bean>
</beans>

示例代碼如下:

public class A {private Map<String,String> map;public void setMap(Map<String, String> map) { this.map = map; }public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");A a = applicationContext.getBean("a", A.class);System.out.println(JSONObject.toJSONString(a.map));/** Output:*  {"name":"a","age":"01"}*/}
}

(4)props

本質(zhì)上是hashtable。

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><bean id="a" class="com.example.A"><property name="props"><props><prop key="name">a</prop><prop key="age">01</prop></props></property></bean>
</beans>

示例代碼如下:

public class A {private Properties props;public void setProps(Properties props) { this.props = props; }public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");A a = applicationContext.getBean("a", A.class);System.out.println(JSONObject.toJSONString(a.props));/** Output:*  {"age":"01","name":"a"}*/}
}

映射鍵或值或設(shè)置值的值也可以是以下任何元素:

bean | ref | idref | list | set | map | props | value | null

  • Null和空字符串值

如果將值設(shè)為null或者空字符串可以這樣:

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><bean id="b" class="com.example.B"><property name="name" value=""/><property name="age"><null></null></property></bean>
</beans>

示例代碼如下:

public class B {private String name;private Integer age;public void setName(String name) { this.name = name; }public void setAge(Integer age) { this.age = age; }public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");B b = applicationContext.getBean("b", B.class);System.out.println(b.age+","+b.name);/** Output:*  null,*/}
}
  • 使用depends-on

如果一個(gè)bean是另一個(gè)bean的依賴項(xiàng),這通常意味著一個(gè)bean被設(shè)置為另一個(gè)bean的屬性。通常,您可以使用<ref/>元素在基于XML的配置元數(shù)據(jù)中。depends-on屬性表示bean之間的依賴關(guān)系,bean被初始化之前指定強(qiáng)制一個(gè)或多個(gè)bean被初始化。

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><bean id="a" class="com.example.A" depends-on="b,c"></bean><bean id="b" class="com.example.B"></bean><bean id="c" class="com.example.C"></bean>
</beans>

示例代碼如下:

public class B {public void b(){ System.out.println("b"); }
}
public class C {public void c(){ System.out.println("c"); }
}
public class A {public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");A a = applicationContext.getBean("a", A.class);/** Output:*  ... ...Creating shared instance of singleton bean 'b'*  ... ...Creating shared instance of singleton bean 'c'*  ... ...Creating shared instance of singleton bean 'a'*/}
}

你也可以使用@DependsOn注解,進(jìn)行bean的依賴關(guān)系初始化。

@Configuration
public class Config {@Bean("a")@DependsOn({"b"})public A getA(){return new A();}@Bean("b")public B getB(){return new B();}
}

當(dāng)然也可以再類上面使用注解

@Component
@DependsOn("b")
public class A{ }
@Component
public class B { }
  • 惰性初始化的Beans

一般情況下,啟動(dòng)項(xiàng)目時(shí)會(huì)初始化所有的bean,當(dāng)不希望出現(xiàn)這種行為時(shí),可以通過將bean定義標(biāo)記為惰性初始化來防止單例bean的預(yù)實(shí)例化。惰性初始化的bean告訴IoC容器在第一次被請求時(shí)創(chuàng)建一個(gè)bean實(shí)例,而不是在啟動(dòng)時(shí)。

<bean/>元素上加入lazy-init=true屬性:

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><bean id="a" class="com.example.A" lazy-init="true"></bean><bean id="b" class="com.example.B"></bean><bean id="c" class="com.example.C"></bean>
</beans>

當(dāng)項(xiàng)目啟動(dòng)時(shí),bean不會(huì)被急切地預(yù)實(shí)例化,示例代碼如下:

public class A {public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");//使用時(shí)被創(chuàng)建
//        A a = applicationContext.getBean("a", A.class);/** Output:*  ... ...Creating shared instance of singleton bean 'b'*  ... ...Creating shared instance of singleton bean 'c'*/}
}

你也可以使用@Lazy注解惰性初始化。

@Component
public class C extends Base{ }
@Component
public class B extends Base{ }
@Lazy
public class A{public static void main(String[] args) {ApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.example");/** Output:*  Creating shared instance of singleton bean 'b'*  Creating shared instance of singleton bean 'c'*/}
}
  • 設(shè)置主Bean

當(dāng)注入的Bean有多個(gè)候選項(xiàng)時(shí),應(yīng)該給Bean設(shè)置一個(gè)主bean,否則注入時(shí)會(huì)NoUniqueBeanDefinitionException錯(cuò)誤

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><bean id="a" class="com.example.A" autowire="byType"></bean><bean id="b" class="com.example.B"></bean><bean id="c" class="com.example.C"></bean>
</beans>
public interface Base {}
public class B implements Base {}
public class C implements Base {}
public class A{private Base base;public void setBase(Base base) { this.base = base; }public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");}
}

在這里插入圖片描述

我們可以使用primary屬性,指定為主bean。

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><bean id="a" class="com.example.A" autowire="byType"></bean><bean id="b" class="com.example.B" primary="true"></bean><bean id="c" class="com.example.C"></bean>
</beans>

示例代碼如下:

public class A{private Base base;public void setBase(Base base) { this.base = base; }public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");A bean = applicationContext.getBean(A.class);System.out.println(bean.base);/** Output:*  com.example.B@16f7c8c1*/}
}

也可以使用autowire-candidate屬性標(biāo)記當(dāng)前bean是否會(huì)被注入候選項(xiàng),默認(rèn)truefalse表示排除候選項(xiàng)。

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><bean id="a" class="com.example.A" autowire="byType"></bean><bean id="b" class="com.example.B" autowire-candidate="false"></bean><bean id="c" class="com.example.C"></bean>
</beans>

你還可以使用@Primary注解確定一個(gè)主要候選對象。

public interface Base {}
@Primary
@Component
public class B implements Base {}
@Component
public class C implements Base {}
@Component
public class A{@Autowiredprivate Base base;public static void main(String[] args) {ApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.example");A bean = applicationContext.getBean(A.class);System.out.println(bean.base);/** Output:*  com.example.B@72a7c7e0*/}
}
  • <context:annotation-config/>標(biāo)簽

通過在基于XMLSpring配置中包含<context:annotation-config/>標(biāo)簽來隱式注冊以下后處理器:

ConfigurationClassPostProcessor
AutowiredAnnotationBeanPostProcessor
CommonAnnotationBeanPostProcessor
PersistenceAnnotationBeanPostProcessor
EventListenerMethodProcessor

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsd"><!--識(shí)別相應(yīng)的注解--><context:annotation-config/></beans>
  • 限定符<qualifier>

您可以將限定符值與特定的參數(shù)相關(guān)聯(lián),縮小類型匹配的范圍,以便為每個(gè)參數(shù)選擇特定的bean。

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><!--識(shí)別相應(yīng)的注解--><context:annotation-config/><bean id="a" class="com.example.A" autowire="byType"></bean><bean id="b" class="com.example.B"><qualifier value="b"></qualifier></bean><bean id="c" class="com.example.C"><qualifier value="c"></qualifier></bean>
</beans>

<qualifier>標(biāo)簽搭配@Qualifier注解使用, 示例代碼如下:

public interface Base {}
public class B implements Base {}
public class C implements Base {}
public class A{private Base base;public void setBase(@Qualifier("b")Base base) { this.base = base; }public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");A bean = applicationContext.getBean(A.class);System.out.println(bean.base);/** Output:*  com.example.B@7920ba90*/}
}

你也可以使用@Autowired注解搭配@Qualifier注解使用,示例代碼如下:

public interface Base {}
@Component
public class B implements Base {}
@Component
public class C implements Base {}
@Component
public class A{@Autowired@Qualifier("b")private Base base;public static void main(String[] args) {ApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.example");A bean = applicationContext.getBean(A.class);System.out.println(bean.base);/** Output:*  com.example.B@70e8f8e*/}
}

還有一種更簡單的方式,使用JSR-250@Resource注解,它在語義上被定義為通過其惟一的名稱來標(biāo)識(shí)特定的目標(biāo)組件,聲明的類型與匹配過程無關(guān)。

public interface Base {}
@Component
public class B implements Base {}
@Component
public class C implements Base {}
@Component
public class A{@Resource(name = "b")private Base base;public static void main(String[] args) {ApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.example");A bean = applicationContext.getBean(A.class);System.out.println(bean.base);/** Output:*  com.example.B@769f71a9*/}
}

生命周期回調(diào)

為了與容器對bean生命周期的管理進(jìn)行交互,您可以實(shí)現(xiàn)SpringInitializingBeanDisposableBean接口,讓bean在初始化和銷毀bean時(shí)執(zhí)行某些操作。

  • 初始化回調(diào)

(1)使用XML進(jìn)行初始化

對于基于XML的配置元數(shù)據(jù),可以使用init-method屬性指定具有void無參數(shù)簽名的方法的名稱。

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><bean id="a" class="com.example.A" init-method="init"></bean>
</beans>

實(shí)例代碼如下:

public class A{public void init(){System.out.println("初始化bean");}public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");A bean = applicationContext.getBean(A.class);System.out.println(bean);/** Output:*  初始化bean*  com.example.A@b7dd107*/}
}

(2)InitializingBean接口

通過實(shí)現(xiàn)org.springframework.beans.factory.InitializingBean接口重寫afterPropertiesSet()方法執(zhí)行初始化工作。

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><bean id="a" class="com.example.A"></bean>
</beans>

示例代碼如下:

public class A implements InitializingBean{public void afterPropertiesSet() throws Exception {System.out.println("初始化");}public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");A bean = applicationContext.getBean(A.class);System.out.println(bean);/** Output:*  初始化bean*  com.example.A@b7dd107*/}
}

(3)@PostConstruct注解

@Component
public class A {@PostConstructpublic void init(){System.out.println("初始化");}public static void main(String[] args) {ApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.example");A bean = applicationContext.getBean(A.class);System.out.println(bean);/** Output:*  初始化bean*  com.example.A@b7dd107*/}
}

(4)使用@BeaninitMethod屬性

@Configuration
public class Config {@Bean(initMethod = "init")public A a(){return new A();}
}
@Component
public class A {public void init(){System.out.println("初始化bean");}public static void main(String[] args) {ApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.example");A bean = applicationContext.getBean(A.class);System.out.println(bean);/** Output:*  初始化bean*  com.example.A@b7dd107*/}
}
  • 銷毀回調(diào)

銷毀回調(diào)和初始化回調(diào)的方式基本一致。你可以調(diào)用ApplicationContext類的registerShutdownHook()方法和close()方法進(jìn)行容器銷毀。

(1)使用XML進(jìn)行銷毀

使用destroy-method屬性指定無參方法名。

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><bean id="a" class="com.example.A" destroy-method="destroy"></bean>
</beans>

示例代碼如下:

public class A {public void destroy(){System.out.println("銷毀bean");}public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");A bean = applicationContext.getBean(A.class);
//        ((ClassPathXmlApplicationContext) applicationContext).registerShutdownHook();((ClassPathXmlApplicationContext) applicationContext).close();/** Output:*  銷毀bean*/}
}

(2)DisposableBean接口

通過實(shí)現(xiàn)org.springframework.beans.factory.DisposableBean接口重寫destroy()方法執(zhí)行銷毀工作。

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><bean id="a" class="com.example.A"></bean>
</beans>

示例代碼如下:

public class A implements DisposableBean {public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");A bean = applicationContext.getBean(A.class);
//        ((ClassPathXmlApplicationContext) applicationContext).registerShutdownHook();((ClassPathXmlApplicationContext) applicationContext).close();/** Output:*  銷毀bean*/}public void destroy() throws Exception {System.out.println("銷毀bean");}
}

(3)@PreDestroy注解

@Component
public class A {@PreDestroypublic void destroy() {System.out.println("銷毀bean");}public static void main(String[] args) {ApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.example");A bean = applicationContext.getBean(A.class);
//        ((AnnotationConfigApplicationContext) applicationContext).registerShutdownHook();((AnnotationConfigApplicationContext) applicationContext).close();/** Output:*  銷毀bean*/}
}

(4)使用@BeandestroyMethod屬性

@Configuration
public class Config {@Bean(destroyMethod = "destroy")public A a(){return new A();}
}
@Component
public class A {public void destroy() {System.out.println("銷毀bean");}public static void main(String[] args) {ApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.example");A bean = applicationContext.getBean(A.class);
//        ((AnnotationConfigApplicationContext) applicationContext).registerShutdownHook();((AnnotationConfigApplicationContext) applicationContext).close();/** Output:*  銷毀bean*/}
}
  • 默認(rèn)初始化和銷毀方法

你可以在頂層元素<beans/>標(biāo)簽上,使用default-init-method屬性和default-destroy-method屬性,當(dāng)創(chuàng)建和組裝bean時(shí),如果bean類有這樣的方法,它將在適當(dāng)?shù)臅r(shí)候被調(diào)用。

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans default-init-method="init" default-destroy-method="destroy"><bean id="a" class="com.example.A"></bean><bean id="b" class="com.example.B"></bean>
</beans>

示例代碼如下:

public class B { }
public class A {public void init(){ System.out.println("初始化bean"); }public void destroy() { System.out.println("銷毀bean"); }public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");A bean = applicationContext.getBean(A.class);
//        ((ClassPathXmlApplicationContext) applicationContext).registerShutdownHook();((ClassPathXmlApplicationContext) applicationContext).close();/** Output:*  初始化bean*  銷毀bean*/}
}

Bean定義繼承

bean定義從父定義繼承配置數(shù)據(jù)。子定義可以根據(jù)需要覆蓋一些值或添加其他值。使用父bean和子bean定義可以節(jié)省大量的輸入。實(shí)際上,這是一種模板形式。

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><bean id="a" class="com.example.A" parent="b"><property name="name" value="child"></property></bean><bean id="b" class="com.example.B" abstract="true"><property name="name" value="parent"></property><property name="age" value="28"></property></bean>
</beans>

子類通過parent屬性與父類建立關(guān)系,且可以覆蓋相應(yīng)的父設(shè)置。

示例代碼如下:

public class B {private String name;private Integer age;public void setName(String name) { this.name = name; }public void setAge(Integer age) { this.age = age; }
}
public class A{private String name;private Integer 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 static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");A bean = applicationContext.getBean(A.class);System.out.println(JSONObject.toJSONString(bean));/** Output:*  {"age":28,"name":"child"}*/}
}

如果父定義沒有指定類,則將父bean定義顯式標(biāo)記為abstract是必需的,如下例所示:

<?xml version="1.0" encoding="UTF-8"?>
<!--省略鏈接地址-->
<beans><bean id="a" class="com.example.A" parent="b"><property name="name" value="child"></property></bean><bean id="b" abstract="true"><property name="name" value="parent"></property><property name="age" value="28"></property></bean>
</beans>

在這里插入圖片描述
當(dāng)父類顯式標(biāo)記為abstract,父bean不能自行實(shí)例化,因?yàn)樗遣煌暾?#xff0c;只能用作純模板bean定義。

基于注解的容器配置

開發(fā)人員不使用XML來描述bean連接,而是通過使用相關(guān)類、方法或字段聲明上的注釋將配置移入組件類本身。

對于配置Spring,注釋比XML更好嗎?
簡短的回答是“視情況而定”最長的答案是每種方法都有其優(yōu)點(diǎn)和缺點(diǎn),通常,由開發(fā)人員決定哪種策略更適合他們。無論選擇什么,Spring都可以容納兩種風(fēng)格,甚至可以將它們混合在一起。

SpringJava配置支持中的核心構(gòu)件是@Configuration注解的類和@Bean注解的方法。@Configuration是一個(gè)類級別的注釋,表示一個(gè)對象是bean定義的來源;@Bean注解用于指示一個(gè)方法實(shí)例化、配置和初始化一個(gè)由Spring IoC容器管理的新對象。

@Configuration
public class Config {@Beanpublic A getA(){return new A();}
}

代碼相當(dāng)于下面的XML

<beans><bean id="getA" class="com.example.A"></bean>
</beans>

我們可以使用@Scope注解定義一個(gè)范圍,默認(rèn)范圍是singleton

@Configuration
public class Config {@Bean@Scope("prototype")public A getA(){return new A();}
}

默認(rèn)情況下,配置類使用@Bean方法的名稱作為結(jié)果bean的名稱。但是,可以指定name

@Configuration
public class Config {@Bean("a")public A getA(){return new A();}
}

有時(shí),為bean提供更詳細(xì)的文本描述會(huì)很有幫助,您可以使用@Description注釋。

@Configuration
public class Config {@Bean("a")@Description("this is a test")public A getA(){return new A();}
}

在前面的章節(jié)內(nèi)容中多次使用AnnotationConfigApplicationContext類啟用注解操作:

public class A{public static void main(String[] args) {ApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.example");}
}

對于XML可以使用ClassPathXmlApplicationContext類:

public class A{public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");}
}

spring@Configuration類支持的目標(biāo)不是100%完全替代Spring XML。一些工具,比如Spring XML名稱空間,仍然是配置容器的理想方式。

  • 定義bean的優(yōu)先級

如果希望數(shù)組或列表中的項(xiàng)按特定順序排序,也可以使用@Order@Priority注解。

public abstract class Base {  }@Component
@Order(2)
//@Priority(2)
public class B extends Base{ }@Component
@Order(1)
//@Priority(1)
public class C extends Base{ }public class A{@Autowiredprivate List<Base> baseList;public static void main(String[] args) {ApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.example");A bean = applicationContext.getBean(A.class);System.out.println(bean.baseList);/** Output:*  沒有注解之前:[com.example.B@76508ed1, com.example.C@41e36e46]*  加了注解后:[com.example.C@15eb5ee5, com.example.B@4f209819]*/}
}

@OrderSpring提供的注解,@PriorityJSR 250標(biāo)準(zhǔn),都是值越小優(yōu)先級越高。

要注意它們不會(huì)影響bean的啟動(dòng)順序,這是由依賴關(guān)系和@DependsOn聲明。

  • @Resource注解

Spring還通過使用JSR-250支持注入@Resource注釋(jakarta.annotation.Resource)或bean屬性setter方法。這是Jakarta EE中的常見模式。對于Spring管理的對象,Spring也支持這種模式。

@Resource接受名稱屬性。默認(rèn)情況下,Spring將該值解釋為要注入的bean名稱。換句話說,它遵循按名稱語義,如以下示例所示:

public interface Base {}
@Component
public class B implements Base {}
@Component
public class A{@Resource(name = "b")private Base base;@Resourceprivate B b;public static void main(String[] args) {ApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.example");A bean = applicationContext.getBean(A.class);System.out.println(bean.base);/** Output:*  com.example.B@769f71a9*/}
}

如果沒有顯式指定名稱,則默認(rèn)名稱是從字段名或setter方法派生的。

  • 使用@Value

@Value通常用于注入外部化的屬性

application.properties文件內(nèi)容:

spring.application.name=study

配置屬性源:

@Configuration
@PropertySource("classpath:application.properties")
public class Config {}

示例代碼如下:

@Component
public class A{@Value("${spring.application.name}")private String name;public static void main(String[] args) {ApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.example");A bean = applicationContext.getBean(A.class);System.out.println(bean.name);/** Output:*  study*/}
}

如果找不到屬性值,可以通過屬性名:默認(rèn)值定義一個(gè)默認(rèn)值。

@Component
public class A{@Value("${spring.aaa:123}")private String name;public static void main(String[] args) {ApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.example");A bean = applicationContext.getBean(A.class);System.out.println(bean.name);/** Output:*  123*/}
}

spring提供了占位符配置器,你可以通過setPlaceholderPrefix()方法和 setPlaceholderSuffix()方法自定義占位符。

@Configuration
@PropertySource("classpath:application.properties")
public class Config {@Beanpublic static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer(){PropertySourcesPlaceholderConfigurer property = new PropertySourcesPlaceholderConfigurer();property.setPlaceholderPrefix("**");property.setPlaceholderSuffix("**");return property;}
}

Spring提供的內(nèi)置轉(zhuǎn)換器支持允許簡單的類型轉(zhuǎn)換(到Integer或者int例如)被自動(dòng)處理。

@Component和進(jìn)一步的原型注解

@Repository注解是任何實(shí)現(xiàn)存儲(chǔ)庫角色或原型的類的標(biāo)記(也稱為數(shù)據(jù)訪問對象或DAO)。Spring提供了進(jìn)一步的原型注釋:@Component, @Service,以及@Controller。@Component是任何Spring管理的組件的通用原型。@Repository, @Service,以及@Controller是專業(yè)化的@Component對于更具體的用例(分別在持久層、服務(wù)層和表示層)。

在這里插入圖片描述
您還可以組合元注解來創(chuàng)建“組合注解”。例如,在@RestControllerSpring MVC的注釋由以下部分組成@Controller@ResponseBody。
在這里插入圖片描述

自動(dòng)檢測類和注冊Bean定義

要自動(dòng)檢測這些類并注冊相應(yīng)的bean,您需要將@ComponentScan添加到@Configuration類,其中basePackages屬性是這兩個(gè)類的公共父包。

@Configuration@RestController
@ComponentScan(basePackages = "com.example")
public class Config {
}

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"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsd"><context:component-scan base-package="com.example"/>
</beans>

使用<context:component-scan>隱式地啟用了<context:annotation-config>的功能。通常不需要包含<context:annotation-config>元素。

您可以通過應(yīng)用自定義過濾器來自定義掃描,@ComponentScan注解添加includeFilters(包含過濾器) 或者 excludeFilters(忽略過濾器) 的屬性(XML<context:component-scan>元素中配置子元素<context:include-filter />或者<context:exclude-filter />)

FilterType(過濾器類型):ANNOTATION(注解)、ASSIGNABLE_TYPE(指定類型)、ASPECTJ(切面)、REGEX(正則表達(dá)式)、CUSTOM(自定義)。

public class B {}
//自定義過濾
public class DemoFilter implements TypeFilter {public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();System.out.println(annotationMetadata.getClassName());return false;}
}
@Controller
public class A{public static void main(String[] args) {ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class);/** Output:*  com.example.B*  com.example.DemoFilter*/}
}
@Configuration
@ComponentScan(basePackages = "com.example",includeFilters = {@ComponentScan.Filter(type = FilterType.CUSTOM, classes = DemoFilter.class),@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = B.class)},excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Component.class))
public class Config {
}

XML格式如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans><context:component-scan base-package="com.example"><context:include-filter type="custom" expression="com.example.DemoFilter"></context:include-filter><context:include-filter type="assignable" expression="com.example.B"></context:include-filter><context:exclude-filter type="annotation" expression="org.springframework.stereotype.Component"></context:exclude-filter></context:component-scan>
</beans>

您也可以通過注解設(shè)置useDefaultFilters=false

@ComponentScan(basePackages = "com.example",useDefaultFilters = false)

<component-scan/>元素的use-default-filters="false"屬性禁用默認(rèn)過濾器。

<beans><context:component-scan base-package="com.example" use-default-filters="false"/>
</beans>

這實(shí)際上禁用了@Component, @Repository, @Service, @Controller,@RestController@Configuration。

當(dāng)在掃描過程中自動(dòng)檢測到一個(gè)組件時(shí),它的bean名稱由BeanNameGenerator掃描器已知策略。默認(rèn)情況下,任何Spring原型注釋(@Component, @Repository, @Service,以及@Controller)包含一個(gè)名稱value從而將該名稱提供給相應(yīng)的bean定義。如果未設(shè)置value值,默認(rèn)bean名稱生成器返回未大寫的非限定類名。

@Controller(value = "a")
public class A{}

自動(dòng)檢測的組件的默認(rèn)且最常見的作用域是singleton,但是,有時(shí)您需要一個(gè)不同的范圍,該范圍可以由@Scope注解。

@Service
@Scope("prototype")
public class A{}

使用JSR 330標(biāo)準(zhǔn)注釋

Spring支持JSR-330標(biāo)準(zhǔn)注釋(依賴注入)。先引入Maven依賴。

        <dependency><groupId>jakarta.inject</groupId><artifactId>jakarta.inject-api</artifactId><version>1.0</version></dependency>

使用@Named注解代替@Component注解,@Inject注解代替@Autowired注解,示例代碼如下:

@Named("b")
public class B{}
@Named
public class A{@Injectprivate B b;public static void main(String[] args) {ApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.example");A bean = applicationContext.getBean(A.class);System.out.println(bean.b);/** Output:*  com.example.B@67a20f67*/}
}

還有其他的注解替換,比如:@ManagedBean注解等價(jià)于@Component注解,@Scope("singleton")注解等價(jià)于@Singleton注解。

ApplicationContext的附加功能

  • 使用MessageSource進(jìn)行國際化

ApplicationContext接口擴(kuò)展了一個(gè)名為MessageSource的接口,因此提供了國際化(“i18n”)功能,用于支持信息的國際化和包含參數(shù)的信息的替換。

Spring的各種MessageSource實(shí)現(xiàn)遵循與標(biāo)準(zhǔn)JDK ResourceBundle相同的語言環(huán)境解析和回退規(guī)則。

定義兩個(gè)配置文件,語言類別簡稱結(jié)尾。

messages_en.properties

spring.msg=hello,{0}

messages_zh.properties

spring.msg=你好,{0}

通過調(diào)用MessageSource.getMessage()方法解析,示例代碼如下:

@Configuration
public class Config {@Beanpublic ResourceBundleMessageSource messageSource(){ResourceBundleMessageSource resourceBundleMessageSource = new ResourceBundleMessageSource();//指定beannameresourceBundleMessageSource.setBasenames("i18n/messages");//設(shè)置字符編碼resourceBundleMessageSource.setDefaultEncoding("utf-8");return resourceBundleMessageSource;}
}
@Component
public class A{@Autowiredprivate MessageSource messageSource;public void test(){String message = messageSource.getMessage("spring.msg", new Object[]{"world"},"default", Locale.ENGLISH);System.out.println(message);message = messageSource.getMessage("spring.msg", new Object[]{"world"},"default", Locale.CHINESE);System.out.println(message);}public static void main(String[] args) {ApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.example");A bean = applicationContext.getBean(A.class);bean.test();/** Output:*  hello,world*  你好,world*/}
}

xml方式創(chuàng)建bean

<beans><bean id="messageSource"class="org.springframework.context.support.ResourceBundleMessageSource"><property name="basenames"><list><value>messages_en</value><value>messages_zh</value></list></property></bean>
</beans>

Spring提供了三個(gè)MessageSource實(shí)現(xiàn)方式:ResourceBundleMessageSource、ReloadableResourceBundleMessageSourcStaticMessageSource

  • 標(biāo)準(zhǔn)和自定義事件

ApplicationContext中的事件處理是通過ApplicationEvent類和ApplicationListener接口提供的。如果將實(shí)現(xiàn)ApplicationListener接口的bean部署到上下文中,那么每當(dāng)ApplicationEvent發(fā)布到ApplicationContext時(shí),就會(huì)通知該bean。本質(zhì)上,這是標(biāo)準(zhǔn)的觀察者設(shè)計(jì)模式。

Spring提供的標(biāo)準(zhǔn)事件:ContextRefreshedEvent、ContextStartedEventContextStoppedEvent、ContextClosedEvent、RequestHandledEvent、ServletRequestHandledEvent,您還可以創(chuàng)建和發(fā)布自己的自定義事件。

假設(shè)創(chuàng)建一個(gè)發(fā)送通知的功能,首先創(chuàng)建事件類,繼承ApplicationEvent抽象類:

public class MyEvent extends ApplicationEvent {public String message;public MyEvent(Object source, String message) {super(source);this.message = message;System.out.println("創(chuàng)建MyEvent");}
}

創(chuàng)建一個(gè)發(fā)布事件類,實(shí)現(xiàn)ApplicationEventPublisherAware 接口:

public class NotifyService implements ApplicationEventPublisherAware {private ApplicationEventPublisher publisher;public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {publisher = applicationEventPublisher;}public void sendMessage(String message){publisher.publishEvent(new MyEvent(this,message));}
}

容器自動(dòng)調(diào)用setApplicationEventPublisher()。實(shí)際上,傳入的參數(shù)是Spring容器本身。

注冊bean

<beans><bean id="notifyService" class="com.example.NotifyService"></bean>
</beans>

創(chuàng)建監(jiān)聽類,接收自定義ApplicationEvent類,可以實(shí)現(xiàn)ApplicationListener接口,為了更直觀觀測,創(chuàng)建兩個(gè)監(jiān)聽類:

public class Zhangsan implements ApplicationListener<MyEvent> {public void onApplicationEvent(MyEvent event) {System.out.println("zhangsan收到消息:"+event.message);}
}
public class Lisi implements ApplicationListener<MyEvent> {public void onApplicationEvent(MyEvent event) {System.out.println("lisi收到消息:"+event.message);}
}

注冊bean

<beans><bean id="zhangsan" class="com.example.Zhangsan"></bean><bean id="lisi" class="com.example.Lisi"></bean>
</beans>

ApplicationListener指定事件類型,onApplicationEvent()方法可以保持類型安全,避免任何向下轉(zhuǎn)換的需要。您可以注冊任意數(shù)量的事件監(jiān)聽器,但是請注意,默認(rèn)情況下,事件偵聽器同步接收事件。

執(zhí)行結(jié)果如下所示:

public class Test{public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");NotifyService bean = applicationContext.getBean(NotifyService.class);bean.sendMessage("hello world");/** Output:*  創(chuàng)建MyEvent*  zhangsan收到消息:hello world*  lisi收到消息:hello world*/}
}

你也可以使用@EventListener注解,在bean的任意方法上注冊事件偵聽器:

@Component
public class NotifyService {@Autowiredprivate ApplicationEventPublisher publisher;public void sendMessage(String message){publisher.publishEvent(new MyEvent(this,message));}
}
@Component
public class Lisi {@EventListenerpublic void onApplicationEvent(MyEvent event) {System.out.println("lisi收到消息:"+event.message);}
}
@Component
public class Zhangsan {@EventListenerpublic void onApplicationEvent(MyEvent event) {System.out.println("zhangsan收到消息:"+event.message);}
}

@EventListener注解也可以監(jiān)聽多個(gè)事件:

@Component
public class Lisi {@EventListener({MyEvent.class, MyEvent2.class})public void onApplicationEvent(Object event) {System.out.println(event);}
}
  • 異步偵聽器

假設(shè):方法B調(diào)用方法A,你希望方法B不需要等待方法A執(zhí)行完成而是繼續(xù)往下執(zhí)行,可以使用@Async注解。

創(chuàng)建任務(wù)執(zhí)行器(防止報(bào)異常),@EnableAsync啟用異步注解:

@Configuration
@EnableAsync
public class Config {@Beanpublic AsyncTaskExecutor asyncTaskExecutor(){ThreadPoolTaskExecutor asyncTaskExecutor = new ThreadPoolTaskExecutor();asyncTaskExecutor.setCorePoolSize(10);asyncTaskExecutor.setMaxPoolSize(10);asyncTaskExecutor.initialize();return asyncTaskExecutor;}
}

指定異步注解方法

@Component
public class A{@Asyncpublic void a(){System.out.println("thread:"+Thread.currentThread().getName());try {Thread.sleep(20000);} catch (InterruptedException e) {e.printStackTrace();}}
}

需要注意@Async注解,對同一個(gè)類中的方法和static方法無效,不能通過返回值來進(jìn)行后續(xù)操作。如果引發(fā)Exception,不會(huì)傳播到調(diào)用方。

測試注解是否生效

@Component
public class B {@AutowiredA a;public void test() {System.out.println("before");this.a.a();System.out.println("after");}public static void main(String[] args) {ApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.example");B bean = applicationContext.getBean(B.class);bean.test();/** Output:*  before*  after*  thread:asyncTaskExecutor-1*/}
}

本章內(nèi)容主要介紹了Spring IoC 容器與Bean之間的關(guān)系及基本使用。

http://www.risenshineclean.com/news/60723.html

相關(guān)文章:

  • qq郵箱登錄入口網(wǎng)頁版廣州seo網(wǎng)站推廣公司
  • 搭建cms網(wǎng)站網(wǎng)絡(luò)互聯(lián)網(wǎng)推廣
  • 廣東兩學(xué)一做網(wǎng)站西安網(wǎng)是科技發(fā)展有限公司
  • 江門模板建站哪家好網(wǎng)站推廣網(wǎng)絡(luò)營銷方案
  • 網(wǎng)站里的橫幅怎么做項(xiàng)目網(wǎng)站
  • 鄭州網(wǎng)站建設(shè)哪家好打開百度一下網(wǎng)頁版
  • 青之峰做網(wǎng)站廈門seo新站策劃
  • 臨清網(wǎng)站制作公司plc培訓(xùn)機(jī)構(gòu)哪家最好
  • 創(chuàng)建公司策劃書寧波優(yōu)化推廣選哪家
  • 網(wǎng)站建站方案說明書網(wǎng)站制作的費(fèi)用
  • 哪家上市公司做視頻網(wǎng)站培訓(xùn)機(jī)構(gòu)專業(yè)
  • wordpress導(dǎo)航目錄手機(jī)優(yōu)化大師為什么扣錢
  • 天津制作企業(yè)網(wǎng)站提高工作效率的方法
  • 惠州哪家做網(wǎng)站比較好百度seo如何做
  • 做網(wǎng)站備案與不備案的區(qū)別seo長尾關(guān)鍵詞優(yōu)化
  • 重慶所有做網(wǎng)站的公司包頭網(wǎng)站建設(shè)推廣
  • 商城網(wǎng)站建設(shè)-公司網(wǎng)絡(luò)營銷推廣軟件
  • 網(wǎng)站建設(shè)管理的規(guī)章制度新產(chǎn)品怎樣推廣
  • 廣告商對接平臺(tái)百度seo網(wǎng)站優(yōu)化
  • 如何讓百度快速收錄網(wǎng)站惠州百度關(guān)鍵詞優(yōu)化
  • 俄羅斯網(wǎng)站建設(shè)公司網(wǎng)頁開發(fā)需要學(xué)什么
  • 學(xué)校做網(wǎng)站有些什么好處在什么網(wǎng)站可以免費(fèi)
  • 電商網(wǎng)站建設(shè)技術(shù)交流問題2023年的新聞時(shí)事熱點(diǎn)論文
  • 上海網(wǎng)站建設(shè)seo1888百度快速收錄技術(shù)
  • 哪幾個(gè)網(wǎng)站做acm題目最近幾天發(fā)生的新聞大事
  • 網(wǎng)站建設(shè)費(fèi)用 優(yōu)幫云杭州做seo的公司
  • 朝陽專業(yè)網(wǎng)站建設(shè)靜態(tài)網(wǎng)頁設(shè)計(jì)與制作
  • 交城有做網(wǎng)站的嗎品牌營銷是什么
  • wordpress支付文件在哪seo網(wǎng)上培訓(xùn)課程
  • 怎么制作黃色網(wǎng)站中國北京出啥大事了