Spring中Bean的配置、实例化、作用域、生命周期和装配方式

1 Bean的配置

1.1 概述

  举个生动的例子吧。如果把Spring看作是一个大工厂的话,那么Bean就是这个工厂里的产品。当我们要使用这些产品的时候,就需要工厂为我们生产,工厂还需要管理这些产品,这就需要我们告诉工厂我们需要哪些产品(Bean),以及需要使用何种方式将这些产品(Bean)装配到一起。
  Bean的本质其实就是Java中的类,而Spring中的Bean其实就是对实体类的引用,来生产Java类对象,从而实现生产和管理Bean。
  在Spring容器中,支持两种格式的配置文件:Properties文件和XML文件。在实际的开发中,最常使用的是XML文件格式的配置方式,这种配置方式是通过XML文件来注册并管理Bean之间的依赖关系。

1.2 属性或子元素

  • XML配置文件的根元素是<beans>
  • <beans>包含了多个<bean>子元素,每一个<bean>子元素定义一个Bean
  • <bean>元素常用属性如下:
属性或子元素名称描述
id是一个Bean的唯一标识符,Spring容器对Bean的配置、管理都通过该属性来完成
nameSpring容器同样可以通过此属性对容器中的Bean进行配置和管理,name的属性中可以为bean指定多个名称,每个名称之间用逗号或分号隔开
class该属性指定了Bean的具体实现类,必须是一个完整的类名,使用类的全限定名
scope用来设定Bean实例的作用域,属性值有:singleton(单例)、prototype(原型)、request、session、global session、application和websocket,默认值为singleton

  配置文件中,一个普通的Bean只需要定义id(或name)和class两个属性即可,如下:

<?xml version=" 1.0" encoding="UTF-8"?>
<beans xmIns= *"http://www.springframework.org/schema/beans"
		xmlns:xsi-="http://www.w3.org/2001/XML Schema-instance"
		xsi:schemaL ocation="http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd">
	<bean id='bean1"' class= 'cn.edu.ujn.Bean1"' />
	<bean name="bean2" class= "cn.edu.ujn.Bean2" />
</beans>

  注:要是没有指定Bean的id和name,则Spring会将class的值当作id使用。

2 Bean的实例化

  实例化:在面向对象的程序中,要想使用某个对象,就需要先实例化这个对象。在Spring中实例化Bean有三种方式:

  1. 构造器实例化
  2. 静态工厂方式实例化
  3. 实例工厂方式实例化

  注:比较常用的是构造器实例化

2.1 构造器实例化

  构造器实例化是指Spring容器通过Bean对应的类中默认的构造函数来实例化Bean。使用构造器来创建Bean实例是最常见的情况,如果不采用构造注入,Spring底层会调用Bean类的无参数构造器来创建实例,因此要求该Bean类提供无参数的构造器。采用默认的构造器创建Bean实例,Spring对Bean实例的所有属性执行默认初始化,即所有的基本类型的值初始化为0或false;所有的引用类型的值初始化为null。
  使用如下:

2.2 静态工厂方式实例化

  静态工厂是实例化Bean的另一种方式。该方式要求自己创建一个 静态工厂的方法来创建Bean的实例。使用静态工厂方法创建Bean实例时,class属性也必须指定,但此时class属性并不是指定Bean实例的实现类,而是静态工厂类,Spring通过该属性知道由哪个工厂类来创建Bean实例。
  除此之外,还需要使用factory-method属性来指定静态工厂方法,Spring将调用静态工厂方法返回一个Bean实例,一旦获得了指定Bean实例,Spring后面的处理步骤与采用普通方法创建Bean实例完全一样。
  使用如下:

2.3 实例工厂方式实例化

  实例工厂是采用直接创建Bean实例的方式,在配置文件中,通过factory-bean属性配置一个实例工厂,然后使用factory-method属性确定使用工厂中哪个方法。实例工厂方法与静态工厂方法只有一个不同:调用静态工厂方法只需使用工厂类即可,而调用实例工厂方法则需要工厂实例。使用实例工厂方法时,配置Bean实例的<bean…/>元素无须class属性,配置实例工厂方法使用factory-bean指定工厂实例。
