Spring定義Bean的兩種方式:和@Bean


前言:
    Spring中最重要的概念IOC和AOP,實際圍繞的就是Bean的生成與使用。

    什么叫做Bean呢?我們可以理解成對象,每一個你想交給Spring去托管的對象都可以稱之為Bean。

    今天通過Spring官方文檔來了解下,如何生成bean,如何使用呢?



1.通過XML的方式來生成一個bean
    最簡單也是最原始的一種方式,通過XML來定義一個bean,我們來看下其過程



    1)創建entity,命名為Student

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student implements Serializable {

    private static final long serialVersionUID = -2088281526481179972L;
    private int id;
    private String name;
    private int age;
}
    2)在beans.xml中定義Student


    <!-- 1.空值的student -->
    <bean id="studentNoValue" class="domain.Student"/>

    <!-- 2.帶值的student -->
    <bean id="student" class="domain.Student">
        <property name="id" value="11"/>
        <property name="age" value="22"/>
        <property name="name" value="jack"/>
    </bean>

    <!-- 3.全參構造:使用成員變量名稱對應 -->
    <bean id="studentConstruct" class="domain.Student">
        <constructor-arg name="age" value="22"></constructor-arg>
        <constructor-arg name="id" value="11"></constructor-arg>
        <constructor-arg name="name" value="jack"></constructor-arg>
    </bean>

    <!-- 4.全參構造:使用成員變量index對應 -->
    <bean id="studentConstruct2" class="domain.Student">
        <constructor-arg index="0" value="11"></constructor-arg>
        <constructor-arg index="1" value="jack"></constructor-arg>
        <constructor-arg index="2" value="22"></constructor-arg>
    </bean>

    <!-- 5.全參構造:使用成員變量類型對應 -->
    <bean id="studentConstruct3" class="domain.Student">
        <constructor-arg type="int" value="11"></constructor-arg>
        <constructor-arg type="java.lang.String" value="jack"></constructor-arg>
        <constructor-arg type="int" value="22"></constructor-arg>
    </bean>
    總結:可以看到,創建bean的方式多種多樣,我們可以通過屬性來賦值<property>,也可以通過構造參數來賦值<constructor>,關於構造賦值以上展示了三種方式,我們可以根據自己的需求來選擇對應的方式。



    3)測試bean

public class ApplicationContextTest {

    @Test
    public void testXml(){
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        Student studentNoValue = (Student) applicationContext.getBean("studentNoValue");
        Student studentFullValue = (Student) applicationContext.getBean("studentFullValue");
        System.out.println(studentNoValue);
        System.out.println(studentFullValue);


        Student studentConstruct1 = (Student) applicationContext.getBean("studentConstruct");
        Student studentConstruct2 = (Student) applicationContext.getBean("studentConstruct2");
        Student studentConstruct3 = (Student) applicationContext.getBean("studentConstruct3");
        System.out.println(studentConstruct1);
        System.out.println(studentConstruct2);
        System.out.println(studentConstruct3);

        Book bookChinese = (Book) applicationContext.getBean("bookChinese");
        System.out.println(bookChinese);
    }
}
// res:
Student(id=0, name=null, age=0)
Student(id=11, name=jack, age=22)
Student(id=11, name=jack, age=22)
Student(id=11, name=jack, age=22)
Student(id=11, name=jack, age=22)
2.<bean>標簽深入了解
    我們剛才介紹了最基本的Bean使用方式,大家會發現<bean>標簽還有其他的屬性,比如name/scope/lazy-init/init-method/...等,這些是做什么用的呢?我們在實際的工作中怎么使用呢?



    1)name屬性

    在介紹name屬性之前,我們先來看下ApplicationContext.getBean()的兩種方式

    * ApplicationContext.getBean(String name)

    * ApplicationContext.getBean(Class<T> requiredType)



    第一種方式的這個name是什么呢?我們應該如何定義,又該如何使用呢?

// 上文示例中,我們只是指定了Bean的id和class,如下所示
<bean id="studentNoValue" class="domain.Student" />

// 具體獲取bean的方式如下:
Student studentNoValue = (Student) applicationContext.getBean("studentNoValue");

