spring_bean三種裝配方式


bean的裝配

bean裝配:spring ioc 容器將bean對象創建好並傳遞給使用者的過程叫bean的裝配

spring ioc 會創建我們在配置文件中配置好的對象,並將對象返回給使用者,spring ioc創建對象的方式有以下三種  

  1:默認方式,通過構造器來創建

<bean id="自定義id" class="接口的實現類" />

  2:實例工廠

<bean id="factory" class="工廠類" />
<bean id="自定義id" factory-bean="factory" factory-method="調用的實例化工廠方法" />

  3:靜態工廠

<bean id="自定義id" class="工廠類" factory-method="靜態工廠方法" />

# 默認方式

該方式spring ioc容器會調用bean(接口實現類)的無參構造方法來創建對象,當創建一個java類后,系統會自動在類中創默認構造函數,當自己創建個構造方法時默認構造函數就會不存在,所以開發者需確保在bean中存在無參構造方法

<!-- 默認方式 -->
<bean id="studentService" class="com.doaoao.impl.StudentServiceImpl"/>

# 實例工廠

1:定義一個工廠類,該類中的方法都是非靜態的(方法的返回值為StudentService類型)

package com.doaoao.factory;
import com.doaoao.impl.StudentServiceImpl;
import com.doaoao.service.StudentService;
public class BeanFactory {
    public StudentService createStudentService(){
        return new StudentServiceImpl();
    }
}

2:修改配置文件中的內容(主要為了告訴spirng我們要使用 實例工廠 方法)

<!-- 創建實例工廠配置溫江 id 和class  -->
<bean id="myFactory" class="com.doaoao.factory.BeanFactory" />

<!-- 將上創建的實例工廠 myFactory添加進去,利用實例工廠中的方法 factory-method指定的方法,來創建studentService -->
<bean id="studentService" factory-bean="myFactory" factory-method="createStudentService" />

其它與之前的相同

# 靜態工廠(中的方法都是 static 修飾的)

1:定義一個工廠類,類的中的方法都為靜態方法(從該類中來看和實例工廠對比只是多了一個static)

package com.doaoao.factory;
import com.doaoao.impl.StudentServiceImpl;
import com.doaoao.service.StudentService;
public class StaticBeanFactory {
    public static StudentService createStudentService(){
        return new StudentServiceImpl();
    }
}

2:修改配置文件中的內容

<!-- 靜態工廠:調用class指定的工廠類的方法 createStudentService 來創建 id 指定的對象-->
<bean id="studentService" class="com.doaoao.factory.StaticBeanFactory" factory-method="createStudentService" />

## 注:在使用時,一般使用默認方式即可


 ## bean的作用域

  singleton: 單例模式。即在一個Spring ioc容器中,只創建一個對象,默認為單例模式

  prototype: 原型模式。即每次使用 getBean 方法獲取的同一個bean的實例都是一個新的實例

  request:對於每次 HTTP 請求,都將會產生一個不同的 Bean 實例

  session:對於每個不同的 HTTP session,都將產生一個不同的 Bean 實例(同一個瀏覽器中產生同一個session)

  application:在一個web應用中會產生一個bean實例,就相當於在一個ServletContext中只有該bean的實例

  websocket:在一個websocket中會產生一個bean實例

單利模式例子:

1:在StudetnServiceImpl.java中創建一個無參構造方法

package com.doaoao.impl;
import com.doaoao.service.StudentService;
public class StudentServiceImpl implements StudentService {
    @Override
    public void testDao() {
        System.out.println("Hello World");
    }
    public StudentServiceImpl(){
        System.out.println("執行 StudentService的構造方法");
    }
}

2:在測試類中創建兩個對象,分別執行兩個對象,看輸出

    @Test
    public void sprintTest(){
        // 讀取spring配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        // 從配置文件中獲取對應id所對應的對象
        StudentService studentService = (StudentService) context.getBean("studentService");
        StudentService studentService1 = (StudentService) context.getBean("studentService");

        System.out.println(studentService);
        System.out.println(studentService1);
    }

