zoukankan      html  css  js  c++  java
  • 【Spring学习随笔】3. Spring Bean

    3. Spring Bean

    3.1 Bean的配置

    ​ Spring可以看作一个大型工厂,用于生产和管理Spring容器中的Bean。如果要使用这个工厂生产和管理bean,需要开发者将Bean配置在Spring的配置文件中。Spring框架支持XML和Properties两种格式的配置文件,在实际开发中常用XML格式的配置文件。

    3.1.1 <bean>元素的常用属性及其子元素

    3.1.2 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"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd">
        <!-- 使用id属性定义myTestDIDao,其对应的实现类为dao.TestDIDaoImpl-->
        <bean id="myTestDIDao" class="dao.TestDIDaoImpl" />
        <!-- 使用构造方法注入 -->
        <bean id="testDIService" class="service.TestDIServiceImpl">
            <!-- 给构造方法传引用类型的参数值myTestDIDao -->
            <constructor-arg index="0" ref="myTestDIDao"/>
        </bean>
    </beans>
    

    3.2 Bean的实例化

    ​ 在Spring框架中,如果想使用Spring容器中的Bean,需要实例化Bean。Spring框架实例化Bean有3种方式,即构造方法实例化静态工厂实例化、和实例工厂实例化,其中最常见的是构造方法实例化

    3.2.1 构造方法实例化

    ​ 在Spring框架中,Spring容器可以调用Bean对应类中的无参数构造方法来实例化Bean,这种方式称为构造方法实例化。

    实例演示:

    • 创建Web应用,在src目录下创建instance包,在包中创建BeanClass类

      package instance;
      public class BeanClass {
          public String message;
          public BeanClass() {
              message = "构造方法实例化Bean";
        }
      
          public BeanClass(String s) {
              message = s;
          }
      }
      
    • 创建配置文件

      <?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-->
          <bean id="constructorInstance" class="instance.BeanClass" />
      
      </beans>
      
    • 创建测试类

      package test;
      
      import instance.BeanClass;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestInstance {
          public static void main(String[] args) {
      //        初始化Spring容器ApplicationContext,加载配置文件
              ApplicationContext appCon = new ClassPathXmlApplicationContext("applicationContext.xml");
      //        测试构造方法实例化Bean
              BeanClass b1 = (BeanClass) appCon.getBean("constructorInstance");
              System.out.println(b1+b1.message);
          }
      
      }
      
    • 运行结果

    3.2.2 静态工厂实例化

    ​ 在使用静态工厂实例化Bean时要求开发者在工厂类中创建一个静态方法来创建Bean的实例。在配置Bean时,class属性指定静态工厂类,同时还需要使用factory-method属性指定工厂类中的静态方法

    实例演示:

    • 创建工厂类BeanStaticFactory,在instance包中创建工厂类BeanStaticFactory

      package instance;
      
      public class BeanStaticFactory {
          private static BeanClass beanInstance = new BeanClass("调用静态工厂方法实例化Bean");
          public static BeanClass createInstance() {
              return beanInstance;
          }
      
      }
      
    • 编辑配置文件

      <?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,createInstance为静态工厂类BeanStaticFactory中的静态方法-->
          <bean id="staticFactoryInstance" class="instance.BeanStaticFactory" factory-method="createInstance" />
      </beans>
      
    • 添加测试代码

      package test;
      
      import instance.BeanClass;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestInstance {
          public static void main(String[] args) {
      //        初始化Spring容器ApplicationContext,加载配置文件
              ApplicationContext appCon = new ClassPathXmlApplicationContext("applicationContext.xml");
      //        测试静态工厂方法实例化Bean
              BeanClass b2 = (BeanClass) appCon.getBean("staticFactoryInstance");
              System.out.println(b2+b2.message);
      
          }
      }
      
    • 运行效果

    3.2.3 实例工厂实例化

    ​ 在使用实例工厂实例化Bean时要求开发者在工厂类中创建一个实例方法来创建Bean的实例。在配置Bean时需要使用factory-method属性指定配置的实例工厂,同时还需要使用factory-method属性指定实例工厂中的实例方法

    • 创建工厂类BeanStaticFactory

      在instance包中创建工厂类BeanInstanceFactory,该类中有一个实例方法类实例化对象

      package instance;
      
      public class BeanInstanceFactory {
          public BeanClass createBeanClassInstance() {
              return new BeanClass("调用实例工厂方法实例化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"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
      
      <!--    配置工厂-->
          <bean id="myFactory" class="instance.BeanInstanceFactory" />
      <!--    使用factory-bean属性指定配置工厂,使用factory-method属性指定使用工厂中的哪个方法实例化Bean-->
          <bean id="instanceFactoryInstance" factory-bean="myFactory" factory-method="createBeanClassInstance" />
      </beans>
      
      
    • 添加测试代码

      package test;
      
      import instance.BeanClass;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestInstance {
          public static void main(String[] args) {
      //        初始化Spring容器ApplicationContext,加载配置文件
              ApplicationContext appCon = new ClassPathXmlApplicationContext("applicationContext.xml");
      //        测试实例工厂方法实例化Bean
              BeanClass b3 = (BeanClass) appCon.getBean("instanceFactoryInstance");
              System.out.println(b3+b3.message);
      
          }
      }
      
      
    • 运行效果

    3.3 Bean的作用域

    3.3.1 在Spring 5.0中为Bean的实例定义的作用域

    singletonprototype是最常用的两种,后面4中作用域尽在Web Spring应用程序上下文中使用。

    3.3.2 singleton作用域

    ​ 当bean的scope设置为singleton时,Spring IoC容器仅生成和管理一个Bean实例。在使用id或name获取Bean实例时,IoC容器将会返回共享的Bean实例。

    ​ singleton时scope的默认方式,有两种方式将bean的scope设置为singleton。示例如下:

    <bean id="constructorInstance" class="instance.BeanClass" />
    
    

    <bean id="constructorInstance" class="instance.BeanClass" scope="singleton"/>
    
    

    在使用id或name获取Bean实例时,IoC容器仅返回同一个Bean实例。

    3.3.3 prototype作用域

    ​ 当bean的scope设置为prototype时,Spring IoC容器将为每次请求创建一个新的实例。示例如下:

    <bean id="constructorInstance" class="instance.BeanClass" scope="prototype"/>
    
    

    3.4 Bean的生命周期

    • Bean的生命周期过程:

    • 步骤文字描述:
    1. Spring启动,查找并加载需要被Spring管理的bean,进行Bean的实例化。
    2. Bean实例化后对将Bean的引入和值注入到Bean的属性中。
    3. 如果Bean实现了BeanNameAware接口的话,Spring将Bean的Id传递给setBeanName()方法。
    4. 如果Bean实现了BeanFactoryAware接口的话,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入。
    5. 如果Bean实现了ApplicationContextAware接口的话,Spring将调用Bean的setApplicationContext()方法,将bean所在应用上下文引用传入进来。
    6. 如果Bean实现了BeanPostProcessor接口,Spring就将调用他们的postProcessBeforeInitialization()方法。
    7. 如果Bean 实现了InitializingBean接口,Spring将调用他们的afterPropertiesSet()方法。类似的,如果bean使用init-method声明了初始化方法,该方法也会被调用
    8. 如果Bean 实现了BeanPostProcessor接口,Spring就将调用他们的postProcessAfterInitialization()方法。
    9. 此时,Bean已经准备就绪,可以被应用程序使用了。他们将一直驻留在应用上下文中,直到应用上下文被销毁。
    10. 如果bean实现了DisposableBean接口,Spring将调用它的destory()接口方法,同样,如果bean使用了destory-method 声明销毁方法,该方法也会被调用。

    实例演示Bean的生命周期:

    • 创建Bean的实现类

      在src目录中创建life包,在life包下创建BeanLife类。在BeanLife类中有两个方法,一个演示初始化方法,一个演示销毁过程。

      package life;
      
      public class BeanLife {
          public void initMyself() {
              System.out.println(this.getClass().getName()+"执行自定义的初始化方法");
          }
      
          public void destoryMyself() {
              System.out.println(this.getClass().getName()+"执行自定义的销毁方法");
          }
      }
      
      
    • 配置Bean

      在Spring配置文件中使用实现类BeanLife配置一个id为beanLife的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"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
      
      <!--    配置bean,使用iniit-method属性指定初始化方法,使用destroy-method属性指定销毁方法-->
          <bean id="beanLife" class="life.BeanLife" init-method="initMyself" destroy-method="destoryMyself" />
      </beans>
      
      
    • 测试声明周期

      在test包中创建测试类TestLife。

      package test;
      
      import life.BeanLife;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestLife {
          public static void main(String[] args) {
      //        初始化Spring容器,加载配置文件
      //        为了方便演示销毁方法的执行,这里使用ClassPathXmlApplicationContext
      //        实现类声明容器
              ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
              System.out.println("获得对象前");
              BeanLife blife = (BeanLife)ctx.getBean("beanLife");
              System.out.println("获得对象后" + blife);
              ctx.close();     //关闭容器,销毁Bean对象
          }
      }
      
      
    • 运行效果

    3.5 Bean的装配方式

    Bean的装配可以理解为将bean依赖注入到Spring容器中Bean的装配方式即Bean依赖注入的方式

    3.5.1 基于XML配置的装配

    ​ 在使用构造方法注入方式装配Bean时,Bean的实现类需要提供带参数构造方法,并在配置文件中使用元素的子元素来定义构造方法的参数;在使用属性的setter方法注入方式装配Bean时,Bean的实现类需要提供一个默认无参数的构造方法,并为需要注入的属性提供对应的setter方法,另外还需要使用元素的子元素为每个属性注入值。

    实例演示:

    • 创建Bean的实现类

      在src目录中创建assemble包,在assemble包下创建ComplexUser类。在ComplexUser类中分别使用构造方法注入和使用属性的setter方法注入。

      package assemble;
      
      import java.util.List;
      import java.util.Map;
      import java.util.Set;
      
      public class ComplexUser {
          private String uname;
          private List<String> hobbyList;
          private Map<String,String> residenceMap;
          private Set<String> aliasSet;
          private String[] array;
      
          /*
          使用构造方法注入,需要提供带参数的构造方法
           */
          public ComplexUser(String uname, List<String> hobbyList, Map<String, String> residenceMap, Set<String> aliasSet, String[] array) {
              super();
              this.uname = uname;
              this.hobbyList = hobbyList;
              this.residenceMap = residenceMap;
              this.aliasSet = aliasSet;
              this.array = array;
          }
          /**
           * 使用属性的setter方法注入,提供默认无参数的构造方法,并为注入的属性提供setter方法
           */
          public ComplexUser() {
              super();
          }
      
          @Override
          public String toString() {
              return  "uname=" + uname + ";hobbyList=" + hobbyList + ";residenceMap=" + residenceMap + ";aliasSet=" + aliasSet +";array=" + array;
          }
      
          //    此处为所有属性的setter方法
          public void setUname(String uname) {
              this.uname = uname;
          }
      
          public void setHobbyList(List hobbyList) {
              this.hobbyList = hobbyList;
          }
      
          public void setResidenceMap(Map residenceMap) {
              this.residenceMap = residenceMap;
          }
      
          public void setAliasSet(Set aliasSet) {
              this.aliasSet = aliasSet;
          }
      
          public void setArray(String[] array) {
              this.array = array;
          }
      }
      
      
    • 配置Bean

      在Spring配置文件中使用实现类ComplexUser配置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"
             xsi:schemaLocation="http://www.springframework.org/schema/beans
                                 http://www.springframework.org/schema/beans/spring-beans.xsd">
      
      <!--    使用构造方法注入方式装配ComplexUser实例user1-->
          <bean id="user1" class="assemble.ComplexUser">
              <constructor-arg index="0" value="yihang1" />
              <constructor-arg index="1">
                  <list>
                      <value>唱歌</value>
                      <value>跳舞</value>
                      <value>爬山</value>
                  </list>
              </constructor-arg>
      
              <constructor-arg index="2">
                  <map>
                      <entry key="dalian" value="大连" />
                      <entry key="beijing" value="北京" />
                      <entry key="shanghai" value="上海" />
                  </map>
              </constructor-arg>
      
              <constructor-arg index="3">
                  <set>
                      <value>逸航01</value>
                      <value>逸航02</value>
                      <value>逸航03</value>
                  </set>
              </constructor-arg>
      
              <constructor-arg index="4">
                  <array>
                      <value>aaaaa</value>
                      <value>bbbbb</value>
                  </array>
              </constructor-arg>
          </bean>
      
      <!--    使用属性的setter方法注入方式装配 ComplexUser实例user2-->
          <bean id="user2" class="assemble.ComplexUser">
              <property name="uname" value="yihang2" />
              <property name="hobbyList">
                  <list>
                      <value>看书</value>
                      <value>学习Spring</value>
                  </list>
              </property>
      
              <property name="residenceMap" >
                  <map>
                      <entry key="shenzhen" value="深圳" />
                      <entry key="guangzhou" value="广州" />
                      <entry key="tianjin" value="天津" />
                  </map>
              </property>
      
              <property name="aliasSet">
                  <set>
                      <value>逸航04</value>
                      <value>逸航05</value>
                      <value>逸航06</value>
                  </set>
              </property>
      
              <property name="array">
                  <array>
                      <value>ccccc</value>
                      <value>ddddd</value>
                  </array>
              </property>
          </bean>
      </beans>
      
      
    • 测试基于XML配置的装配方式

      在test包中创建测试类TestAssemble。

      package test;
      
      import assemble.ComplexUser;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestAssemble {
          public static void main(String[] args) {
              ApplicationContext appCon = new ClassPathXmlApplicationContext("applicationContext.xml");
      //        使用构造方法装配测试
              ComplexUser u1 = (ComplexUser) appCon.getBean("user1");
              System.out.println(u1);
              System.out.println("-------------------------");
      //        使用setter方法装配测试
              ComplexUser u2 = (ComplexUser) appCon.getBean("user2");
              System.out.println(u2);
          }
      }
      
      
    • 运行效果

    3.5.2 基于注解的装配

    ​ 大量的Bean装配会导致XML配置文件过于庞大,不方便以后的升级与维护,因此更多的时候推荐开发者使用注解(annotation)的方式去装配Bean。

    3.5.1.1 @Component

    ​ 该注解是一个泛化的概念,仅仅表示一个组件对象(Bean),可以作用在任何层次上。

    3.5.2.2 @Repository

    ​ 该注解用于将数据访问层(DAO)的类标识为Bean,即注解数据访问层Bean,其功能与@Component相同。

    3.5.2.3 @Service

    ​ 该注解用于标注一个业务逻辑组件类(Service层),其功能与@Component相同。

    3.5.2.4 @Controller

    ​ 该注解用于标注一个控制器组件类(Spring MVC的Controller),其功能与@Component相同。

    3.5.2.5 @Autowired

    ​ 该注解可以对类成员变量、方法及构造方法进行标注,完成自动装配的工作。通过使用@Autowired来消除setter和getter方法。默认按照Bean的类型进行装配。

    3.5.2.6 @Resource

    ​ 该注解与@Autowired的功能一样,区别在于该注解默认是按照名称来装配注入的,只有当找不到与名称匹配的Bean时才会按照类型来装配注入;而@Autowired默认按照Bean的类型进行装配,如果想按照名称来装配注入,则需要和@Qualifier注解一起使用。

    3.5.3.7 @Qualifier

    ​ 该注解与@Aitowired注解配合使用。当@Autowired注解需要按照名称来装配注入时需要和该注解一起使用,Bean的实例名称由@Qualifier注解的参数制定。

    实例演示:

    • 创建DAO层

      在src中创建annotation.dao包,在该包下创建TestDao接口和TestDaoImpl实现类,并将实现类TestDaoImpl使用@Repository注解标注为数据访问层。

      TestDao的代码如下:

      package annotation.dao;
      
      public interface TestDao {
          public void save();
      }
      
      

      TestDaoImpl的代码如下:

      package annotation.dao;
      
      import org.springframework.stereotype.Repository;
      
      @Repository("testDao")
      /**
       * 相当于@Repository,但如果在service层中使用@Resource(name="testDao"),
       * testDao不能省略
       */
      public class TestDaoImpl implements TestDao {
          @Override
          public void save() {
              System.out.println("testDao save");
          }
      }
      
      
    • 创建Service层

      在src中创建annotation.service包,在该包下创建TestService接口和TestServiceImpl实现类,并将实现类TestServiceImpl使用@service注解标注为业务逻辑层。

      Testservice的代码如下:

      package annotation.service;
      
      public interface TestService {
          public void save();
      }
      
      

      TestServiceImpl的代码如下:

      package annotation.service;
      
      import annotation.dao.TestDao;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.stereotype.Service;
      
      @Service("testService")  //相当于@Service
      public class TestSerivceImpl implements TestService {
      //    @Resource(name="testDao")
          @Autowired
      //    相当于@Autowired,@Autowired默认按照Bean状态装配
          private TestDao testDao;
      
          @Override
          public void save() {
              testDao.save();
              System.out.println("testService save");
          }
      }
      
      
    • 创建Controller层

      在src中创建annotation.controller包,在该包下创建TestController类,并将TestController类使用@Controller注解标注为控制器层。

      TestController的代码如下:

      package annotation.controller;
      
      import annotation.service.TestService;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.stereotype.Controller;
      
      @Controller
      public class TestController {
          @Autowired
          private TestService testService;
      
          public void save() {
              testService.save();
              System.out.println("testController save");
          }
      }
      
      
    • 配置注解

      由于annotation.dao、annotation.service和annotation.controller包都属于annotation包的子包,因此不要在配置文件annotationContext.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:context="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 http://www.springframework.org/schema/context/spring-context.xsd">
      
          <context:component-scan base-package="annotation" />
      </beans>
      
      
    • 创建测试类

      package test;
      
      import annotation.controller.TestController;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestMoreAnnotation {
          public static void main(String[] args) {
              ApplicationContext appCon = new ClassPathXmlApplicationContext("annotationContext.xml");
              TestController testcon = (TestController) appCon.getBean("testController");
              testcon.save();
          }
      }
      
      
    • 运行效果

    都说酒是陈的香。
  • 相关阅读:
    第三周学习进度
    四则运算之结对开发
    第二周学习进度
    单元测试
    构建之法阅读笔记03
    本周学习进度
    四则运算三
    构建之法阅读笔记02
    本周学习进度
    按照Right-BICEP要求设计的测试用例
  • 原文地址:https://www.cnblogs.com/yihangjou/p/11929345.html
Copyright © 2011-2022 走看看