// 可以看到,在沒有指定bean的name屬性的時候,默認使用id來獲取bean,當做name使用
// 如果我們不想根據id獲取,那就需要主動指定bean的name屬性,如下所示:
<bean id="studentNoValue" class="domain.Student" name="stuName"/>
// 這樣在獲取的時候,就需要使用指定的名稱來獲取,再根據id來獲取的時候就會報錯了
Student studentNoValue = (Student) applicationContext.getBean("stuName");
    * 根據Class來獲取這種方式很好理解,這個不關心你定義的id或者name是什么,使用如下:

Student studentNoValue = (Student) applicationContext.getBean(Student.class);
    2)scope屬性

    可以看到,在使用scope屬性的時候,提示有兩種輸入值,分別是singleton/prototype

    這個就代表了Spring-Bean的兩種創建模式,單例模式和原型模式

    * Spring默認使用單例模式來創建Bean,通過ApplicationContext所獲得的bean都是同一個bean(在beanName相同的情況下),我們可以來驗證下

Student studentNoValue = (Student) applicationContext.getBean("stuName");
Student studentNoValue2 = (Student) applicationContext.getBean("stuName");

System.out.println(studentNoValue == studentNoValue2);// true
    可以看到的是結果輸入為true,從工廠類中兩次獲取的stuName是同一個對象。



    * 下面來驗證下原型模式

    原型模式:每次獲取的bean都為一個新的對象

// 修改beans.xml中studentNoValue的scope為prototype
<bean id="studentNoValue" class="domain.Student" name="stuName" scope="prototype"/>

// 然后執行上面的測試代碼
Student studentNoValue = (Student) applicationContext.getBean("stuName");
Student studentNoValue2 = (Student) applicationContext.getBean("stuName");

System.out.println(studentNoValue == studentNoValue2);// false
    可以看到,輸出結果為false,原型模式下從工廠類兩次獲取的stuName不是同一個對象。



    3)init-method和destroy-method方法

    見名知意,init-method應該是初始化方法的意思,destroy-method應該是銷毀方法的意思。那怎么使用呢?

// 在Student.java中添加init()方法和destroy()方法
public void init(){
    System.out.println("student init...");
}

public void destroy(){
    System.out.println("student destroy...");
}

// 在beans.xml中studentNoValue的bean上添加 init-method和destroy-method
<bean id="studentNoValue" class="domain.Student" name="stuName" init-method="init" destroy-method="destroy"/>

// 測試方法如下:
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
Student studentNoValue = (Student) applicationContext.getBean("stuName");

applicationContext.close();

// 執行結果:
student init...
student destroy...    
    總結:在獲取bean的時候init()方法被執行,在容器被銷毀的時候,執行了destroy()方法

    根據這個,我們可以在初始化bean和銷毀bean的時候做點什么,比如關閉連接,保存記錄之類的操作。

    延伸:那么初始化init()方法在構造方法之前調用,還是之后調用呢?讀者可以自行驗證下



    總結:還有一些其他屬性,筆者就不再一一驗證了,下面說一下通過JavaConfig的方法來實現bean的定義。



3.JavaConfig方式的bean定義
    JavaConfig是Spring4.x推薦的配置方式,可以完全替代XML的方式定義。

    1)如何定義一個Bean

// 創建一個類,命名為SpringConfiguration
@Configuration
public class SpringConfiguration {
    @Bean
    public Student student(){
        return new Student(11,"jack",22);
    }
}

// 使用bean
AnnotationConfigApplicationContext applicationContext
                = new AnnotationConfigApplicationContext(SpringConfiguration.class);
Student student = (Student) applicationContext.getBean("student")
System.out.println(student);

// res:
Student(id=11, name=jack, age=22)
    相對於XML的使用方式而言,JavaConfig的使用方式基本是同步的

    * @Configuration等同於<beans></beans>

    * @Bean等同於<bean></bean>

    * 通過AnnotationConfigApplicationContext來加載JavaConfig

    * 方法名student()就等同於<bean>中的id,默認方法名就是beanName



    2)@Bean的其他參數

    * name屬性等同於<bean>的name

    * initMethod屬性等同於<bean>的init-method

    * destroyMethod屬性等同於<bean>的destroy-method

    * scope這個比較奇怪,不屬於@Bean的參數,這是一個單獨的注解,使用方式如下

@Bean(name = "stu",autowire = Autowire.BY_TYPE)
@Scope(value = "singleton")
public Student student(){
    return new Student(11,"jack",22);
}
總結:

    以上全文,我們通過兩種方式來定義一個Bean,默認推薦JavaConfig。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM