Enterprise-level Spring-探索Spring-从入门到入厂

Posted man_one

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Enterprise-level Spring-探索Spring-从入门到入厂相关的知识,希望对你有一定的参考价值。

目录

一、Spring简介

二、Spring体系结构

三、Core contaainer(核心容器)

 3.1 IoC 容器

3.1.1IoC容器概述

3.1.2  Spring IOC的两个容器

3.1.3  BeanFactory

3.1.4 ApplicationContext

3.1.5 BeanFactory 和 ApplicationContext 的区别:

3.2  依赖注入(Dependency Injection,DI)

3.2.1 什么是DI依赖注入?

3.3  依赖注入的实现方式

3.3.1  set注入(主流)

3.3.2  构造器注入(了解)

3.3.3   集合类型数据注入

3.3.4   使用p命名空间简化配置(了解)

3.3.5  SpEL (了解)

3.3.6  properties文件

3.3.7   import(团队开发)

四、Spring中的 Bean

4.1 bean的配置

4.2 bean的实例化

4.3 Bean的三种实例化方式

4.4 bean属性scope(作用域)

4.4.1 singleton

4.4.2 prototype

4.5 Bean的生命周期



一、Spring简介

Spring 使创建 Java 企业应用程序变得容易。它提供了在企业环境中使用 Java 语言所需的一切,并支持 Groovy 和 Kotlin 作为 JVM 上的替代语言,并且可以根据应用程序的需求灵活地创建多种体系结构。从 Spring Framework 5.0 开始,Spring 需要 JDK 8(Java SE 8),并且已经为 JDK 9 提供了现成的支持。如图1-1

图1-1 Spring发展史

Spring 支持广泛的应用场景。在大型企业中,应用程序通常存在很长时间,并且必须在升级周期不受开发人员控制的 JDK 和应用程序服务器上运行。其他服务器则可以作为单个 jar 运行,并且服务器可以嵌入云环境中。还有一些可能是不需要服务器的独立应用程序(例如批处理或集成工作负载)。

Spring 是开源的。它拥有一个庞大而活跃的社区,可以根据各种实际用例提供持续的反馈。这帮助 Spring 在很长一段时间内成功地 Developing 了。

GitHub社区:https://github.com/spring-projects

Spring 中文 文档:Spring Framework 中文文档 - Spring 框架概述 | Docs4devSpring 是一个开放源代码的设计层面框架,它解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用。Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson创建。简单来说,Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架。https://www.docs4dev.com/docs/zh/spring-framework/5.1.3.RELEASE/reference/overview.html#overview-spring

官网 : Spring | Home

官方下载地址 : JFrog

Spring优势
| ------------------------ | -------- |
| 方便解耦,简化开发       |   |
| 方便集成各种优秀框架     |   |
| 方便程序的测试           |  |
| AOP编程的支持            |   |
| 声明式事务的支持         |    |
| 降低JavaEE API的使用难度 |   |
| Java源码是经典学习范例   |  |

                                  图 1-2 Spring的优势作用

二、Spring体系结构

图 2-1 Spring体系结构

