前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java EE之SSM框架整合开发 -- (3) Spring Bean

Java EE之SSM框架整合开发 -- (3) Spring Bean

作者头像
浩Coding
发布2019-07-03 11:52:45
4510
发布2019-07-03 11:52:45
举报
文章被收录于专栏:浩Coding

在Spring的应用中,Spring IOC容器可以创建、装配和配置应用组件对象,这里的组件对象称为Bean。本章我们主要讲述Spring中Bean的配置、Bean的实例化、Bean的作用域、Bean的生命周期、Bean的装配方式。

3.1 Bean的配置

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

常见Bean的配置示例代码如下:

代码语言:javascript
复制
<?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" scope="prototype"/>
</beans>

3.2 Bean的实例化

Spring框架实例化Bean有三种方式:构造方法实例化、静态工厂实例化和实例工厂实例化(其中,最常用的实例方法是构造方法实例化)。

3.2.1 构造方法实例化

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

1.创建Web应用ch3

2.创建BeanClass类

在ch3的src目录下,创建instance包,并在该包中创建BeanClass类,代码如下:

代码语言:javascript
复制
public class BeanClass {
  public String message;
  public BeanClass() {
    message = "构造方法实例化Bean";
  }
  public BeanClass(String s) {
    message = s;
  }
}

3.创建配置文件

在ch3的src目录下,创建Spring的配置文件applicationContext.xml,在配置文件中定义一个id为constructorInstance的Bean,代码如下:

代码语言:javascript
复制
<!-- 构造方法实例化Bean -->
  <bean id="constructorInstance" class="instance.BeanClass" />

4.创建测试类

在ch3的src目录下,创建test包,并在该包下创建测试类TestInstance,代码如下:

代码语言:javascript
复制
package test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import instance.BeanClass;

public class TestStance {
  public static void main(String[] args) {
    //初始化Spring容器applicationcontext ,加载配置文件
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    //测试构造方法实例化Bean
    BeanClass b1 = (BeanClass) applicationContext.getBean("constructorInstance");
    System.out.println(b1 + b1.message);
  }
}

运行结果:

3.2.2 静态工厂实例化

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

运行结果:

3.2.3 实例工厂实例化

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

最后总的运行结果:

3.3 Bean的作用域

当将bean的scope设置为singleton时,Spring IoC容器仅生成和管理一个Bean实例。使用id或name获取Bean实例时,IoC容器将返回共享的Bean实例。 由于singleton是scope的默认方式,因此有两种方式将bean的scope设置为singleton。配置文件示例代码如下:

代码语言:javascript
复制
<bean id="constructorInstance" class="instance.BeanClass" />

或者:

代码语言:javascript
复制
<bean id="constructorInstance" class="instance.BeanClass" scope="singleton"/>

测试singleton作用域,代码如下:

代码语言:javascript
复制
//初始化Spring容器ApplicationContext,加载配置文件
ApplicationContext appCon = new ClassPathXmlApplicationContext("applicationContext.xml");
//测试构造方法实例化
BeanBeanClass b1 = (BeanClass)appCon.getBean("constructorInstance");
System.out.println(b1);
BeanClass b2 = (BeanClass)appCon.getBean("constructorInstance");

最后运行结果发现是同一个对象:

当bean的scope设置为prototype时,Spring IoC容器将为每次请求创建一个新的实例。如果将3.3.1中bean的配置修改如下:

代码语言:javascript
复制
<bean id="constructorInstance" class="instance.BeanClass" scope="prototype"/>

最后结果如下:

3.4 Bean的生命周期

Bean的生命周期整个过程如下:

1.根据Bean的配置情况,实例化一个Bean。

2.根据Spring上下文对实例化的Bean进行依赖注入,即对Bean的属性进行初始化。

3.如果Bean实现了BeanNameAware接口,将调用它实现的setBeanName(String beanId)方法,此处参数传递的是Spring配置文件中Bean的ID。

4.如果Bean实现了BeanFactoryAware接口,将调用它实现的setBeanFactory()方法,此处参数传递的是当前Spring工厂实例的引用。

5.如果Bean实现了ApplicationContextAware接口,将调用它实现的setApplicationContext(ApplicationContext)方法,此处参数传递的是Spring上下文实例的引用。

6.如果Bean关联了BeanPostProcessor接口,将调用预初始化方法postProcessBeforeInitialization(Object obj, String s)对Bean进行操作。

7.如果Bean实现了InitializingBean接口,将调用afterPropertiesSet()方法。

8.如果Bean在Spring配置文件中配置了init-method属性,将自动调用其配置的初始化方法。

9.如果Bean关联了BeanPostProcessor接口,将调用postProcessAfterInitialization(Object obj, String s)方法,由于是在Bean初始化结束时调用After方法,也可用于内存或缓存技术。

以上工作(1至9)完成以后就可以使用该Bean,由于该Bean的作用域是singleton,所以调用的是同一个Bean实例。

10.当Bean不再需要时,将经过销毁阶段,如果Bean实现了DisposableBean接口,将调用其实现的destroy方法将Spring中的Bean销毁。

11.如果在配置文件中通过destroy-method属性指定了Bean的销毁方法,将调用其配置的销毁方法进行销毁。

下面通过一个实例演示Bean的生命周期。

1.创建Bean的实现类

在ch3应用src目录中,创建包life,在life包下创建类BeanLife。在类BeanLife中有两个方法,一个演示初始化过程,一个演示销毁过程。具体代码如下:

代码语言:javascript
复制
public class BeanLife {
  public void initMyself() {
    System.out.println(this.getClass().getName() + "执行的自定义的初始化方法,嘿嘿。");
  }
  public void destroyMyself() {
    System.out.println(this.getClass().getName() + "执行的自定义的销毁方法,哈哈。");
  }
}

