Spring IOC 基础应用:BeanFactory与ApplicationContext区别及三种配置方式

Posted 丿涛哥哥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring IOC 基础应用:BeanFactory与ApplicationContext区别及三种配置方式相关的知识,希望对你有一定的参考价值。

Spring IOC 基础应用:BeanFactory与ApplicationContext区别及三种配置方式

1、 Spring IoC

Spring_11

1.1、 BeanFactory与ApplicationContext区别

BeanFactory是Spring框架中IoC容器的顶层接口,它只是用来定义一些基础功能,定义一些基础规范,而 ApplicationContext是它的一个子接口,所以ApplicationContext是具备BeanFactory提供的全部功能的。

通常,我们称BeanFactory为SpringIOC的基础容器,ApplicationContext是容器的⾼级接口,比 BeanFactory要拥有更多的功能,比如说国际化支持和资源访问(xml,java配置类)等等。

Spring_12

启动 IoC 容器的方式:

  • Java环境下启动IoC容器

    • ClassPathXmlApplicationContext:从类的根路径下加载配置文件(推荐使用)
    • FileSystemXmlApplicationContext:从磁盘路径上加载配置文件
    • AnnotationConfigApplicationContext:纯注解模式下启动Spring容器
  • Web环境下启动IoC容器

    • 从xml启动容器

      <!DOCTYPE web-app PUBLIC
      "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
      "http://java.sun.com/dtd/web-app_2_3.dtd" >
      <web-app>
      	 <display-name>Archetype Created Web Application</display-name>
      	 
      	 <!--配置Spring ioc容器的配置文件-->
      	 <context-param>
      		 <param-name>contextConfigLocation</param-name>
      		 <param-value>classpath:applicationContext.xml</param-value>
      	 </context-param>
      	 <!--使用监听器启动Spring的IOC容器-->
      	 <listener>
      		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
      	 </listener>
      </web-app>
      
    • 从配置类启动容器

      <!DOCTYPE web-app PUBLIC
      "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
      "http://java.sun.com/dtd/web-app_2_3.dtd" >
      <web-app>
      	 <display-name>Archetype Created Web Application</display-name>
      	 
      	 <!--告诉ContextloaderListener知道我们使用注解的方式启动ioc容器-->
      	 <context-param>
      		 <param-name>contextClass</param-name>
      		 <paramvalue>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
      	 </context-param>
      	 
      	 <!--配置启动类的全限定类名-->
      	 <context-param>
      		 <param-name>contextConfigLocation</param-name>
      		 <param-value>com.tao.edu.SpringConfig</param-value>
      	 </context-param>
      	 
      	 <!--使用监听器启动Spring的IOC容器-->
      	 <listener>
      		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
      	 </listener>
      </web-app>
      

2、 纯xml模式

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">

实例化Bean的三种方式

方式一:使用无参构造函数

在默认情况下,它会通过反射调用无参构造函数来创建对象。如果类中没有无参构造函数,将创建失败。

<!--配置service对象-->
<bean id="userService" class="com.tao.service.impl.TransferServiceImpl">
</bean>

方式二:使用静态方法创建

在实际开发中,我们使用的对象有些时候并不是直接通过构造函数就可以创建出来的,它可能在创建的过程中会做很多额外的操作。此时会提供一个创建对象的方法,恰好这个方法是static修饰的方法,即是此种情况。

例如,我们在做Jdbc操作时,会用到java.sql.Connection接口的实现类,如果是mysql数据库,那么用的就是JDBC4Connection,但是我们不会去写JDBC4Connection connection = new JDBC4Connection(),因为我们要注册驱动,还要提供URL和凭证信息,用 DriverManager.getConnection 方法来获取连接。

那么在实际开发中,尤其早期的项目没有使用Spring框架来管理对象的创建,但是在设计时使用了工厂模式解耦,那么当接口spring之后,工厂类创建对象就具有和上述例子相同特征,即可采用此种方式配置。

<!--使用静态方法创建对象的配置方方式-->
<bean id="userService" class="com.tao.factory.BeanFactory" factory-method="getTransferService"></bean>

方式三:使用实例化方法创建

此种方式和上面静态方法创建其实类似,区别是用于获取对象的方法不再是static修饰的了,而是类中的一个普通方法。此种方式比静态方法创建的使用几率要高一些。

在早期开发的项目中,工厂类中的方法有可能是静态的,也有可能是非静态方法,当是非静态方法时,即可采用下面的配置方式:

<!--使用实例方法创建对象的配置方式-->
<bean id="beanFactory" class="com.tao.factory.instancemethod.BeanFactory"></bean>
<bean id="transferService" factory-bean="beanFactory" factorymethod="getTransferService"></bean>

Bean的生命周期