3:輸出結果分析:只執行了一次bean中的構造方法,因為在創建對象時會執行構造方法,說明單利模式只創建了一次構造方法

執行 StudentService的構造方法
com.doaoao.impl.StudentServiceImpl@64cd705f
com.doaoao.impl.StudentServiceImpl@64cd705f 

## 在配置文件中將作用域修改為singleton(單例模式)

<bean id="studentService" class="com.doaoao.impl.StudentServiceImpl" scope="singleton"/>

# 輸出結果和上方默認方式相同
執行 StudentService的構造方法
com.doaoao.impl.StudentServiceImpl@418e7838
com.doaoao.impl.StudentServiceImpl@418e7838

## 在配置文件中將作用域修改為 prototype(原型模式)每次使用getBean時都會創建

<bean id="studentService" class="com.doaoao.impl.StudentServiceImpl" scope="prototype"/>

# 輸出 <!-- 執行兩次構造方法 -->
執行 StudentService的構造方法
執行 StudentService的構造方法
com.doaoao.impl.StudentServiceImpl@5ae50ce6
com.doaoao.impl.StudentServiceImpl@6f96c77

 ## BeanPostProcessor 接口

實現該接口的類稱為bean后處理器,在該類中重寫兩個方法"postProcessBeforeInitialization" 和 "postProcessAfterInitialization",在獲得某個bean的對象后,在該對象的執行之前和執行之后分別調用上面兩個方法,我們可以通過這兩個方法實現特定的功能

以下下為實例:

package com.doaoao.processor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class BeanPostProcessorTest implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("執行postProcessBeforeInitialization");
        // 注意:這里不能返回null,必須返回bean
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(final Object bean, String beanName) throws BeansException {
        if("studentService".equals(beanName)){
            //創建
            InvocationHandler invocationHandler = ((Object p,Method method,Object[] args)->{
                // 調用study方法時,使用動態代理對其進行增強
                if("study".equals(method.getName())) {
                    System.out.println("目標方法開始執行");
                    // 執行目標方法
                    Object result = method.invoke(bean, args);

                    System.out.println("目標方法結束執行");
                    return result;
                }
                return method.invoke(bean,args);
            });

            // 增強bean
            Object proxy = Proxy.newProxyInstance(
                    bean.getClass().getClassLoader(),
                    bean.getClass().getInterfaces(),
                    invocationHandler
            );
            System.out.println("postProcessAfterInitialization執行");
            return proxy;
        }
        return bean;
    }
}

 ## bean的生命周期

可以指定bean在初始化和銷毀時執行特定的方法

1:在StudentServiceImpl類中創建兩個方法 init 和 destroy

package com.doaoao.impl;
import com.doaoao.service.StudentService;
public class StudentServiceImpl implements StudentService {
    @Override
    public void testDao() {
        System.out.println("Hello World");
    }
    public StudentServiceImpl(){
        System.out.println("執行 StudentService的構造方法");
    }

    public void init(){
        System.out.println("執行初始化方法");
    }
    public void destroy(){
        System.out.println("執行銷毀方法");
    }
}

2:在配置文件中添加兩個屬性 init-method 和 destroy-method 分別指定初始化方法和銷毀方法

    <bean id="studentService" class="com.doaoao.impl.StudentServiceImpl" init-method="init" destroy-method="destroy"/>

 3:修改測試類中的內容

    @Test
    public void sprintTest(){
        // 讀取spring配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        // 從配置文件中獲取對應id所對應的對象
        StudentService studentService = (StudentService) context.getBean("studentService");

        // 調用對象中的指定方法
        studentService.testDao();

        // 將context給關閉
        ((ClassPathXmlApplicationContext) context).close();
    }

 4:查看輸出(當創建時執行的方法,當銷毀時執行的方法)

執行 StudentService的構造方法
執行初始化方法
Hello World
執行銷毀方法

...

本筆記參考自:小猴子老師教程 http://www.monkey1024.com


免責聲明!

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



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