如何手動實現Spring Bean的生命週期全過程

spring bean注入方式

構造器注入

    <!--構造器注入-->
    <bean id="user" class="com.sean.spring.User">
        <constructor-arg index="0" value="德萊文"/>
        <constructor-arg index="1" value="18"/>
    </bean>

setter注入

    <!--setter注入-->
    <bean id="user" class="com.sean.spring.User">
        <property name="name" value="無敵"></property>
        <property name="age" value="18"></property>
    </bean>

如果我們一個類中多個參數,那麼我們要賦值豈不是通過以上兩種方法要寫很多,除了通過xml注入,還可以通過註解的方式注入注入。
context:annotation-config ,用於激活那些已經在spring容器裏註冊過的bean

    <context:annotation-config></context:annotation-config>
    <bean id="user" class="com.sean.spring.User"/>

然後在類中需要注入值的屬性上添加@Autowired,如果需要設置,可通過 @Value直接給值

    @Autowired
    @Value("無敵")
    public void setName(String name) {
        this.name = name;
    }
    @Autowired
    @Value("25")
    public void setAge(Integer age) {
        this.age = age;
    }

當然項目中有很多類,通過這種方式,豈不是也要配置很多的bean,別怕,Spring提供了掃描包的方式。
context:component-scan自動將帶有@component,@service,@Repository等註解的對象註冊到spring容器中的功能。

<context:component-scan base-package="com.sean.spring" />

只需在類中添加@Component

@Component
public class User{

    private Long id;

    private String name;

    private Integer age;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    @Autowired
    @Value("無敵")
    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }


    public String getUser(){
        String user = "我的名字是"+ name+"我今年" + age+"歲";
        return user;
    }
}

測試後輸出:

我們將applicationContext.xml配置文件作如下修改:
在這裏插入圖片描述
關於spring配置註解context:annotation-configcontext:component-scan區別,網上很多博客都有講解
https://www.cnblogs.com/leiOOlei/p/3713989.html

Spring bean 的生命週期

  • 如果Bean實現了BeanNameAwaresetBeanName方法,那麼它就會調用這個方法。
  • 如果Bean實現了BeanFactoryAwaresetBeanFactory方法,那麼它就會調用這個方法。
  • 如果Bean實現了ApplicationContextAwaresetApplicationContext方法,且Spring IoC容器也必須是一個ApplicationContext接口的實現類,那麼纔會調用這個接口,否則不調用
  • 如果Bean實現了BeanPostProcessorpostProcessBeforeInitialization方法,那麼它就會調用這個方法。
  • 如果Bean實現了InitializingBeanafterPropertiesSet方法,那麼它就會調用這個方法。
  • 如果Bean自定義了初始化方法,那麼它就會調用這個方法。
  • 如果Bean實現了BeanPostProcessorpostProcessAfterInitialization方法,完成這些調用,這時候Bean就完成了初始化
  • 當服務器關閉,調用對應額方法完成Bean的銷燬
  • 如果Bean實現了DisposableBeandestroy方法,那麼它就會調用這個方法。
  • 如果自定義銷燬對象,那麼就會調用它。

下邊我們來測試一下,先測試一下BeanPostProcessor接口。
我們下一個實現類BeanPostProcessorImpl

public class BeanPostProcessorImpl implements BeanPostProcessor {
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("【"+this.getClass().getSimpleName()+"】"+beanName + "開始實例化");
        return  bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("【"+this.getClass().getSimpleName()+"】"+beanName + "實例化完成");
        return  bean;
    }
}

這樣一個BeanPostProcessor 就被我們用代碼實現了,它會處理Spring IoC容器所有的Bean

測試生命週期

public class User implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean {

    private Long id;

    private String name;

    private Integer age;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }


    public void init(){
        System.out.println("【"+this.getClass().getSimpleName()+"】" + "執行自定義初始化方法");
    }

    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("【"+this.getClass().getSimpleName()+"】" + "setBeanFactory");
    }

    public String getUser(){
        String user = "我的名字是"+ name+"我今年" + age+"歲";
        return user;
    }

    public void setBeanName(String s) {
        System.out.println("【"+this.getClass().getSimpleName()+"】"+ "setBeanName");
    }

    public void myDestroy() throws Exception {
        System.out.println("【"+this.getClass().getSimpleName()+"】"+ "自定義銷燬");
    }

    public void destroy() throws Exception {
        System.out.println("【"+this.getClass().getSimpleName()+"】"+ "destroy");
    }

    public void afterPropertiesSet() throws Exception {
        System.out.println("【"+this.getClass().getSimpleName()+"】" + "afterPropertiesSet");
    }

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("【"+this.getClass().getSimpleName()+"】"+ "setApplicationContext");
    }
}

這個類實現了所有生命週期所能實現的方法,以便於觀察生命週期的過程,其中init方法是自定義初始化方法,myDestroy方法是自定義銷燬方法。
我們修改配置文件spring-config.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="beanPostProcessor" class="com.sean.spring.BeanPostProcessorImpl"/>
    <!--setter注入-->
    <bean id="user" class="com.sean.spring.User" init-method="init" destroy-method="myDestroy">
        <property name="name" value="無敵"></property>
        <property name="age" value="18"></property>
    </bean>
</beans>

寫一個測試類,看一下結果

    @Test
    public void test1(){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring/spring-config.xml");
        User user = context.getBean(User.class);
        logger.debug(user.getUser());
        ((ClassPathXmlApplicationContext) context).close();
    }

打印日誌:
在這裏插入圖片描述
在項目或者面試中,經常會碰到Spring 循環依賴問題,從源碼解決Spring 循環依賴問題

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章