三、Core contaainer(核心容器)

  • 核心容器:核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转(IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。

  • Spring 上下文:Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。

  • Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向切面的编程功能 , 集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理任何支持 AOP的对象。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖组件,就可以将声明性事务管理集成到应用程序中。

  • Spring DAO:JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。

  • Spring ORM:Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。

  • Spring Web 模块:Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。

  • Spring MVC 框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。

 3.1 IoC 容器

3.1.1IoC容器概述

- IoC(Inversion Of Control)控制反转,Spring反向控制应用程序所需要使用的外部资源

- Spring控制的资源全部放置在Spring容器中,该容器称为IoC容器

IoC是Spring框架的核心内容,使用多种方式完美的实现了IoC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置实现IoC。

Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象。

 控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,也有人认为DI只是IoC的另一种说法。没有IoC的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。(狂神说java)

                                  图3-1 IOC容器

IoC是Spring框架的核心内容,使用多种方式完美的实现了IoC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置实现IoC。

Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象。

ctrl+V了这么多废话,终于可以说重点了!                       

3.1.2  Spring IOC的两个容器

对于 IoC 来说,最重要的就是容器。容器管理着 Bean 的生命周期,控制着 Bean 的依赖注入。

那么, Spring 如何设计容器的呢?

Spring 作者 Rod Johnson 设计了两个接口用以表示容器。

  • BeanFactory

  • ApplicationContext

BeanFactory  E西好用!,是就是个 HashMap,Key 是 BeanName,Value 是 Bean 实例。

ApplicationContext 可以称之为 “高级容器”。因为他比 BeanFactory 多了更多的功能。他继承了多个接口。因此具备了更多的功能。例如资源的获取,支持多种消息(例如 JSP tag 的支持),对 BeanFactory 多了工具级别的支持等待。所以你看他的名字,已经不是 BeanFactory 之类的工厂了,而是 “应用上下文”, 代表着整个大容器的所有功能。该接口定义了一个 refresh 方法,此方法是所有阅读 Spring 源码的人的最熟悉的方法,用于刷新整个容器,即重新加载/刷新所有的 bean。

                                                图 3-2 ApplicationContext 的接口类

其实还有其他接口....

3.1.3  BeanFactory

 BeanFactory 位于设计的最底层,它提供了 Spring IoC 最底层的设计,其方法如下:

     图3-3 BeanFactory的方法体

  • getBean 对应了多个方法来获取配置给 Spring IoC 容器的 Bean。
    1.按照类型拿 bean:
    bean = (Bean) factory.getBean(Bean.class);
    注意:要在 Spring 中只配置了一个这种类型的实例,不然报错。(如果有多个那 Spring 就懵了,不知道该获取哪一个)
    2. 按照 bean 的名字拿 bean:
    bean = (Bean) factory.getBean("beanName");
    注意:这种方法不太安全,IDE 不会检查其安全性(关联性)
    3. 按照名字和类型拿 bean:(推荐)
    bean = (Bean) factory.getBean("beanName", Bean.class);
  • isSingleton 用于判断是否单例,如果判断为真,其意思是该 Bean 在容器中是作为一个唯一单例存在的。而【isPrototype】则相反,如果判断为真,意思是当你从容器中获取 Bean,容器就为你生成一个新的实例。
    注意:在默认情况下,【isSingleton】为 ture,而【isPrototype】为 false
  • 关于 type 的匹配,这是一个按 Java 类型匹配的方式
  • getAliases  方法是获取别名的方法

3.1.4 ApplicationContext

创建一个Service接口

写入方法

public class UserServiceImpl implements UserService 
    public void save() 
        System.out.println("user service running...");
    

配置applicationContext.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 1.创建spring控制的资源-->
    <bean id="userService" class="impl.service.impl.UserServiceImpl"/>
</beans>

Test

public static void main(String[] args) 
        //2.加载配置文件
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        //3.获取资源
        UserService userService = (UserService) ctx.getBean("userService");
        userService.save();
    

ApplicationContext 常见实现类:

1.ClassPathXmlApplicationContext:
读取classpath中的资源

ApplicationContext c = new ClassPathXmlApplicationContext("applicationContext.xml");

2:FileSystemXmlApplicationContext:-
读取指定路径的资源

ApplicationContext a = new FileSystemXmlApplicationContext("c:/applicationContext.xml");

3.XmlWebApplicationContext:
需要在Web的环境才可运行

XmlWebApplicationContext ac = new XmlWebApplicationContext(); // 这时并没有初始化容器 ac.setServletContext(servletContext); // 需要指定ServletContext对象 ac.setConfigLocation("/WEB-INF/applicationContext.xml"); // 指定配置文件路径,开头的斜线表示Web应用的根目录 ac.refresh(); // 初始化容器

3.1.5 BeanFactory 和 ApplicationContext 的区别:

  • BeanFactory:是Spring中最底层的接口,只提供了最简单的IoC功能,负责配置,创建和管理bean。
    在应用中,一般不使用 BeanFactory,而推荐使用ApplicationContext(应用上下文),原因如下。
  • ApplicationContext:
    1.继承了 BeanFactory,拥有了基本的 IoC 功能;
    2.除此之外,ApplicationContext 还提供了以下功能:
    ① 支持国际化;
    ② 支持消息机制;
    ③ 支持统一的资源加载;
    ④ 支持AOP功能;

3.2  依赖注入(Dependency Injection,DI)

3.2.1 什么是DI依赖注入?

  spring动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,依赖注入)来实现的。比如对象A需要操作数据库,以前我们总是要在A中自己编写代码来获得一个Connection对象,有了 spring我们就只需要告诉spring,A中需要一个Connection,至于这个Connection怎么构造,何时构造,A不需要知道。在系统运行时,spring会在适当的时候制造一个Connection,然后像打针一样,注射到A当中,这样就完成了对各个对象之间关系的控制。A需要依赖 Connection才能正常运行,而这个Connection是由spring注入到A中的,依赖注入的名字就这么来的。那么DI是如何实现的呢? Java 1.3之后一个重要特征是反射(reflection),它允许程序在运行的时候动态的生成对象、执行对象的方法、改变对象的属性,spring就是通过反射来实现注入的。

  简单来说什么是依赖注入,就是给属性赋值(包括基本数据类型和引用数据类型)