采用实例工厂方法创建Bean的<bean…/>元素时需要指定如下两个属性:

  • factory-bean: 该属性的值为工厂Bean的id。
  • factory-method: 该属性指定实例工厂的工厂方法。

  使用如下:

3 Bean的作用域

  Spring 4.3中定义了7种作用域,如下所示:

这里边singleton和prototype是最常用的两种作用域。

3.1 singleton作用域

  singleton是Spring容器默认的作用域,容器里就只会存在一个共享的实例,无论我们调用多少次,就只存在一个。singleton作用域对于无会话状态的Bean(如Dao组件、Service层组件)来说,是最理想的选择。 无会话状态的Bean就是说只要给一个输入和输出,就会做相应的业务逻辑,不记录之前所做的任何事情。

  • 配置方式:
    在Spring的配置文件中使用<bean>元素的scope属性,将Bean的作用域定义为singleton。

3.2 prototype作用域

  对需要保持会话状态的Bean(如Struts 2的Action类)应该使用prototype作用域。在使用prototype作用域的时候,Spring容器会为每个对该Bean的请求都创建一个新的实例。也就是说我们每一次获取的都是不一样的实例。在Web的交互层我们一般需要prototype。

  • 配置方式:
    在Spring的配置文件中使用<bean>元素的scope属性,将Bean的作用域定义为prototype。

4 Bean的生命周期

4.1 Spring中Bean的生命周期的意义

  了解Spring中的Bean的生命周期的意义就在于,可以利用Bean在其存活期间的特定时刻完成一些相关操作。这种时刻可能有很多,但一般情况下,常会在Bean的postinitiation(初始化后)和predestruction(销毁前)执行一些相关操作。

4.2 Spring容器管理Bean部分作用域的生命周期

4.2.1 singleton作用域

  Spring容器可以管理singleton作用域的Bean的生命周期。在此作用域下,Spring能够精确知道该Bean何时被创建,何时被初始化,以及何时被销毁。

4.2.2 prototype作用域

  prototype作用域的Bean,Spring只负责创建,当容器创建了Bean的实例之后,Bean的实例就交给客户端代码来管理,Spring容器将不再跟踪其生命周期。

4.3 Spring容器中Bean的生命周期流程

  Spring容器中Bean的生命周期流程如图所示:

ApplicationContext容器中,Bean的生命周期流程如上图所示,流程大致如下:

  1. 首先容器启动后,会对scope为singleton且非懒加载的bean进行实例化;
  2. 按照Bean定义信息配置信息,注入所有的属性;
  3. 如果Bean实现了BeanNameAware接口,会回调该接口的setBeanName()方法,传入该Bean的id,此时该Bean就获得了自己在配置文件中的id;
  4. 如果Bean实现了BeanFactoryAware接口,会回调该接口的setBeanFactory()方法,传入该Bean的BeanFactory,这样该Bean就获得了自己所在的BeanFactory;
  5. 如果Bean实现了ApplicationContextAware接口,会回调该接口的setApplicationContext()方法,传入该Bean的ApplicationContext,这样该Bean就获得了自己所在的ApplicationContext;
  6. 如果有Bean实现了BeanPostProcessor接口,则会回调该接口的postProcessBeforeInitialzation()方法;
  7. 如果Bean实现了InitializingBean接口,则会回调该接口的afterPropertiesSet()方法;
  8. 如果Bean配置了init-method方法,则会执行init-method配置的方法;
  9. 如果有Bean实现了BeanPostProcessor接口,则会回调该接口的postProcessAfterInitialization()方法;
  10. 经过流程9之后,就可以正式使用该Bean了,对于scope为singleton的Bean,Spring的ioc容器中会缓存一份该bean的实例,而对于scope为prototype的Bean,每次被调用都会new一个新的对象,其生命周期就交给调用方管理了,不再是Spring容器进行管理了;
  11. 容器关闭后,如果Bean实现了DisposableBean接口,则会回调该接口的destroy()方法;
  12. 如果Bean配置了destroy-method方法,则会执行destroy-method配置的方法,至此,整个Bean的生命周期结束。

