Spring 框架基礎(02):Bean的生命周期,作用域,裝配總結

  • 2019 年 10 月 6 日
  • 筆記

一、裝配方式

Bean的概念:Spring框架管理的應用程式中,由Spring容器負責創建,裝配,設置屬性,進而管理整個生命周期的對象,稱為Bean對象。

1、XML格式裝配

Spring最傳統的Bean的管理方式。

  • 配置方式
<bean id="userInfo" class="com.spring.mvc.entity.UserInfo">      <property name="name" value="cicada" />  </bean>  
  • 測試程式碼
ApplicationContext context01 = new ClassPathXmlApplicationContext("/bean-scan-02.xml");  UserInfo userInfo = (UserInfo)context01.getBean("userInfo") ;  System.out.println(userInfo.getName());  

2、註解掃描

在實際開發中:通常使用註解 取代 xml配置文件。

  • 常見註解
@Component <==> <bean class="Class">  @Component("id") <==> <bean id="id" class="Class">  @Repository :Mvc架構中Dao層Bean的註解  @Service:Mvc架構中Service層Bean的註解  @Controller:Mvc架構中Controller層Bean的註解  
  • 使用案例
// 1、註解程式碼塊  @Component("infoService")  public class InfoServiceImpl implements InfoService {      @Override      public void printName(String name) {          System.out.println("Name:"+name);      }  }    // 2、配置程式碼塊  @ComponentScan // 組件掃描註解  public class BeanConfig {    }  
  • 測試程式碼
@RunWith(SpringJUnit4ClassRunner.class)  @ContextConfiguration(classes = BeanConfig.class)  public class Test01 {      @Autowired      private InfoService infoService ;      @Test      public void test1 (){          infoService.printName("cicada");          System.out.println(infoService==infoService);      }  }  

3、XML配置掃描

上面使用 ComponentScan 註解,也可在配置文件進行統一的配置,效果相同,還簡化程式碼。

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

4、Java程式碼裝配

這種基於Configuration註解,管理Bean的創建,在SpringBoot和SpringCloud的框架中,十分常見。

  • 配置類程式碼
@Configuration // 配置類註解  public class UserConfig {      @Bean      public UserInfo userInfo (){          System.out.println("userInfo...");          return new UserInfo() ;      }  }  
  • 測試程式碼
@RunWith(SpringJUnit4ClassRunner.class)  @ContextConfiguration(classes = UserConfig.class)  public class Test03 {      @Autowired      private UserInfo userInfo ;      @Autowired      private UserInfo userInfo1 ;      @Test      public void test1 (){          /*           * userInfo...           * true           */          System.out.println(userInfo==userInfo1);      }  }  

二、屬性值設置

上面是Bean的裝配幾種常見方式,下面來看看Bean屬性值設置,這裡就基於Xml配置的方式。

1、基礎類型和集合

  • 配置程式碼
<!-- 配置Employee公共屬性 -->  <bean id="emp1" class="com.spring.mvc.entity.Employee">      <property name="name" value="cicada" />      <property name="id" value="1" />  </bean>  <bean id="emp2" class="com.spring.mvc.entity.Employee">      <property name="name" value="smile" />      <property name="id" value="2" />  </bean>  <!-- 配置Department屬性 -->  <bean id="department" class="com.spring.mvc.entity.Department">      <!-- 普通屬性值的注入 -->      <property name="name" value="IT部門" />      <!-- 給數組注入值 -->      <property name="empName">          <list>              <value>empName1</value>              <value>empName2</value>              <value>empName3</value>          </list>      </property>      <!-- 給List注入值:可以存放相同的值 -->      <property name="empList">          <list>              <ref bean="emp1"/>              <ref bean="emp2"/>              <ref bean="emp1"/>          </list>      </property>      <!-- 配置Set屬性,相同的對象會被覆蓋 -->      <property name="empSet">          <set>              <ref bean="emp1"/>              <ref bean="emp2"/>              <ref bean="emp1"/>          </set>      </property>      <!-- 配置Map屬性,key相同的話,後面的值會覆蓋前面的 -->      <property name="empMap">          <map>              <entry key="1" value-ref="emp1" />              <entry key="2" value-ref="emp2" />              <entry key="2" value-ref="emp1" />          </map>      </property>      <!-- 配置屬性集合 -->      <property name="pp">          <props>              <prop key="pp1">Hello</prop>              <prop key="pp2">World</prop>          </props>      </property>  </bean>  
  • 測試程式碼
public class Test05 {      @Test      public void test01 (){          ApplicationContext context = new ClassPathXmlApplicationContext("/bean-value-03.xml");          Department department = (Department) context.getBean("department");          System.out.println(department.getName());          System.out.println("--------------------->String數組");          for (String str : department.getEmpName()){              System.out.println(str);          }          System.out.println("--------------------->List集合");          for (Employee smp : department.getEmpList()){              System.out.println(smp.getId()+":"+smp.getName());          }          System.out.println("--------------------->Set集合");          for (Employee emp : department.getEmpSet()){              System.out.println(emp.getId()+":"+emp.getName());          }          System.out.println("--------------------->Map集合");          for (Map.Entry<String, Employee> entry : department.getEmpMap().entrySet()){              System.out.println(entry.getKey()+":"+entry.getValue().getName());          }          System.out.println("--------------------->Properties");          Properties pp = department.getPp();          System.out.println(pp.get("pp1"));          System.out.println(pp.get("pp2"));      }  }  