java面向对象的方式,需要调用另一个java对象,采用"new 被调用者"的方式创建对象,缺点是调用与被调用者的耦合增强,不利于后期维护。

 使用Spring框架后,对象不在由调用者创建,而是由Spring容器创建,容器会负责控制程序间的关系,而不是由调用者直接控制,我们称控制权转移的这种情况为Spring控制反转!

3.3  依赖注入的实现方式

3.3.1  set注入(主流)

- 名称:property

- 类型:**标签**

- 归属:bean标签

- 作用:使用set方法的形式为bean提供资源

- 格式:

  ```java
  <bean>
      <property />
  </bean>
  ```

- 基本属性:

  ```xml
  <property name="propertyName" value="propertyValue" ref="beanId"/>
  ```

​    name:对应bean中的属性名,要求该属性必须提供可访问的set方法(严格规范为此名称是set方法对应名称)

​    value:设定非引用类型属性对应的值,不能与ref同时使用

​    ref:设定引用类型属性对应bean的id ,不能与value同时使用

- 注意:一个bean可以有多个property标签

3.3.2  构造器注入(了解)

- 名称:constructor-arg

- 类型:**标签**

- 归属:bean标签

- 作用:使用构造方法的形式为bean提供资源,兼容早期遗留系统的升级工作

- 格式:

  ```xml
  <bean>
      <constructor-arg />
  </bean>
  ```

- 基本属性:

  ```xml
  <constructor-arg name="argsName" value="argsValue />
  ```

​    name:对应bean中的构造方法所携带的参数名

​    value:设定非引用类型构造方法参数对应的值,不能与ref同时使用

其他属性:

```xml
<constructor-arg index="arg-index" type="arg-type" ref="beanId"/>
```

​    ref:设定引用类型构造方法参数对应bean的id ,不能与value同时使用

​    type :设定构造方法参数的类型,用于按类型匹配参数或进行类型校验

​    index :设定构造方法参数的位置,用于按位置匹配参数,参数index值从0开始计数

- 注意:一个bean可以有多个constructor-arg标签

3.3.3   集合类型数据注入

- 名称:array,list,set,map,props

- 类型:**标签**

- 归属:property标签 或 constructor-arg标签

- 作用:注入集合数据类型属性

- 格式:

  ```xml
  <property>
      <list></list>
  </property>
  ```

(1)集合类型数据注入——list

```xml
<property name="al">
    <list>
        <value>itheima</value>
        <value>66666</value>
    </list>
</property>
```

(2)集合类型数据注入——props

```xml
<property name="properties">
    <props>
        <prop key="name">zhangsan666</prop>
        <prop key="value">666666</prop>
    </props>
</property>
```

(3)集合类型数据注入——array (了解)

