1. 程式人生 > >Java學習筆記(10)Spring Bean配置

Java學習筆記(10)Spring Bean配置

Spring Beans自動裝配

Beans自動裝配:

Spring 容器可以在不使用<constructor-arg><property> 元素的情況下自動裝配相互協作的 bean 之間的關係,這有助於減少編寫一個大的基於 Spring 的應用程式的 XML 配置的數量。

自動裝配模式:

下列自動裝配模式,它們可用於指示 Spring 容器為來使用自動裝配進行依賴注入。你可以使用<bean>元素的 autowire 屬性為一個 bean 定義指定自動裝配模式。

模式 描述
no 這是預設的設定,它意味著沒有自動裝配,你應該使用顯式的bean引用來連線。你不用為了連線做特殊的事。
由屬性名自動裝配。Spring 容器看到在 XML 配置檔案中 bean 的自動裝配的屬性設定為 byName。然後嘗試匹配,並且將它的屬性與在配置檔案中被定義為相同名稱的 beans 的屬性進行連線。
由屬性資料型別自動裝配。Spring 容器看到在 XML 配置檔案中 bean 的自動裝配的屬性設定為 byType。然後如果它的型別匹配配置檔案中的一個確切的 bean 名稱,它將嘗試匹配和連線屬性的型別。如果存在不止一個這樣的 bean,則一個致命的異常將會被丟擲。
類似於 byType,但該型別適用於建構函式引數型別。如果在容器中沒有一個建構函式引數型別的 bean,則一個致命錯誤將會發生。
autodetect Spring首先嚐試通過 constructor 使用自動裝配來連線,如果它不執行,Spring 嘗試通過 byType 來自動裝配。

可以使用 byType 或者 constructor 自動裝配模式來連線陣列和其他型別的集合。

自動裝配的侷限性:

當自動裝配始終在同一個專案中使用時,它的效果最好。如果通常不使用自動裝配,它可能會使開發人員混淆的使用它來連線只有一個或兩個 bean 定義。不過,自動裝配可以顯著減少需要指定的屬性或構造器引數,但你應該在使用它們之前考慮到自動裝配的侷限性和缺點。

限制 描述
重寫的可能性 你可以使用總是重寫自動裝配的 和 設定來指定依賴關係。
原始資料型別 你不能自動裝配所謂的簡單型別包括基本型別,字串和類。
混亂的本質 自動裝配不如顯式裝配精確,所以如果可能的話儘可能使用顯式裝配。

Spring自動裝配”byName”:

這種模式由屬性名稱指定自動裝配。Spring 容器看作 beans,在 XML 配置檔案中 beans 的 auto-wire 屬性設定為 byName。然後,它嘗試將它的屬性與配置檔案中定義為相同名稱的 beans 進行匹配和連線。如果找到匹配項,它將注入這些 beans,否則,它將丟擲異常。

例如,在配置檔案中,如果一個 bean 定義設定為自動裝配 byName,並且它包含 spellChecker 屬性(即,它有一個 setSpellChecker(…) 方法),那麼 Spring 就會查詢定義名為 spellChecker 的 bean,並且用它來設定這個屬性。你仍然可以使用 標籤連線其餘的屬性。下面的例子將說明這個概念。

示例:

下面是在正常情況下的配置檔案 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
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <!-- Definition for textEditor bean -->
   <bean id="textEditor" class="autowire.TextEditor">
       <property name="spellChecker" ref="spellChecker" />
       <property name="name" value="Generic Text Editor" />
   </bean>

   <!-- Definition for spellChecker bean -->
   <bean id="spellChecker" class="autowire.SpellChecker">
   </bean>

</beans>

但是,如果你要使用自動裝配 “byName”,那麼你的 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
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <!-- Definition for textEditor bean -->
   <bean id="textEditor" class="autowire.TextEditor" 
      autowire="byName">
      <property name="name" value="Generic Text Editor" />
   </bean>

   <!-- Definition for spellChecker bean -->
   <bean id="spellChecker" class="autowire.SpellChecker">
   </bean>

