Spring系列.Bean简介
Bean属性配置
Spring
在读取配置文件中bean的metadata后会构造一个个BeanDefination对象。后面Spring会根据这些BeanDefinition创建对象。在配置一个bean的时候我们可以配置下面这些元素:
元素 | 备注 |
---|---|
class | 设定类的全限定名 |
name | 设置Bean的名称,可以设置多个用逗号分隔 |
id/name | Bean的唯一标识符,全局只能有一个 |
scope | 设置Bean是单例还是原型,默认单例 |
constructor arguments | 构造方法入参,进行依赖注入 |
properties | 进行依赖注入 |
autowiring mode | 自动注入模式 |
lazy-initialization mode | 只对scope为单列的bean生效,设置为true会在getBean()时才创建bean实例 |
initialization method | 设定Bean的初始化方法 |
destruction method | 设定Bean的销毁方法 |
除了通过配置信息来创建Bean,Spring还允许通过接口的方式创建用户在容器外部创建的对象。(通过DefaultListableBeanFactory类的registerSingleton方法和registerBeanDefinition方法)
In addition to bean definitions that contain information on how to create a specific bean, the
ApplicationContext
implementations also permit the registration of existing objects that are created outside the container (by users). This is done by accessing the ApplicationContext’s BeanFactory through thegetBeanFactory()
method, which returns the BeanFactoryDefaultListableBeanFactory
implementation.DefaultListableBeanFactory
supports this registration through theregisterSingleton(..)
andregisterBeanDefinition(..)
methods. However, typical applications work solely with beans defined through regular bean definition metadata.
虽然Spring容器还提供了registerSingleton(..)方法和registerBeanDefinition(..)来注册单例Bean,但是不建议自己使用这个方法,因为我们可能在依赖注入之后再注册了这个Bean。推荐使用配置BeanDefinition的方式来配置Bean。(其实这两个方法更多是Spring框架自己使用,在配置文件以外的一些地方再注册一些Bean到容器中)
关于上面表格中的id属性和name属性这边多说一句。
id和name属性都可以用来当做一个bean的标识符,他们两个的区别是id只能给这个bean指定一个标识符,而name属性可以同时给这个bean指定多个标识符(多个标识符之间用,隔开)。下面给出一个配置的列子
<!--经过下面的配置,bean1,bean2、name1、name2、alias1、alias2、alias3其实是一个Bean-->
<bean id="bean1,bean2" name="name1,name2" class="com.csx.demo.springdemo.service.MyBean1">
</bean>
<alias name="bean1,bean2" alias="alias1"/>
<alias name="name1" alias="alias2"/>
<alias name="name2" alias="alias3"/>
Bean命名
如果没有给Bean指定一个标识符,Spring容器会默认给这个Bean设置一个标识符。用户可以通过id和name两个属性来设置Bean的标识符,这些标识符需要在整个容器范围内唯一,同时name可以指定多个用逗号分隔。
实例化Bean
实例化Bean一般有四种方式:默认构造函数、待参数的构造函数、静态工厂类、实例方法创建Bean。需要我们注意的是Bean的实例化和依赖注入的区别。
- 默认构造函数方式
<bean id="exampleBean" class="examples.ExampleBean"/>
- 带参数的构造函数
<bean id="Hello2" class="com.csx.personal.web.services.HelloImpl2">
<constructor-arg index="0" value="chensongxia"/>
<constructor-arg index="1" value="zhaoru"/>
<constructor-arg index="2" ref="beanid"/>
</bean>
- 使用静态工厂类(不推荐使用)
<bean id="bean3" class="cn.javass.spring.chapter2.HelloApiStaticFactory" factory-method="newInstance">
<constructor-arg index="0" value="Hello Spring!"/>
</bean>
<!-- 使用examples.ClientService这个类的createInstance方法创建bean -->
<bean id="clientService" class="examples.ClientService" factory-method="createInstance"/>
public class ClientService {
private static ClientService clientService = new ClientService();
private ClientService() {}
public static ClientService createInstance() {
return clientService;
}
}
- 使用实例方法进行Bean创建
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
<!-- inject any dependencies required by this locator bean -->
</bean>
<!-- 使用serviceLocator这个Bean的createClientServiceInstance方法创建Bean -->
<bean id="clientService" factory-bean="serviceLocator" factory-method="createClientServiceInstance"/>
<bean id="accountService" factory-bean="serviceLocator" factory-method="createAccountServiceInstance"/>
//类定义
public class DefaultServiceLocator {
private static ClientService clientService = new ClientServiceImpl();
private static AccountService accountService = new AccountServiceImpl();
public ClientService createClientServiceInstance() {
return clientService;
}
public AccountService createAccountServiceInstance() {
return accountService;
}
}
如果我们要通过xml的形式配置一个静态内部类,可以参考下面的例子
For example, if you have a class called SomeThing in the com.example package, and this SomeThing class has a static nested class called OtherThing, the value of the class attribute on a bean definition would be com.example.SomeThing$OtherThing.
Bean的Scope
Spring默认支持的Scope
Scopes | 描述 |
---|---|
singleton | 整个IOC容器中只有一个Bean |
prototype | 每次请求都会生成新的Bean |
request | 每个HTTP request都会生成一个新的Bean,只对web系列的ApplicationContext生效 |
session | 每个session范围内生成一个新的Bean,只对web系列的ApplicationContext生效 |
Application | ServletContext范围内生成一个新的Bean,只对web系列的ApplicationContext生效 |
websocket | -- |
singleton类型的bean定义,在一个容器中只存在一个实例,所有对该类型bean的依赖都引用这一单一实例。
scope为prototype的bean,容器在接受到该类型的对象的请求的时候(调用getBean方法),会每次都重新 生成一个新的对象给请求方,虽然这种类型的对象的实例化以及属性设置等工作都是由容器负责的,但是只要准备完毕,并且对象实例返回给请求方之后,容器就不 在拥有当前对象的引用,请求方需要自己负责当前对象后继生命周期的管理工作,包括该对象的销毁。也就是说,容器每次返回请求方该对象的一个新的实例之后, 就由这个对象“自生自灭”了。
单例Bean依赖原型Bean
当一个单例的Bean依赖一个原型Bean时,由于单例只初始化一次,所以拿到的原型Bean也只是我们第一次初始化时拿到的Bean,并不能达到我们想要的效果。此时我们可以使用Spring提供的look-up方式的注入来解决这个问题。
Request, Session, Application, and WebSocket Scopes
这三种Scope只对Web系列的ApplicationContext的生效。可以视同@RequestScope、@SessionScope和@ApplicationScope使之生效。
自定义Scope
Spring还支持自定义scope,需要时可以学些下这个特性。
Bean的扩展点(注意和容器扩展点的区别)
Spring提供了一系列接口让用户来自定义Bean的属性(注意和容器扩展点那一个章节的区别),主要的接口有:
- Lifecycle Callbacks;
- ApplicationContextAware and BeanNameAware;
- Other Aware Interfaces;
生命周期回调
所谓生命周期交互就是指在容器创建Bean和销毁Bean之前做某些操作。在Spring中我们可以通过让Bean实现InitializingBean和DisposableBean接口,使用@PostConstruct和@PreDestroy以及通过如下的配置实现。
<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
<bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="cleanup"/>
如果我们给一个Bean同时配置了上面多种的初始化和销毁机制,那么他们的执行顺序如下:
初始化顺序
- Methods annotated with @PostConstruct (这个方法在构造函数之后执行,是最佳实践,可以和Spring API解耦)
- afterPropertiesSet() as defined by the InitializingBean callback interface(不建议使用,会耦合Spring API)
- A custom configured init() method(普通的xml配置文件中配置的初始化方法)
析构顺序 - Methods annotated with @PreDestroy(建议使用)
- destroy() as defined by the DisposableBean callback interface (不建议使用)
- A custom configured destroy() method (普通的xml文件中配置的销毁方法)
Spring完整的初始化顺序
- 容器启动,实例化所有实现了BeanFactoyPostProcessor接口的类;这步会在任何普通Bean实例化之前加载;
- 实例化剩下的单例Bean,对这些Bean进行依赖注入;
- 如果Bean有实现BeanNameAware的接口那么对这些Bean进行调用;
- 如果Bean有实现BeanFactoryAware接口的那么对这些Bean进行调用;
- 如果Bean有实现ApplicationContextAware接口的那么对这些Bean进行调用;
- 如果配置有实现BeanPostProcessor的Bean,那么调用它的postProcessBeforeInitialization方法;
- 调用@PostConstruct注解的方法;
- 如果Bean有实现InitializingBean接口那么对这些Bean进行调用;
- 如果Bean配置有init属性,那么调用它属性中设置的方法;
- 如果配置有实现BeanPostProcessor的Bean,那么调用它的postProcessAfterInitialization方法;
- Bean正常的使用;
- 调用@PreDestroy标注的方法;
- 调用DisposableBean接口的destory方法;
- 调用Bean定义是指定的destroy-method方法;
LifeCycle和SmartLifeCycle接口
Spring提供了LifeCycle接口,实现了这个接口的Bean在Spring容器调用start()和stop()方法的时候能收到Spring的回调信息,分别调用这个Bean的start()和stop()方法。
Aware接口
Spring提供了很多aware接口让Bean来实现,提示IOC容器,这个Bean需要得到容器的某些组件或元素。
- ApplicationContextAware
- ApplicationEventPublisherAEwvaenrte
- BeanClassLoaderAware
- BeanFactoryAware
- BeanNameAware
- BootstrapContextAware:Typically available only in JCA aware ApplicationContext instances.
- LoadTimeWeaverAware
- MessageSourceAware
- NotificationPublisherAwareSpring:Spring JMX notification publisher.
- ResourceLoaderAware
- ServletConfigAware
- ServletContextAware
Spring系列.Bean简介的更多相关文章
- Spring 系列: Spring 框架简介 -7个部分
Spring 系列: Spring 框架简介 Spring AOP 和 IOC 容器入门 在这由三部分组成的介绍 Spring 框架的系列文章的第一期中,将开始学习如何用 Spring 技术构建轻量级 ...
- Spring 系列: Spring 框架简介(转载)
Spring 系列: Spring 框架简介 http://www.ibm.com/developerworks/cn/java/wa-spring1/ Spring AOP 和 IOC 容器入门 在 ...
- Spring系列__02IOC模块简介
Spring的两大核心功能就是IOC和AOP,这篇文章主要介绍IOC. 简单来说,在面向对象思想下,A类中有一个B类的属性, 那么我们在创建A类时往往需要同时创建一个B类的对象,以便A类对其进行调用. ...
- Spring 系列教程之 bean 的加载
Spring 系列教程之 bean 的加载 经过前面的分析,我们终于结束了对 XML 配置文件的解析,接下来将会面临更大的挑战,就是对 bean 加载的探索.bean 加载的功能实现远比 bean 的 ...
- 深入理解Spring系列之六:bean初始化
转载 https://mp.weixin.qq.com/s/SmtqoELzBEdZLo8wsSvUdQ <深入理解Spring系列之四:BeanDefinition装载前奏曲>中提到,对 ...
- Spring核心技术(一)——IoC容器和Bean简介
IoC容器和Bean简介 这章包括了Spring框架对于IoC规则的实现.Ioc也同DI(依赖注入).而对象是通过构造函数,工厂方法,或者一些Set方法来定义对象之间的依赖的.容器在创建这些Bean对 ...
- [JavaEE] IBM - Spring 系列: Spring 框架简介
Spring AOP 和 IOC 容器入门 在这由三部分组成的介绍 Spring 框架的系列文章的第一期中,将开始学习如何用 Spring 技术构建轻量级的.强壮的 J2EE 应用程序.develop ...
- Spring源码系列 — Bean生命周期
前言 上篇文章中介绍了Spring容器的扩展点,这个是在Bean的创建过程之前执行的逻辑.承接扩展点之后,就是Spring容器的另一个核心:Bean的生命周期过程.这个生命周期过程大致经历了一下的几个 ...
- java Spring系列之 配置文件的操作 +Bean的生命周期+不同数据类型的注入简析+注入的原理详解+配置文件中不同标签体的使用方式
Spring系列之 配置文件的操作 写在文章前面: 本文带大家掌握Spring配置文件的基础操作以及带领大家理清依赖注入的概念,本文涉及内容广泛,如果各位读者耐心看完,应该会对自身有一个提升 Spri ...
随机推荐
- elasticsearch中保存时间格式
利用logstash从文档中导入数据到es中,若未事先设定数据格式,有可能存储时间并未保存为date格式而是text格式. 时间若保存为text,则在会以字符串数组格式存储在es中,是乱序,不好查询. ...
- Java实现 LeetCode 63 不同路径 II(二)
63. 不同路径 II 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为"Start" ). 机器人每次只能向下或者向右移动一步.机器人试图达到网格的右下角(在 ...
- 从linux源码看socket的阻塞和非阻塞
从linux源码看socket的阻塞和非阻塞 笔者一直觉得如果能知道从应用到框架再到操作系统的每一处代码,是一件Exciting的事情. 大部分高性能网络框架采用的是非阻塞模式.笔者这次就从linux ...
- Linux 文件特殊权限-SetUID
SetUID非常类似于Windows中以管理员身份来运行文件,针对的是可执行文件,而且命令执行者要拥有对这个文件的执行权限,只在文件执行的过程中变换身份,最常见的passwd命令就具有SetUID权限 ...
- PAT 旧键盘打字
旧键盘上坏了几个键,于是在敲一段文字的时候,对应的字符就不会出现.现在给出应该输入的一段文字.以及坏掉的那些键,打出的结果文字会是怎样? 输入格式: 输入在 2 行中分别给出坏掉的那些键.以及应该输入 ...
- Centos7快速安装RocketMQ
1. 为什么要用MQ 消息队列是一种"先进先出"的数据结构 其应用场景主要包含以下3个方面 应用解耦 系统的耦合性越高,容错性就越低.以电商应用为例,用户创建订单后,如果耦合调用库 ...
- ELK的踩坑之旅
前言 设计思路如下 有3台机器 2台做elasticsearch的主副节点 1台做kibana和elasticsearch_head 由于机器匮乏我还在这台机器上部署了logstash和nginx服务 ...
- 区分http请求状态码来理解缓存(协商缓存和强制缓存)
什么是http缓存呢,当我们使用chrome浏览器,按F12打开控制台,在网络请求中有时候看到状态码是200,有时候状态码是304,当我们去看这种请求的时候,我们会发现状态码为304的状态结果是:St ...
- C#9.0 终于来了,您还学的动吗? 带上VS一起解读吧!(应该是全网第一篇)
一:背景 1. 讲故事 好消息,.NET 5.0 终于在2020年6月10日发布了第五个预览版,眼尖的同学一定看到了在这个版本中终于支持了 C# 9.0,此处有掌声,太好了!!! .Net5官方链接 ...
- SpringBoot与(Security)安全
1.简介 应用程序的两个主要区域 认证(Authentication): 是建立一个它声明的主体的过程(一个"主体" 一般是指用户,设备或一些可以在你的应用程序中执行动作的其他系统 ...