```xml
<property name="arr">
    <array>
        <value>123456</value>
        <value>66666</value>
    </array>
</property>
```

(4)集合类型数据注入——set(了解)

```xml
 <property name="hs">
     <set>
         <value>Test</value>
         <value>66666</value>
     </set>
</property>
```

(5)集合类型数据注入——map(了解)

```xml
<property name="hm">
    <map>
        <entry key="name" value="Test66666"/>
        <entry key="value" value="6666666666"/>
    </map>
</property>


3.3.4   使用p命名空间简化配置(了解)

- 名称:p:propertyName,p:propertyName-ref

- 类型:**属性**

- 归属:bean标签

- 作用:为bean注入属性值

- 格式:

  ```xml
  <bean p:propertyName="propertyValue" p:propertyName-ref="beanId"/>
  ```

- 注意:使用p命令空间需要先开启spring对p命令空间的的支持,在beans标签中添加对应空间支持

  ```xml
   <bean
         id="userService"
         class="com.itheima.service.impl.UserServiceImpl"
         p:userDao-ref="userDao"
         p:bookDao-ref="bookDao"
         />
  ```

  

3.3.5  SpEL (了解)

- Spring提供了对EL表达式的支持,统一属性注入格式

- 类型:**属性值**

- 归属:value属性值

- 作用:为bean注入属性值

- 格式:

  ```xml
  <property value="EL"></bean>
  ```

- 注意:所有属性值不区分是否引用类型,统一使用value赋值

- 所有格式统一使用  value=“********”

  - 常量  #10  #3.14  #2e5  #‘itcast’

  - 引用bean  #beanId    

  - 引用bean属性  #beanId.propertyName

  - 引用bean方法  beanId.methodName().method2()

  - 引用静态方法  T(java.lang.Math).PI

  - 运算符支持  #3 lt 4 == 4 ge 3

  - 正则表达式支持  #user.name matches‘[a-z]6,’

  - 集合支持  #likes[3]

3.3.6  properties文件

- Spring提供了读取外部properties文件的机制,使用读取到的数据为bean的属性赋值

- 操作步骤

  1.准备外部properties文件

  2.开启context命名空间支持

  ```xml
  xmlns:context="http://www.springframework.org/schema/context"
  ```

​        3.加载指定的properties文件

```xml
<context:property-placeholder location="classpath:filename.properties">
```

​        4.使用加载的数据

```xml
<property name="propertyName" value="$propertiesName"/>
```

- 注意:如果需要加载所有的properties文件,可以使用`*.properties`表示加载所有的properties文件

- 注意:读取数据使用**$propertiesName**格式进行,其中**propertiesName**指properties文件中的属性名

3.3.7   import(团队开发)

- 名称:import

- 类型:**标签**

- 归属:beans标签

- 作用:在当前配置文件中导入其他配置文件中的项

- 格式:

  ```xml
  <beans>
      <import />
  </beans>
  ```

- 基本属性:

  ```xml
  <import resource=“config.xml"/>
  ```

​    resource:加载的配置文件名

- Spring容器加载多个配置文件

  ```java
  new ClassPathXmlApplicationContext("config1.xml","config2.xml");
  ```

- Spring容器中的bean定义冲突问题

  - 同id的bean,后定义的覆盖先定义的

  - 导入配置文件可以理解为将导入的配置文件复制粘贴到对应位置

  - 导入配置文件的顺序与位置不同可能会导致最终程序运行结果不同

想要测试详情请参考:狂神说Spring03:依赖注入(DI)

四、Spring中的 Bean

4.1 bean的配置

Spring中,XML配置文件的根元素是<beans>,<beans>中包含了多个<bean>子元素,每一个<bean>中定义了一个Bean

属性名称描述
id是一个 Bean 的唯一标识符,Spring 容器对 Bean 的配置和管理都通过该属性完成
nameSpring 容器同样可以通过此属性对容器中的 Bean 进行配置和管理,name 属性中可以为 Bean 指定多个名称,每个名称之间用逗号或分号隔开
class该属性指定了 Bean 的具体实现类,它必须是一个完整的类名,使用类的全限定名
scope 用于设定 Bean 实例的作用域,其属性值有 singleton(单例)、prototype(原型)、request、session 和 global Session。其默认值是 singleton
constructor-arg<bean>元素的子元素,可以使用此元素传入构造参数进行实例化。该元素的 index 属性指定构造参数的序号(从 0 开始),type 属性指定构造参数的类型
property<bean>元素的子元素,用于调用 Bean 实例中的 Set 方法完成属性赋值,从而完成依赖注入。该元素的 name 属性指定 Bean 实例中的相应属性名
ref<property> 和 <constructor-arg> 等元素的子元索,该元素中的 bean 属性用于指定对 Bean 工厂中某个 Bean 实例的引用
value<property> 和 <constractor-arg> 等元素的子元素,用于直接指定一个常量值
list用于封装 List 或数组类型的依赖注入
set用于封装 Set 类型属性的依赖注入
map用于封装 Map 类型属性的依赖注入
entry<map> 元素的子元素,用于设置一个键值对。其 key 属性指定字符串类型的键值,ref 或 value 子元素指定其值

4.2 bean的实例化

- 名称:bean

- 类型:**标签**

- 归属:beans标签

- 作用:定义spring中的资源,受此标签定义的资源将受到spring控制

- 格式:

  ```xml
  <beans>
      <bean />
  </beans>
  ```

- 基本属性:

  ```xml
  <bean id="beanId" name="beanName1,beanName2" class="ClassName"></bean>
  ```

  ​    id:bean的名称,通过id值获取bean

  ​    class:bean的类型

  ​    name:bean的名称,可以通过name值获取bean,用于多人配合时给bean起别名

                        测试一下

创建一个接口以及实现类:

public interface UserService 
    public void save();

public class UserServiceImpl implements UserService 
    public void save() 
        System.out.println("Hello world");
    

applicationContext.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 1.创建spring控制的资源-->
    <bean id="userService" class="com.service.impl.UserServiceImpl"/>
</beans>

注意:在Bean中为指定id和name,spring会将class当id值

创建测试类:

public static void main(String[] args) 
        //2.加载配置文件
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        //3.获取资源
        UserService userService = (UserService) ctx.getBean("userService");
        userService.save();
    

输出了Hello world

4.3 Bean的三种实例化方式

BeanFactory作用

  • 配置、创建以及管理Bean对象

  • 维持Bean对象之间的依赖关系

  • 负责Bean对象的生命周期

上面我们通过小案例了解了bean的大致概念,下面我们来学习Bean的实例化方式

①构造器实例化

指Spring容器通过Bean对应类中的默认无参构造方法实例化。

②静态工厂实例化

创建静态工厂的方法来创建Bean实例,其中Bean的class属性所指定的不是Bean实现类而是静态工厂类,需要使用factory-merhod属性来指定创建的静态工厂。

                           文件 MyBean2Facory

public class MyBean2Facory 
    //使用自己创建的Bean2工厂
    public static Bean2 createBean()
        return new Bean2();
    

                        applicationContest.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"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">

     <bean id="Bean2" class="instance.MyBean2Facory"
            factory-method="createBean"/>
 </beans>

③实例工厂实例化

                                        创建实例工厂MyBean3Factory

public class MyBean3Facory 
    public MyBean3Facory() 
        System.out.println("bean3工厂实例化中....");
    
    //使用自己创建的Bean2工厂
    public Bean3 createBean()
        return new Bean3();
    

             创建beans3.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"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">

     <bean id="MyBean3Facory" class="instance.MyBean3Facory"/>
        <!--使用factory-bean属性执行实例工厂-->
    <!--使用factory-method属性确定使用的方法-->
    <bean id="bean3"  factory-bean="MyBean3Facory" factory-method="createBean"/>
 </beans>

   <!--使用factory-bean属性执行实例工厂-->
    <!--使用factory-method属性确定使用的方法-->

测试输出

4.4 bean属性scope(作用域)

    作用域的类型;

作用域名称说明

singleton

默认值,单例模式,表示在 Spring 容器中只有一个 Bean 实例,Bean 以单例的方式存在。

prototype

原型模式,表示每次通过 Spring 容器获取 Bean 时,容器都会创建一个 Bean 实例。

request

每次 HTTP 请求,容器都会创建一个 Bean 实例。该作用域只在当前 HTTP Request 内有效。

session

同一个 HTTP Session 共享一个 Bean 实例,不同的 Session 使用不同的 Bean 实例。该作用域仅在当前 HTTP Session 内有效。

application

同一个 Web 应用共享一个 Bean 实例,该作用域在当前 ServletContext 内有效。类似于 singleton,不同的是,singleton 表示每个 IoC 容器中仅有一个 Bean 实例,而同一个 Web 应用中可能会有多个 IoC 容器,但一个 Web 应用只会有一个 ServletContext,也可以说 application 才是 Web 应用中货真价实的单例模式。

websocket

websocket 的作用域是 WebSocket ,即在整个 WebSocket 中有效。

4.4.1 singleton

名称:scope

- 类型:**作用域**

- 归属:bean标签

- 作用:定义bean的作用范围

- 格式:

  • <bean id="..." class="..." scope="singleton"/>

HelloWorld 类代码如下。

public class HelloWorld 
private String message;

public void setMessage(String message) 
this.message = message;


public void getMessage() 
System.out.println("message : " + message);

MainApp 类如下。

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp 
    public static void main(String[] args) 
        ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
        HelloWorld objA = (HelloWorld) context.getBean("helloWorld");
        objA.setMessage("对象A");
        objA.getMessage();
        HelloWorld objB = (HelloWorld) context.getBean("helloWorld");
        objB.getMessage();
    

Beans.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-3.0.xsd">
    <bean id="helloWorld" class="HelloWorld" scope="singleton"/>
      
</beans>

运行结果如下。

message : 对象A
message : 对象A

从运行结果可以看出,两次输出内容相同,这说明 Spring 容器只创建了一个 HelloWorld 类的实例。由于 Spring 容器默认作用域是 singleton,所以如果省略 scope 属性,其输出结果也会是一个实例。

4.4.2 prototype

名称:scope

- 类型:**作用域**

- 归属:bean标签

- 作用:定义bean的作用范围

- 格式:

  • <bean id="..." class="..." scope="prototype"/>

在上面例子 的基础上,修改配置文件 Beans.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-3.0.xsd">

    <bean id="helloWorld" class="HelloWorld" scope="prototype"/>
      
</beans>

运行结果如下。

message : 对象A
message : null

4.5 Bean的生命周期

Spring 根据 Bean 的作用域来选择管理方式。对于 singleton 作用域的 Bean,Spring 能够精确地知道该 Bean 何时被创建,何时初始化完成,以及何时被销毁;而对于 prototype 作用域的 Bean,Spring 只负责创建,当容器创建了 Bean 的实例后,Bean 的实例就交给客户端代码管理,Spring 容器将不再跟踪其生命周期。

 了解 Spring 生命周期的意义就在于,可以利用 Bean 在其存活期间的指定时刻完成一些相关操作。一般情况下,会在 Bean 被初始化后和被销毁前执行一些相关操作。

Spring 官方提供了 3 种方法实现初始化回调和销毁回调:

  1. 实现 InitializingBean 和 DisposableBean 接口;
  2. 在 XML 中配置 init-method 和 destory-method;
  3. 使用 @PostConstruct 和 @PreDestory 注解。


在一个 Bean 中有多种生命周期回调方法时,优先级为:注解 > 接口 > XML。

不建议使用接口和注解,这会让 pojo 类和 Spring 框架紧耦合。

以上是关于Enterprise-level Spring-探索Spring-从入门到入厂的主要内容,如果未能解决你的问题,请参考以下文章

三探循环依赖 → 记一次线上偶现的循环依赖问题

Spring事务管理---上

Spring CommonsMultipartResolver上传文件小结

Redis实战之达人探店

Redis实战之达人探店

一个模仿探探头像编辑效果解析