首頁 > 軟體

Java Spring中Bean的作用域及生命週期

2022-08-05 22:00:17

1.Bean的作用域

1.1 被修改的Bean案例

原因:Bean的作用域預設是單例模式的,也就是說所有⼈的使⽤的都是同⼀個物件!之前我們學單例模式的時候都知道,使⽤單例可以很⼤程度上提⾼效能,所以在 Spring 中Bean 的作⽤域預設也是 singleton 單例模式。

@Component
public class Users {

    @Bean
    public User user1(){
        User user = new User();
        user.setId(1);
        user.setName("Java");
        return user;
    }
}
@Component
public class Bean1 {

    @Autowired
    private User user;
    public User getUser(){
        System.out.println("Bean1物件未修改name之前 : "+user);
        user.setName("C++");
        return user;
    }
}
@Component
public class Bean2 {
    @Autowired
    private User user;

    public User getUser(){
        return user;
    }
}
public class App {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");

        Bean1 bean1 = context.getBean("bean1",Bean1.class);
        System.out.println(bean1.getUser());
        Bean2 bean2 = context.getBean("bean2",Bean2.class);
        System.out.println(bean2.getUser());
    }
}

1.2 為什麼使用單例模式作為預設作用域

  • 相同資源只建立一份,節省空間
  • 不需要過多的建立和銷燬物件,執行速度提高

1.3 作用域

作用域,一般理解為:限定程式中變數的可⽤範圍叫做作⽤域,或者說在原始碼中定義變數的某個區域就叫做作⽤域。
Bea的作⽤域是指BeanSpring整個框架中的某種⾏為模式,⽐如singleton單例作⽤域,就表
Bean在整個Spring中只有⼀份,它是全域性共用的,那麼當其他⼈修改了這個值之後,那麼另⼀個
⼈讀取到的就是被修改的值。

在Spring中,bean 的作用域被稱為是行為模式,因為在Spring看來,單例模式,就是一種行為,意味著在整個Spring中bean只能存在一份。

1.4 Bean的6種作用域

  • singleton:單例作⽤域
  • prototype:原型作⽤域(多例作⽤域)
  • request:請求作⽤域
  • session:對談作⽤域
  • application:全域性作⽤域
  • websocket:HTTP WebSocket 作⽤域

後四種都是SpringMVC中限定使用的,因此現階段我們只學前兩個就行。

1.5 設定作用域

回到剛才的案例,Bean2希望獲取到的bean物件是未被修改的,我們就可以將單例模式修改為多例模式。

使用@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)

使用@Scope("prototype")

2.Spring執行流程和Bean的生命週期

ps:當執行性到裝配Bean的屬性那一步時,當掃描到有屬性注入時,會先停下類注入,優先進行屬性注入,因為後面的方法可能會用到該屬性。

2.1 Bean的生命週期

所謂的生命週期指的是一個物件從誕生到銷燬的整個生命過程,我們把這個過程就叫做一個物件的生命週期。

Bean 的生命週期分為以下5大部分:

  • 1.範例化 Bean(為 Bean 分配記憶體空間)
  • 2.設定屬性(Bean 注入和裝配)
  • 3.Bean 初始化
實現了各種 Aware 通知的方法,如 BeanNameAware、BeanFactoryAware、 ApplicationContextAware 的介面方法,例如:Spring在初始化 bean,是需要給 bean 賦予 id(name)。而設定 beanName 成功的話,就會生成一個 beadNameAware 通知;執行 BeanPostProcessor 初始化前置方法(如果沒有重寫此方法,按照原始碼操作);執行 @PostConstruct 初始化方法,依賴注入操作之後被 執行;執行自己指定的 init-method 方法(如果有指定的話),是Spring中bean標籤內指定的方法;

這個初始化方法和上面一個用註解初始化的方法是兩個不同時期的產物,init是xml時代產物,@PostConstruct是註解時代產物。優先順序:當樑總方法同時存在時,優先執行註解,再執行init執行 BeanPostProcessor 初始化後置方法(如果沒有重寫此方法,按照原始碼操作)。
  • 4.使用 Bean
  • 5.銷燬 Bean銷燬容器的各種方法, 如 @PreDestroy、DisposableBean 介面方法、destroy-method。

@PreDestroy和destroy-method的關係和初始化方法的兩個關係差不多
優先順序:@ProDestroy > 重寫的DisposableBean介面方法 > destroy-method

執行流程圖如下:

ps:範例化和初始化的區別:範例化就是 分配記憶體空間。初始化,就是把我們一些引數,方法的具體實現邏輯給載入進去。

2.1.1生命週期演示

xml設定如下:

Bean

public class BeanLifeComponent implements BeanNameAware {
    @PostConstruct
    public void PostConstruct(){
        System.out.println("執行@PostConstruct");
    }
    public void init(){
        System.out.println("執行bean-init-method");
    }
    public void use(){
        System.out.println("正在使用bean");
    }
    @PreDestroy
    public void PreDestroy(){
        System.out.println("執行@PreDestroy");
    }
    public void setBeanName(String s){
        System.out.println("執行了Aware通知");
    }
}

啟動類

public class App2 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        BeanLifeComponent beanLifeComponent = context.getBean(BeanLifeComponent.class);
        beanLifeComponent.use();
        context.destroy();
    }
}

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: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.beans"></content:component-scan>
    <bean id="1" class="com.beans.BeanLifeComponent" init-method="init"></bean>
</beans>

2.1.2 為什麼要先設定屬性,在進行初始化

@Controller
public class TestUser {
    @Autowired
    private Test test;

    public TestUser(){
        test.sayHi();
        System.out.println("TestUser->呼叫構造方法");
    }
}

如果這段程式碼先執行了初始化,也就是其構造方法,會用到test物件,此時還沒有設定屬性,test就為null,會造成空指標異常。因此必須先設定屬性,在進行初始化。

到此這篇關於Java Spring中Bean的作用域及生命週期的文章就介紹到這了,更多相關Java Spring Bean 內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com