作用范围的改变:

在spring框架管理Bean对象的创建时,Bean对象默认都是单例的,但是它支持配置的方式改变作用范围。作用范围官方提供的说明如下图:

在这里插入图片描述

在上图中提供的这些选项中,我们实际开发中用到最多的作用范围就是singleton(单例模式)和prototype(原型模式,也叫多例模式)。配置方式参考下面的代码:

<!--配置service对象-->
<bean id="transferService"
	class="com.tao.service.impl.TransferServiceImpl" scope="singleton">
</bean>

不同作用范围的生命周期:

单例模式:singleton

对象出生:当创建容器时,对象就被创建了。

对象活着:只要容器在,对象一直活着。

对象死亡:当销毁容器时,对象就被销毁了。

一句话总结:单例模式的bean对象生命周期与容器相同。

多例模式:prototype

对象出生:当使用对象时,创建新的对象实例。

对象活着:只要对象在使用中,就一直活着。

对象死亡:当对象长时间不用时,被java的垃圾回收器回收了。

一句话总结:多例模式的bean对象,spring框架只负责创建,不负责销毁。

Bean标签属性:

在基于xml的IoC配置中,bean标签是最基础的标签。它表示了IoC容器中的一个对象。换句话说,如果一个对象想让spring管理,在XML的配置中都需要使用此标签配置,Bean标签的属性如下:

id属性: 用于给bean提供一个唯一标识。在一个标签内部,标识必须唯一。

class属性: 用于指定创建Bean对象的全限定类名。

name属性: 用于给bean提供一个或多个名称。多个名称用空格分隔。

factory-bean属性: 用于指定创建当前bean对象的工厂bean的唯一标识。当指定了此属性之后,class属性失效。

factory-method属性: 用于指定创建当前bean对象的工厂方法,如配合factory-bean属性使用,则class属性失效。如配合class属性使用,则用法必须是static的。

scope属性: 用于指定bean对象的作用范围。通常情况下就是singleton。当要用到多例模式时,可以配置为prototype。

init-method属性: 用于指定bean对象的初始化方法,此方法会在bean对象装配后调用。必须是一个无参方法。

destory-method属性: 用于指定bean对象的销毁方法,此方法会在bean对象销毁前执行。它只能为scope是singleton时起作用。

DI 依赖注入的xml配置:

  • 依赖注入分类:

    • 按照注入的方式分类:

      构造函数注入: 顾名思义,就是利用带参构造函数实现对类成员的数据赋值。

      set方法注入: 它是通过类成员的set方法实现数据的注入。(使用最多的)

    • 按照注入的数据类型分类:

      基本类型和String

      注入的数据类型是基本类型或者是字符串类型的数据。

      其他Bean类型

      注入的数据类型是对象类型,称为其他Bean的原因是,这个对象是要求出现在IoC容器中的。那么针对当前Bean来说,就是其他Bean了。

      复杂类型(集合类型)

      注入的数据类型是Aarry,List,Set,Map,Properties中的一种类型。

    • 依赖注入的配置实现构造函数注入,就是利用构造函数实现对类成员的赋值。它的使用要求是,类中提供的构造函数参数个数必须和配置的参数个数一致,且数据类型匹配。同时需要注意的是,当没有无参构造时,则必须提供构造函数参数的注入,否则Spring 框架会报错。

Spring_14

Spring_15

在使用构造函数注入时,涉及的标签是 constructor-arg ,该标签有如下属性:

name: 用于给构造函数中指定名称的参数赋值。

index: 用于给构造函数中指定索引位置的参数赋值。

value: 用于指定基本类型或者String类型的数据。

ref: 用于指定其他Bean类型的数据。写的是其他bean的唯一标识。

  • 依赖注入的配置实现之set方法注入

顾名思义,就是利用字段的set方法实现赋值的注入方式。此种方式在实际开发中是使用最多的注入方式。

Spring_16

在这里插入图片描述

在使用set方法注入时,需要使用 property 标签,该标签属性如下:

name: 指定注入时调用的set方法名称。(注:不包含set这三个字⺟,druid连接池指定属性名称)

value: 指定注入的数据。它⽀持基本类型和String类型。

ref: 指定注入的数据。它⽀持其他bean类型。写的是其他bean的唯一标识。

  • 复杂数据类型注入:⾸先,解释一下复杂类型数据,它指的是集合类型数据。集合分为两类,一类 是List结构(数组结构),一类是Map接⼝(键值对) 。

接下来就是注入的方式的选择,只能在构造函数和set方法中选择,我们的示例选用set方法注入。

Spring_18

Spring_19

在List结构的集合数据注入时,array , list , set 这三个标签通用,另外注值的 value 标签内部 可以直接写值,也可以使用 bean 标签配置一个对象,或者用 ref 标签引用一个已经配合的bean的唯一标识。