</beans>

Spring自動裝配”byType”:

這種模式由屬性型別指定自動裝配。Spring 容器看作 beans,在 XML 配置檔案中 beans 的 autowire 屬性設定為 byType。然後,如果它的 type 恰好與配置檔案中 beans 名稱中的一個相匹配,它將嘗試匹配和連線它的屬性。如果找到匹配項,它將注入這些 beans,否則,它將丟擲異常。

例如,在配置檔案中,如果一個 bean 定義設定為自動裝配 byType,並且它包含 SpellChecker 型別的 spellChecker 屬性,那麼 Spring 就會查詢定義名為 SpellChecker 的 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-3.0.xsd">

   <!-- Definition for textEditor bean -->
   <bean id="textEditor" class="autowire.TextEditor">
      <property name="spellChecker" ref="spellChecker" />
      <property name="name" value="Generic Text Editor" />
   </bean>

   <!-- Definition for spellChecker bean -->
   <bean id="spellChecker" class="autowire.SpellChecker">
   </bean>

</beans>

但是,如果你要使用自動裝配 “byType”,那麼你的 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
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <!-- Definition for textEditor bean -->
   <bean id="textEditor" class="autowire.TextEditor" 
      autowire="byType">
      <property name="name" value="Generic Text Editor" />
   </bean>

   <!-- Definition for spellChecker bean -->
   <bean id="SpellChecker" class="autowire.SpellChecker">
   </bean>

</beans>

Spring由建構函式自動裝配:

這種模式與 byType 非常相似,但它應用於構造器引數。Spring 容器看作 beans,在 XML 配置檔案中 beans 的 autowire 屬性設定為 constructor。然後,它嘗試把它的建構函式的引數與配置檔案中 beans 名稱中的一個進行匹配和連線。如果找到匹配項,它會注入這些 bean,否則,它會丟擲異常。

例如,在配置檔案中,如果一個 bean 定義設定為通過建構函式自動裝配,而且它有一個帶有 SpellChecker型別的引數之一的建構函式,那麼 Spring 就會查詢定義名為 SpellChecker 的 bean,並用它來設定建構函式的引數。你仍然可以使用

package autowire;

public class TextEditor {
    private SpellChecker spellChecker;
    private String name;

    public TextEditor(SpellChecker spellChecker, String name) {
        this.spellChecker = spellChecker;
        this.name = name;
    }
    public SpellChecker getSpellChecker() {
        return spellChecker;
    }

    public String getName() {
        return name;
    }

    public void spellCheck() {
        spellChecker.checkSpelling();
    }
}

SpellChecker.java

package autowire;

public class SpellChecker {
    public SpellChecker() {
        System.out.println("Inside SpellChecker constructor.");
    }

    public void checkSpelling() {
        System.out.println("Inside checkSpelling." );
    }
}

MainApp.java

package autowire;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
    public static void main(String[] args) {
        ApplicationContext context = new 
                ClassPathXmlApplicationContext("Beans.xml");
        TextEditor te = (TextEditor)context.getBean("textEditor");
        te.spellCheck();
    }
}

下面是在正常情況下的配置檔案 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
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <!-- Definition for textEditor bean -->
   <bean id="textEditor" class="autowire.TextEditor">
      <constructor-arg  ref="spellChecker" />
      <constructor-arg  value="Generic Text Editor"/>
   </bean>

   <!-- Definition for spellChecker bean -->
   <bean id="spellChecker" class="autowire.SpellChecker">
   </bean>

</beans>

但是,如果你要使用自動裝配 “by constructor”,那麼你的 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
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <!-- Definition for textEditor bean -->
   <bean id="textEditor" class="autowire.TextEditor" 
      autowire="constructor">
      <constructor-arg value="Generic Text Editor"/>
   </bean>

   <!-- Definition for spellChecker bean -->
   <bean id="SpellChecker" class="autowire.SpellChecker">
   </bean>

</beans>