参考链接:https://www.jianshu.com/p/3944792a5fff

5 Bean的装配方式

5.1 什么是Bean的装配

  Bean的装配其实可以理解为依赖关系注入,Bean的装配方式即Bean依赖注入的方式。Spring容器支持多种形式的Bean的装配方式,有:

  • 基于XML的装配
  • 基于注解(Annotation)的装配(最常用)
  • 自动装配

5.2 装配方式

5.2.1 基于XML的装配方式

推荐使用设值注入,好用且容易理解。

5.2.1.1 设值注入

  与传统的JavaBean的写法更相似,程序开发人员更容易理解、接受。通过setter方法设定依赖关系显得更加直观、自然。对于复杂的依赖关系,如果采用构造注入,会导致构造器过于臃肿,难以阅读。Spring在创建Bean实例时,需要同时实例化其依赖的全部实例,因而导致性能下降。而使用设值注入,则能避免这些问题。尤其在某些成员变量可选的情况下,多参数的构造器更加笨重。

5.2.1.2 构造注入

  构造注入可以在构造器中决定依赖关系的注入顺序,优先依赖的优先注入。对于依赖关系无需变化的Bean,构造注入更有用处。因为没有setter方法,所有的依赖关系全部在构造器内设定,无须担心后续的代码对依赖关系产生破坏。依赖关系只能在构造器中设定,则只有组件的创建者才能改变组件的依赖关系,对组件的调用者而言,组件内部的依赖关系完全透明,更符合高内聚的原则。

5.2.2 基于注解(Annotation)的装配方式

5.2.2.1 使用方法
  • 创建接口UserDao,并定义方法:
public interface IUserDao {
	public void save();
}
  • 创建接口实现类UserDaoImpl,用@Repository声明类:
package cn.edu.ujn.annotation;

import org.springframework.stereotype.Repository;

@Repository("userDao")
public class UserDaoImpl implements IUserDao {
	@Override
	public void save() {
		System.out.println("UserDaoImpl saving........");
	}
}
  • 创建接口UserService,并定义方法:
public interface IUserService {
	public void save();
}
  • 创建接口实现类UserServiceImpl,用@Service声明类,并使用@Resource注入UserDao属性:
package cn.edu.ujn.annotation;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service("userService")
public class UserServiceImpl implements IUserService {
	public UserServiceImpl() {
		System.out.println("UserServiceImpl构造方法被调用");
	}
	@Resource(name="userDao")
	private IUserDao userDao;
	
	@Override
	public void save() {
		// TODO Auto-generated method stub
		this.userDao.save();
		System.out.println("UserServiceImpl saving......");
	}
}

  • 创建控制器类,用@Controller声明,并使用@Resource注入UserService属性:
@Controller("userController")
public class UserController{
	@Resource(name="userService")
	private UserService userService;
	public void save(){
		this.userService.save();
	}
}
  • 创建Spring配置文件,配置Bean:

除了通过<bean>元素来配置Bean外,还可以通过包扫描的形式来配置一个包下的所有Bean:
<context:component-scan base-package="cn.edu.ujn.annotation"></context:component-scan>

  • 创建测试文件,测试类

5.2.3 自动装配方式

  所谓自动装配,就是将一个Bean自动的注入到到其他Bean的Property中。Spring的<bean>元素中包含一个autowire属性,我们可以通过设置autowire的属性值来自动装配Bean。autowire属性有5个值,其值及说明下表所示:

参考文章

https://www.runoob.com/w3cnote/basic-knowledge-summary-of-spring.html


声明:
若本人发布的作品涉及版权或存在其他问题,请联系我进行删除。
谢谢浏览!
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值