在Map结构的集合数据注入时, map 标签使用 entry ⼦标签实现数据注入, entry 标签可以使 用keyvalue属性指定存入map中的数据。使用value-ref属性指定已经配置好的bean的引用。 同时 entry 标签中也可以使用 ref 标签,但是不能使用 bean 标签。而 property 标签中不能使 用 ref 或者bean标签引用对象

3、 xml与注解相结合模式

注意:

  1. 实际企业开发中,纯xml模式使用已经很少了
  2. 引入注解功能,不需要引入额外的jar
  3. xml+注解结合模式,xml文件依然存在,所以,spring IOC容器的启动仍然从加载xml开始
  4. 哪些bean的定义写在xml中,哪些bean的定义使用注解

第三方jar中的bean定义在xml,比如德鲁伊数据库连接池

自己开发的bean定义使用注解

  • xml中标签与注解的对应(IoC)
xml形式****对应的注解形式
标签@Component(“accountDao”),注解加在类上 bean的id属性内容直接配置在注解后⾯如果不配置,默认定义个这个bean的id为类 的类名⾸字⺟⼩写;另外,针对分层代码开发提供了@Componenet的三种别名@Controller、 @Service、@Repository分别用于控制层类、服务层类、dao层类的bean定义,这 四个注解的用法完全一样,只是为了更清晰的区分⽽已
标签的 scope属 性@Scope(“prototype”),默认单例,注解加在类上
标签的 initmethod 属性@PostConstruct,注解加在方法上,该方法就是初始化后调用的方法
标签的 destorymethod 属性@PreDestory,注解加在方法上,该方法就是销毁前调用的方法
  • DI 依赖注入的注解实现方式

@Autowired(推荐使用)

@Autowired为Spring提供的注解,需要导入包 org.springframework.beans.factory.annotation.Autowired。

@Autowired采取的策略为按照类型注入。

public class TransferServiceImpl {
	 @Autowired
	 private AccountDao accountDao;
}

如上代码所示,这样装配回去spring容器中找到类型为AccountDao的类,然后将其注入进来。这样会产生一个问题,当一个类型有多个bean值的时候,会造成无法选择具体注入哪一个的情况, 这个时候我们需要配合着@Qualifier使用。

@Qualifier告诉Spring具体去装配哪个对象。

public class TransferServiceImpl {
     @Autowired
     @Qualifier(name="jdbcAccountDaoImpl")
     private AccountDao accountDao;
}

这个时候我们就可以通过类型和名称定位到我们想注入的对象。

@Resource

@Resource 注解由 J2EE 提供,需要导入包 javax.annotation.Resource。

@Resource 默认按照 ByName 自动注入。

public class TransferService {
     @Resource
     private AccountDao accountDao;
     @Resource(name="studentDao")
     private StudentDao studentDao;
     @Resource(type="TeacherDao")
     private TeacherDao teacherDao;
     @Resource(name="manDao",type="ManDao")
     private ManDao manDao;
} 
  • 如果同时指定了 name 和 type,则从Spring上下文中找到唯一匹配的bean进⾏装配,找不到则抛出异常。
  • 如果指定了 name,则从上下文中查找名称(id)匹配的bean进⾏装配,找不到则抛出异常。
  • 如果指定了 type,则从上下文中找到类似匹配的唯一bean进⾏装配,找不到或是找到多个, 都会抛出异常。
  • 如果既没有指定name,⼜没有指定type,则自动按照byName方式进⾏装配;

注意:

@Resource 在 Jdk 11中已经移除,如果要使用,需要单独引入jar包

<dependency>
     <groupId>javax.annotation</groupId>
     <artifactId>javax.annotation-api</artifactId>
     <version>1.3.2</version>
</dependency>

4、 纯注解模式

改造xm+注解模式,将xml中遗留的内容全部以注解的形式迁移出去,最终删除xml,从Java配置类启动

对应注解

@Configuration 注解,表名当前类是一个配置类

@ComponentScan 注解,替代 context:component-scan

@PropertySource,引入外部属性配置文件

@Import 引入其他配置类

@Value 对变量赋值,可以直接赋值,也可以使用 ${} 读取资源配置文件中的信息

@Bean 将方法返回对象加入 SpringIOC 容器

以上是关于Spring IOC 基础应用:BeanFactory与ApplicationContext区别及三种配置方式的主要内容,如果未能解决你的问题,请参考以下文章

String---IOC

Spring Boot IoC 容器初始化过程

Spring_IOC

Spring的Core模块

Spring IOC 基础应用:BeanFactory与ApplicationContext区别及三种配置方式

Spring基础