2.配置Bean

在Spring配置文件中,使用实现类BeanLife配置一个id为beanLife的Bean。具体代码如下:

代码语言:javascript
复制
 <!-- 配置bean,使用init-method属性指定初始化方法,使用 destroy-method属性指定销毁方法-->
 <bean id="beanLife" class="life.BeanLife" init-method="initMyself" destroy-method="destroyMyself"/>

3.测试生命周期

在ch3应用的test包中,创建测试类TestLife,具体代码如下:

代码语言:javascript
复制
// 初始化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依赖注入的方式。Spring容器支持基于XML配置的装配、基于注解的装配以及自动装配等多种装配方式。本节将主要讲解基于XML配置的装配和基于注解的装配。在我们实际应用中,使用XML配置装配方式会导致XML文件过于庞大,不方便后期软件的升级维护,因此推荐大家使用注解装配方式

通过2.3节的学习后,我们知道Spring提供了两种基于XML配置的装配方式:构造方法注入和属性setter方法注入

基于XML配置的装配方式的重要代码:

创建Bean的实现类代码ComplexUser

代码语言:javascript
复制
package assemble;

import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 测试Bean的基于XML配置的复杂装配方式
 * @author hao
 *
 */
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();
  }
  public void setUname(String uname) {
    this.uname = uname;
  }
  public void setHobbyList(List<String> hobbyList) {
    this.hobbyList = hobbyList;
  }
  public void setResidenceMap(Map<String, String> residenceMap) {
    this.residenceMap = residenceMap;
  }
  public void setAliasSet(Set<String> aliasSet) {
    this.aliasSet = aliasSet;
  }
  public void setArray(String[] array) {
    this.array = array;
  }
  @Override
  public String toString() {
    return "uname=" + uname + ";hobbyList=" + hobbyList + ";residenceMap=" 
  + residenceMap +";aliasSet=" + aliasSet + ";array=" + array;
  }
}

配置Bean:

代码语言:javascript
复制
<!-- 使用构造方法注入方式装配ComplexUser实例 user1-->
    <bean id="user1" class="assemble.ComplexUser">
      <constructor-arg index="0" value="chenheng1"/>
      <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>陈恒100</value>
          <value>陈恒101</value>
          <value>陈恒102</value>
        </set>
      </constructor-arg>
      <constructor-arg index="4">
        <array>
          <value>第一</value>
          <value>第二</value>
        </array>
      </constructor-arg>
    </bean>
    <!-- 使用setter方法注入方式装配 ComplexUser实例user2 -->
    <bean id="user2" class="assemble.ComplexUser">
      <property name="uname" value="chenheng2"/>
      <property name="hobbyList">
        <list>
          <value>看书</value>
          <value>学习Spring</value>
        </list>
      </property>
      <property name="residenceMap">
        <map>
          <entry key="shenzhen" value="深圳"/>
          <entry key="gaungzhou" value="广州"/>
          <entry key="tianjin" value="天津"/>
        </map>
      </property>
      <property name="aliasSet">
        <set>
          <value>陈恒103</value>
          <value>陈恒104</value>
          <value>陈恒105</value>
        </set>
      </property>
      <property name="array">
        <array>
          <value>First</value>
          <value>Second</value>
        </array>
      </property>
    </bean>

至于测试基于XML配置的装配方式就和上文一样了,这里只贴出具体结果:

3.5.2 基于注解的装配

在Spring框架中定义了一系列的注解,常用注解如下所示。

1.@Component

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

2.@Repository

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

3.@Service

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

4.@Controller

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

5.@Autowired

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

6.@Resource

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

@Resource注解有两个属性:name和type。name属性指定Bean实例名称,即按照名称来装配注入;type属性指定Bean类型,即按照Bean的类型进行装配。

7.@Qualifier

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

上面几个注解中,虽然@Repository、@Service和 @Controller等注解的功能与@Component()相同,但为了使标注类的用途更加清晰(层次化),在实际开发中推荐使用@Repository标注数据访问层(DAO层)、使用@Service标注业务逻辑层(Service层)以及使用@Controller标注控制器层(控制层)。

下面通过一个实例讲解@Component()。

创建Bean的实现类:

代码语言:javascript
复制
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component()
/**相当于@Component("annotationUser")或@Component(value = "annotationUser"),annotationUser为Bean的id,默认为首字母小写的类名**/
public class AnnotationUser {
  @Value("chenheng")//只注入了简单的值,复杂值的注入目前使用该方式还解决不了
  private String uname;
  
  public String getUname() {
    return uname;
  }
  public void setUname(String uname) {
    this.uname = uname;
  }
  @Override
  public String toString() {
    return "uname=" + uname;
  }
}

配置注解:

现在有了Bean的实现类,但还不能进行测试,因为Spring容器并不知道去哪里扫描Bean对象。需要在配置文件中配置注解,注解配置方式如下:

<context:component-scan base-package="Bean所在的包路径"/>

代码语言:javascript
复制
<!-- 使用context命名空间,通过Spring扫描指定包下所有Bean的实现类,进行注解解析 -->
  <context:component-scan base-package="annotation"/>

注:在Spring 4.0以上版本,配置注解指定包中的注解进行扫描前,需要事先导入Spring AOP的JAR包spring-aop-5.0.2.RELEASE.jar。

测试Bean实例就和上文一样了,不做赘述。

参考文章:

Spring 实例化bean的三种方式:https://www.cnblogs.com/quyanhui/p/3584812.html

Spring笔记--xml配置文件详解:

https://www.cnblogs.com/fingerboy/p/5271697.html

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-03-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 浩Coding 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档