2、配置構造函數

根據配置的參數個數和類型,去映射並載入Bean的構造方法。

  • 配置程式碼
<!-- 這裡配置2個參數,所有調用2個參數的構造函數 -->  <bean id="employee" class="com.spring.mvc.entity.Employee">      <constructor-arg index="0" type="java.lang.String" value="cicada"/>      <constructor-arg index="1" type="int" value="1"/>  </bean>  
  • 測試程式碼
public class Test06 {      @Test      public void test01 (){          ApplicationContext context = new ClassPathXmlApplicationContext("/bean-value-04.xml");          Employee employee = (Employee) context.getBean("employee");          System.out.println(employee.getId()+":"+employee.getName());      }  }  

3、配置繼承關係

  • 配置程式碼
<!-- 配置父類資訊 -->  <bean id="student" class="com.spring.mvc.entity.Student">      <property name="name" value="Spring" />      <property name="age" value="22" />  </bean>  <!-- 配置子類資訊 -->  <bean id="grade" class="com.spring.mvc.entity.Grade">      <!-- 覆蓋 -->      <property name="name" value="Summer" />      <property name="degree" value="大學" />  </bean>  
  • 測試程式碼
public class Test07 {      @Test      public void test01 (){          ApplicationContext context = new ClassPathXmlApplicationContext("/bean-value-05.xml");          Grade grade = (Grade) context.getBean("grade");          /* Summer;0;大學  */          System.out.println(grade.getName()+";"+grade.getAge()+";"+grade.getDegree());      }  }  

三、作用域

作用域:用於確定spring創建bean實例個數,比如單例Bean,原型Bean,等等。

類型

說明

singleton

IOC容器僅創建一個Bean實例,IOC容器每次返回的是同一個單例Bean實例,默認配置。

prototype

IOC容器可以創建多個Bean實例,每次返回的Bean都是新的實例。

request

每次HTTP請求都會創建一個新的Bean,適用於WebApplicationContext環境。

session

同一個HTTP Session共享一個Bean實例。不同HTTP Session使用不同的實例。

global-session

同session作用域不同的是,所有的Session共享一個Bean實例。

四、生命周期

在Spring框架中Bean的生命周期非常複雜,過程大致如下:實例化,屬性載入,初始化前後管理,銷毀等。下面基於一個案例配置,會更加的清楚。

1、編寫BeanLife類

public class BeanLife implements BeanNameAware {      private String name ;      public String getName() {          return name;      }      public void setName(String name) {          System.out.println("設置名稱:"+name);          this.name = name;      }      @Override      public void setBeanName(String value) {          System.out.println("BeanNameAware..SetName:"+value);      }      public void initBean() {          System.out.println("初始化Bean..");      }      public void destroyBean() {          System.out.println("銷毀Bean..");      }      public void useBean() {          System.out.println("使用Bean..");      }      @Override      public String toString() {          return "BeanLife [name = " + name + "]";      }  }  

2、訂製載入過程

實現BeanPostProcessor介面。

public class BeanLifePostProcessor implements BeanPostProcessor {      // 初始化之前對bean進行增強處理      @Override      public Object postProcessBeforeInitialization(Object obj, String beanName) throws BeansException {          System.out.println("初始化之前..."+beanName);          return obj ;      }      // 初始化之後對bean進行增強處理      @Override      public Object postProcessAfterInitialization(Object obj, String beanName) throws BeansException {          System.out.println("初始化之後..."+beanName);          // 改寫Bean的名稱          if (obj instanceof BeanLife){              BeanLife beanLife = (BeanLife)obj ;              beanLife.setBeanName("myBeanLifeTwo");              return beanLife ;          }          return obj ;      }  }  

3、配置文件

<!-- 載入Bean的處理器 -->  <bean class="com.spring.mvc.BeanLifePostProcessor" />  <!-- 指定初始化和銷毀方法 -->  <bean id="beanLife" class="com.spring.mvc.entity.BeanLife"      init-method="initBean" destroy-method="destroyBean">      <property name="name" value="myBeanLifeOne" />  </bean>  

4、測試過程

  • 測試程式碼
public class Test08 {      @Test      public void test01 (){          ApplicationContext context = new ClassPathXmlApplicationContext("/bean-value-06.xml");          BeanLife beanLife = (BeanLife) context.getBean("beanLife");          System.out.println("測試結果BeanLife:"+beanLife.getName()) ;          beanLife.useBean();          // 關閉容器          ((AbstractApplicationContext) context).close();      }  }  
  • 輸出結果
1、設置名稱:myBeanLifeOne  2、BeanNameAware..SetName:beanLife  3、初始化之前...beanLife  4、初始化Bean..  5、初始化之後...beanLife  6、BeanNameAware..SetName:myBeanLifeTwo  7、測試結果BeanLife:myBeanLifeOne  8、使用Bean..  9、銷毀Bean..  

這裡梳理Bean的生命周期,過程十分清晰。

五、源程式碼地址

GitHub·地址  https://github.com/cicadasmile/spring-mvc-parent  GitEE·地址  https://gitee.com/cicadasmile/spring-mvc-parent