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