Spirng基於註解的配置

從 Spring 2.5 開始就可以使用註解來配置依賴注入。而不是採用 XML 來描述一個 bean 連線,你可以使用相關類,方法或欄位宣告的註解,將 bean 配置移動到元件類本身。

在 XML 注入之前進行註解注入,因此後者的配置將通過兩種方式的屬性連線被前者重寫。

註解連線在預設情況下在 Spring 容器中不開啟。因此,在可以使用基於註解的連線之前,我們將需要在我們的 Spring 配置檔案中啟用它。所以如果你想在 Spring 應用程式中使用的任何註解,可以考慮到下面的配置檔案。

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

   <context:annotation-config/>
   <!-- bean definitions go here -->

</beans>

一旦 被配置後,你就可以開始註解你的程式碼,表明 Spring 應該自動連線值到屬性,方法和建構函式。讓我們來看看幾個重要的註解,並且瞭解它們是如何工作的:

序號 註解 & 描述
1 @Required@Required 註解應用於 bean 屬性的 setter 方法。
2 @Autowired@Autowired 註解可以應用到 bean 屬性的 setter 方法,非 setter 方法,建構函式和屬性。
3 @Qualifier通過指定確切的將被連線的 bean,@Autowired 和 @Qualifier 註解可以用來刪除混亂。
4 JSR-250 AnnotationsSpring 支援 JSR-250 的基礎的註解,其中包括了 @Resource,@PostConstruct 和 @PreDestroy 註解。

Spring @Required註釋:

@Required 註釋應用於 bean 屬性的 setter 方法,它表明受影響的 bean 屬性在配置時必須放在 XML 配置檔案中,否則容器就會丟擲一個 BeanInitializationException 異常。下面顯示的是一個使用 @Required 註釋的示例。

示例:

Student.java

package annotation;

import org.springframework.beans.factory.annotation.Required;

public class Student {
    private Integer age;
    private String name;

    public Integer getAge() {
        return age;
    }

    @Required
    public void setAge(Integer age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    @Required
    public void setName(String name) {
        this.name = name;
    }

}

MainApp.java

package annotation;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
    public static void main(String[] args) {
        ApplicationContext context = new 
                ClassPathXmlApplicationContext("Student.xml");
        Student student = (Student) context.getBean("student");
        System.out.println("Name : " + student.getName() );
        System.out.println("Age : " + student.getAge() );
    }
}

Student.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/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

   <context:annotation-config/>

    <!-- Definition for student bean -->
    <bean id="student" class="annotation.Student">
        <property name="name" value="Zara" />
        <property name="age" value="11" />
    </bean>

</beans>

Spring @Autowired註釋:

@Autowired 註釋對在哪裡和如何完成自動連線提供了更多的細微的控制。

@Autowired 註釋可以在 setter 方法中被用於自動連線 bean,就像 @Autowired 註釋,容器,一個屬性或者任意命名的可能帶有多個引數的方法。

  • Setter方法中的@autowired:

    可以在 XML 檔案中的 setter 方法中使用 @Autowired 註釋來除去 元素。當 Spring遇到一個在 setter 方法中使用的 @Autowired 註釋,它會在方法中檢視執行 byType 自動連線。

  • 屬性中的@autowired:

    可以在屬性中使用 @Autowired 註釋來除去 setter 方法。當時使用 為自動連線屬性傳遞的時候,Spring 會將這些傳遞過來的值或者引用自動分配給那些屬性。

  • 建構函式中的@Autowired:

    可以在建構函式中使用 @Autowired。一個建構函式@Autowired 說明當建立 bean 時,即使在 XML 檔案中沒有使用元素配置 bean ,建構函式也會被自動連線。

  • @Autowired的(required=false)選項:

    預設情況下,@Autowired 註釋意味著依賴是必須的,它類似於 @Required 註釋,然而,你可以使用 @Autowired的 (required=false) 選項關閉預設行為。

    @Autowired(required=false)

Spring @Qualifier註釋:

可能會有這樣一種情況,當你建立多個具有相同型別的 bean 時,並且想要用一個屬性只為它們其中的一個進行裝配,在這種情況下,你可以使用 @Qualifier 註釋和 @Autowired 註釋通過指定哪一個真正的 bean 將會被裝配來消除混亂。

示例:

Student.java

package annotation;


public class Student {
    private Integer age;
    private String name;

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Profile.java

package annotation;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

public class Profile {
    @Autowired  
    //在屬性中使用 **@Autowired** 註釋來除去 setter 方法。
    @Qualifier("student2")
    //指定Bean
    private Student student;

    public Profile(){
        System.out.println("Inside Profile constructor." );
    }
    public void printAge() {
        System.out.println("Age : " + student.getAge() );
    }
    public void printName() {
        System.out.println("Name : " + student.getName() );
    }
}

MainApp.java

package annotation;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
    public static void main(String[] args) {
        ApplicationContext context = new 
                ClassPathXmlApplicationContext("Student.xml");
        Profile profile = (Profile)context.getBean("profile");
        profile.printName();
        profile.printAge();
    }
}

Student.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/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

   <context:annotation-config/>

    <bean id="profile" class="annotation.Profile" >
    </bean>

    <!-- Definition for student bean -->
    <bean id="student1" class="annotation.Student">
        <property name="name" value="Zara" />
        <property name="age" value="11"/>
    </bean>

    <bean id="student2" class="annotation.Student">
        <property name="name" value="join" />
        <property name="age" value="13"/>
    </bean>

</beans>

Spring JSR-250註釋:

Spring還使用基於 JSR-250 註釋,它包括 @PostConstruct, @PreDestroy 和 @Resource 註釋。

@PostConstruct 和 @PreDestroy 註釋:

為了定義一個 bean 的安裝和解除安裝,我們使用 init-method 和/或 destroy-method 引數簡單的宣告一下 。init-method 屬性指定了一個方法,該方法在 bean 的例項化階段會立即被呼叫。同樣地,destroy-method 指定了一個方法,該方法只在一個 bean 從容器中刪除之前被呼叫。

你可以使用 @PostConstruct 註釋作為初始化回撥函式的一個替代,@PreDestroy 註釋作為銷燬回撥函式的一個替代。

@Resource 註釋:

可以在欄位中或者 setter 方法中使用 @Resource 註釋,它和在 Java EE 5 中的運作是一樣的。@Resource 註釋使用一個 ‘name’ 屬性,該屬性以一個 bean 名稱的形式被注入。你可以說,它遵循 by-name 自動連線語義。

Spring基於Java的配置:

基於 Java 的配置選項,可以使在不用配置 XML 的情況下編寫大多數的 Spring,但是一些有幫助的基於 Java 的註解,解釋如下:

@Configuration 和 @Bean 註解

帶有 @Configuration 的註解類表示這個類可以使用 Spring IoC 容器作為 bean 定義的來源。@Bean 註解告訴 Spring,一個帶有 @Bean 的註解方法將返回一個物件,該物件應該被註冊為在 Spring 應用程式上下文中的 bean。

示例:

HelloWorldConfig.java

package annotation;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class HelloWorldConfig {
    @Bean
    public HelloWorld helloWorld() {
        return new HelloWorld();
    }
}

HelloWorld.java

package annotation;

public class HelloWorld {
    private String message;

    public void setMessage(String message){
        this.message  = message;
    }

    public void getMessage(){
        System.out.println("Your Message : " + message);
    }
}

MainApp.java

package annotation;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MainApp3 {

    public static void main(String[] args) {
        ApplicationContext ctx = 
                new AnnotationConfigApplicationContext(HelloWorldConfig.class);

        HelloWorld helloWorld = ctx.getBean(HelloWorld.class);
        helloWorld.setMessage("Hello World!");
        helloWorld.getMessage();
    }
}

注入Bean的依賴性:

當 @Beans 依賴對方時,表達這種依賴性非常簡單,只要有一個 bean 方法呼叫另一個。如下所示:

package com.tutorialspoint;
import org.springframework.context.annotation.*;
@Configuration
public class AppConfig {
   @Bean
   public Foo foo() {
      return new Foo(bar());
   }
   @Bean
   public Bar bar() {
      return new Bar();
   }
}

這裡,foo Bean 通過建構函式注入來接收參考基準。

@Import註釋:

@import 註解允許從另一個配置類中載入 @Bean 定義。考慮 ConfigA 類,如下所示:

@Configuration
public class ConfigA {
   @Bean
   public A a() {
      return new A(); 
   }
}

你可以在另一個 Bean 宣告中匯入上述 Bean 宣告,如下所示:

@Configuration
@Import(ConfigA.class)
public class ConfigB {
   @Bean
   public B a() {
      return new A(); 
   }
}

現在,當例項化上下文時,不需要同時指定 ConfigA.class 和 ConfigB.class,只有 ConfigB 類需要提供,如下所示:

public static void main(String[] args) {
   ApplicationContext ctx = 
   new AnnotationConfigApplicationContext(ConfigB.class);
   // now both beans A and B will be available...
   A a = ctx.getBean(A.class);
   B b = ctx.getBean(B.class);
}

生命週期回撥:

@Bean 註解支援指定任意的初始化和銷燬的回撥方法,就像在 bean 元素中 Spring 的 XML 的初始化方法和銷燬方法的屬性:

public class Foo {
   public void init() {
      // initialization logic
   }
   public void cleanup() {
      // destruction logic
   }
}

@Configuration
public class AppConfig {
   @Bean(initMethod = "init", destroyMethod = "cleanup" )
   public Foo foo() {
      return new Foo();
   }
}

指定 Bean 的範圍:

預設範圍是單例項,但是你可以重寫帶有 @Scope 註解的該方法,如下所示:

@Configuration
public class AppConfig {
   @Bean
   @Scope("prototype")
   public Foo foo() {
      return new Foo();
   }
}

Spring中的事件處理:

Spring 的核心是 ApplicationContext,它負責管理 beans 的完整生命週期。當載入 beans 時,ApplicationContext 釋出某些型別的事件。例如,當上下文啟動時,ContextStartedEvent 釋出,當上下文停止時,ContextStoppedEvent 釋出。

通過 ApplicationEvent 類和 ApplicationListener 介面來提供在 ApplicationContext 中處理事件。如果一個 bean 實現 ApplicationListener,那麼每次 ApplicationEvent 被髮布到 ApplicationContext 上,那個 bean 會被通知。

Spring 提供了以下的標準事件:

序號 Spring 內建事件 & 描述
1 ContextRefreshedEvent ApplicationContext 被初始化或重新整理時,該事件被髮布。這也可以在 ConfigurableApplicationContext 介面中使用 refresh() 方法來發生。
2 ContextStartedEvent 當使用 ConfigurableApplicationContext 介面中的 start() 方法啟動 ApplicationContext 時,該事件被髮布。你可以調查你的資料庫,或者你可以在接受到這個事件後重啟任何停止的應用程式。
3 ContextStoppedEvent 當使用 ConfigurableApplicationContext 介面中的 stop() 方法停止 ApplicationContext 時,釋出這個事件。你可以在接受到這個事件後做必要的清理的工作。
4 ContextClosedEvent 當使用 ConfigurableApplicationContext 介面中的 close() 方法關閉 ApplicationContext 時,該事件被髮布。一個已關閉的上下文到達生命週期末端;它不能被重新整理或重啟。
5 RequestHandledEvent 這是一個 web-specific 事件,告訴所有 bean HTTP 請求已經被服務。

由於 Spring 的事件處理是單執行緒的,所以如果一個事件被髮布,直至並且除非所有的接收者得到的該訊息,該程序被阻塞並且流程將不會繼續。因此,如果事件處理被使用,在設計應用程式時應注意。

監聽上下文事件:

為了監聽上下文事件,一個 bean 應該實現只有一個方法 onApplicationEvent() 的 ApplicationListener 介面。因此,我們寫一個例子來看看事件是如何傳播的,以及如何可以用程式碼來執行基於某些事件所需的任務。

HelloWorld.java

package annotation;

public class HelloWorld {
    private String message;

    public void setMessage(String message){
        this.message  = message;
    }

    public void getMessage(){
        System.out.println("Your Message : " + message);
    }
}

CStartEventHandler.java

package annotation;

import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextStartedEvent;

public  class CStartEventHandler 
    implements ApplicationListener<ContextStartedEvent> {
    @Override
    public void onApplicationEvent(ContextStartedEvent arg0) {
        System.out.println("ContextStartedEvent Received");
    }
}

 CStopEventHandler.java

package annotation;

import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextStoppedEvent;

public class CStopEventHandler implements 
    ApplicationListener<ContextStoppedEvent> {

    @Override
    public void onApplicationEvent(ContextStoppedEvent arg0) {
        System.out.println("ContextStoppedEvent Received");
    }
}

MainApp4.java

package annotation;

import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp4 {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = new
                ClassPathXmlApplicationContext("Event.xml");
        context.start();

        HelloWorld obj = (HelloWorld)context.getBean("helloWorld");
        obj.getMessage();

        context.stop();
    }
}

Event.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
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id="helloWorld" class="annotation.HelloWorld">
      <property name="message" value="Hello World!"/>
   </bean>

   <bean id="cStartEventHandler" 
         class="annotation.CStartEventHandler"/>

   <bean id="cStopEventHandler" 
         class="annotation.CStopEventHandler"/>
</beans>

執行結果:

ContextStartedEvent Received
Your Message : Hello World!
ContextStoppedEvent Received

Spring中的自定義事件:

這個是 CustomEvent.java 檔案的內容:

package annotation;
import org.springframework.context.ApplicationEvent;
public class CustomEvent extends ApplicationEvent{
    public CustomEvent(Object source) {
        super(source);
    }   
    public String toString() {
        return "My Custom Event";
    }
}

下面是 CustomEventPublisher.java 檔案的內容:

package annotation;

import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
public class CustomEventPublisher 
   implements ApplicationEventPublisherAware {
   private ApplicationEventPublisher publisher;
   public void setApplicationEventPublisher
              (ApplicationEventPublisher publisher){
      this.publisher = publisher;
   }
   public void publish() {
      CustomEvent ce = new CustomEvent(this);
      publisher.publishEvent(ce);
   }
}
package com.tutorialspoint;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
public class CustomEventPublisher 
   implements ApplicationEventPublisherAware {
   private ApplicationEventPublisher publisher;
   public void setApplicationEventPublisher
              (ApplicationEventPublisher publisher){
      this.publisher = publisher;
   }
   public void publish() {
      CustomEvent ce = new CustomEvent(this);
      publisher.publishEvent(ce);
   }
}

下面是 CustomEventHandler.java 檔案的內容:

package annotation;

import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextStoppedEvent;

public class CStopEventHandler implements 
    ApplicationListener<ContextStoppedEvent> {

    @Override
    public void onApplicationEvent(ContextStoppedEvent arg0) {
        System.out.println("ContextStoppedEvent Received");
    }
}

下面是 MainApp.java 檔案的內容:

package annotation;

import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp5 {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = new 
                ClassPathXmlApplicationContext("Custom.xml");
        CustomEventPublisher cvp = (CustomEventPublisher)
                context.getBean("customEventPublisher");
        cvp.publish();
        cvp.publish();
    }
}

下面是配置檔案Custom.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
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id="customEventHandler" 
      class="annotation.CustomEventHandler"/>

   <bean id="customEventPublisher" 
      class="annotation.CustomEventPublisher"/>

</beans>

程式執行結果:

My Custom Event
My Custom Event

不同配置方式的比較

基於XML配置 基於註解配置 基於Java類配置
Bean定義 在XML檔案中通過