文章目錄
- 一. 關于Bean作用域的實例
- 1. lombok
- 2. 實例代碼
- 二. 作用域定義
- 1. Bean的六種作用域
- 2. 設置作用域
- 三. Spring 執行流程和 Bean 的生命周期
- 1. Spring 執行流程
- 2. Bean生命周期
一. 關于Bean作用域的實例
注意在此例子中需要用到lombok
1. lombok
lombok是什么?
Lombok 是一個 Java 庫,它通過注解的方式來簡化 Java 代碼的編寫。它提供了一組注解,讓我們可以通過在代碼中添加這些注解來自動生成樣板式的代碼,如 getter、setter、構造函數、toString 等。
使用 Lombok 可以有效地減少冗余的樣板代碼,提高代碼的可讀性和開發效率。不需要手動編寫大量的 getter 和 setter 方法,也不需要重復編寫 equals、hashCode 和 toString 方法等。通過簡單地添加幾個注解,Lombok 會在編譯時自動生成這些常見的方法和實現。
lombok的使用:
- 在框架中添加
lombok
依賴.
- 在實體類上使用
lombok
提供的注解.
- 安裝
lombok
插件
2. 實例代碼
Users
:
package com.java.demo.enity;import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;@Controller
public class Users {@Beanpublic User user1(){User user = new User();user.setId(1);user.setName("xxxflower");return user;}
}
UserControlle
:
package com.java.demo.controller;import com.java.demo.enity.User;
import org.springframework.stereotype.Controller;import javax.annotation.Resource;@Controller
public class UserController {@Resourceprivate User user1;public User UserPrint1() {User user = user1;System.out.println("Bean 原 Name:" + user.getName());user.setName("且聽風吟"); // 進?了修改操作System.out.println("UserController 修改后 Name: "+user.getName());return user;}
}
UserController2
:
package com.java.demo.controller;import com.java.demo.enity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;@Controller
public class UserController2 {@Autowiredprivate User user1;public User UserPrint2() {User user = user1;System.out.println(user.toString());return user;}
}
App
:
package com.java.demo;import com.java.demo.controller.UserController;
import com.java.demo.controller.UserController2;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Controller;@Controller
public class App {public static void main(String[] args) {ApplicationContext context =new ClassPathXmlApplicationContext("spring-config.xml");UserController userController = context.getBean("userController",UserController.class);System.out.println(userController.UserPrint1());UserController2 userController2 = context.getBean("userController2",UserController2.class);System.out.println(userController2.UserPrint2());}
}
代碼預計運行結果:
代碼實際運行結果:
我們可以看到上述第三行代碼和我們預計的結果不符,這是為什么呢?
以上問題的原因是Bean默認情況下采用的是單例狀態.(singleton),也就是所有的人使用的都是同一個Bean對象.在我們之前學習過的單例模式中,采用單例模式可以很大程度上提高性能,所以在Spring中Bean的作用域默認也是 singleton
單例模式.
二. 作用域定義
限定程序中變量的可?范圍叫做作?域,或者說在源代碼中定義變量的某個區域就叫做作?域。
而 Bean 的作用域是指 Bean 在 Spring 整個框架中的某種?為模式.比如 singleton 單例作?域,就表示 Bean 在整個 Spring 中只有?份,它是全局共享的,那么當其他?修改了這個值之后,那么另?個?讀取到的就是被修改的值。
1. Bean的六種作用域
Spring 容器在初始化?個 Bean 的實例時,同時會指定該實例的作?域。Spring有 6 種作?域,最后四種是基于 Spring MVC ?效的:
- 單例模式:
singleton
(默認模式) -> 性能的考慮 - 原型模式:
prototype
- 請求作用域:
request
,每次 HTTP請求,都會創建一個Bean對象。【適用于Spring MVC/Spring Web】 - 會話作用域:
session
,每次Session會話共享一個Bean。【Spring MVC】 - 全局作用域:
application
,一個http servlet context 中共享一個bean。【Spring MVC】 webscoket
: 網絡長連接,只適用于Spring WebSocket 項目。
注意后 4 種狀態是 Spring MVC 中的值,在普通的 Spring 項?中只有前兩種.
singleton
- 官?說明:(Default) Scopes a single bean definition to a single object instance for each Spring IoC container.
- 描述:該作?域下的Bean在IoC容器中只存在?個實例:獲取Bean(即通過applicationContext.getBean等?法獲取)及裝配Bean(即通過@Autowired注?)都是同?個對 象。
- 場景:通常?狀態的Bean使?該作?域。?狀態表示Bean對象的屬性狀態不需要更新 備注:Spring默認選擇該作?域
prototype
- 官?說明:Scopes a single bean definition to any number of object instances.
- 描述:每次對該作?域下的Bean的請求都會創建新的實例:獲取Bean(即通過applicationContext.getBean等?法獲取)及裝配 Bean(即通過@Autowired注?)都是新的對象實例。
- 場景:通常有狀態的Bean使?該作?域
request
- 官?說明:Scopes a single bean definition to the lifecycle of a single HTTP request. That is, each HTTP request has its own instance of a bean created off the back of a single bean definition. Only valid in the context of a web-aware Spring ApplicationContext.
- 描述:每次http請求會創建新的Bean實例,類似于prototype
- 場景:?次http的請求和響應的共享Bean
- 備注:限定SpringMVC中使?
session
- 官?說明:Scopes a single bean definition to the lifecycle of an HTTP Session. Only valid in the context of a web-aware Spring ApplicationContext.
- 描述:在?個http session中,定義?個Bean實例
- 場景:?戶回話的共享Bean, ?如:記錄?個?戶的登陸信息
- 備注:限定SpringMVC中使?
2. 設置作用域
使? @Scope
標簽就可以?來聲明 Bean 的作?域,?如設置 Bean 的作?域,如下代碼所示:
package com.java.demo.enity;import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;@Controller
public class Users {//使用@Scope聲明Bean作用域@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)@Beanpublic User user1(){User user = new User();user.setId(1);user.setName("xxxflower");return user;}
}
運行結果:
我們可以看到,在使用prototype時運行結果與預期結果相同.
關于@Scope的寫法有兩種:
- 直接設置值:
@Scope("prototype")
- 使?枚舉設置:
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
三. Spring 執行流程和 Bean 的生命周期
1. Spring 執行流程
- 在main方法中遇到
Application
時啟動spring
容器。 - 此時根據容器設置的配置文件去找相應配置文件。
- 如果存在basepackage 。此時去循環查看basepackage中是否有五大類注解。
- 如果有五大類注解,此時進行初始化和屬性依賴的賦值。
- 操作spring依賴 讀修改 書寫業務
- 關閉容器 釋放資源
圖解:
Bean 執?流程(Spring 執?流程):啟動 Spring 容器 -> 實例化 Bean(分配內存空間,從?到
有) -> Bean 注冊到 Spring 中(存操作) -> 將 Bean 裝配到需要的類中(取操作)。
2. Bean生命周期
Bean 的生命周期是指一個 Bean 在被創建、初始化、使用和銷毀的整個過程。
Bean 生命周期(從誕生到銷毀過程):
- 開辟內存空間:實例化≠初始化
- 設置屬性(注入屬性)
- 初始化
3.1 各種通知
3.2 初始化前置方法
3.3 初始化方法【兩種實現方式: xml 方式、注解方式】
3.4 初始化后置方法 - 使用 Bean
- 銷毀Bean對象
銷毀容器的各種?法,如 @PreDestroy、DisposableBean 接??法、destroy-method。
注意:一定是先設置屬性,再初始化.因為初始化的時候可能用到屬性的內容.
生命周期演示:
首先,我們創建一個名為 ExampleBean
的 Java 類,實現了 Spring 的 InitializingBean
和 DisposableBean
接口,這兩個接口提供了在 Bean 初始化和銷毀時的回調方法。
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;public class ExampleBean implements InitializingBean, DisposableBean {public ExampleBean() {System.out.println("ExampleBean 構造函數");}@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("ExampleBean 初始化方法");}public void doSomething() {System.out.println("ExampleBean 執行業務邏輯");}@Overridepublic void destroy() throws Exception {System.out.println("ExampleBean 銷毀方法");}
}
然后,在 Spring 的配置文件中聲明該 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"xmlns:content="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"><content:component-scan base-package="com.java.demo"></content:component-scan><bean id="exampleBean" class="com.java.demo.ExampleBean" scope="singleton" init-method="afterPropertiesSet" destroy-method="destroy"/></beans>
在上述配置中,我們將 ExampleBean
聲明為一個 singleton
的 Bean,并指定了初始化方法為 afterPropertiesSet
,銷毀方法為 destroy
。
接下來,我們創建一個簡單的測試類 ExampleApp
來使用 ExampleBean
:
package com.java.demo;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class ExampleApp {public static void main(String[] args) {// 加載 Spring 的配置文件ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");// 獲取 ExampleBean 實例ExampleBean exampleBean =context.getBean("exampleBean",ExampleBean.class);// 執行業務邏輯exampleBean.doSomething();// 關閉 Spring 容器,觸發 Bean 的銷毀方法try {exampleBean.destroy();} catch (Exception e) {e.printStackTrace();}}
}
運行 ExampleApp 類
,結果如下:
需要注意的是,Bean 的生命周期可以進一步通過添加自定義的初始化和銷毀方法來擴展。可以使用 @PostConstruct
和 @PreDestroy
注解,或者在 Spring 配置文件中通過 init-method
和 destroy-method
屬性來指定自定義的初始化和銷毀方法。