Spring学习笔记-IOC原理及配置
Bean定义模式
在Spring的IOC实现中,对于Bean的定义有三种模式:
| 模式 | 应用类型 | IOC容器启动方式 |
|---|---|---|
| 纯XML | JavaSE | ApplicationContext context = new ClassPathXMLApplicationContext("Beans.xml") 或者 new FileSystemXmlApplicationContext("/root/Bean.xml") |
| JavaWeb | ContextLoaderListener监听器去加载XML | |
| XML+注解 | JavaSE | ApplicationContext context = new ClassPathXMLApplicationContext("Beans.xml") 或者 new FileSystemXmlApplicationContext("/root/Bean.xml") |
| JavaWeb | ContextLoaderListener监听器去加载XML | |
| 纯注解 | JavaSE | ApplicationContext context = new AnnotationContextApplicationContext(Config.class) |
| JavaWeb | ContextLoaderListener监听器去加载注解配置类 |
BeanFactory与ApplicationContext
BeanFactory是Spring框架中IoC容器的顶层接⼝,它只是⽤来定义⼀些基础功能,定义⼀些基础规范。
ApplicationContext是它的⼀个⼦接⼝,所以ApplicationContext是具备BeanFactory提供的全部功能的。
通常,我们称BeanFactory为SpringIOC的基础容器,ApplicationContext是容器的⾼级接⼝,⽐BeanFactory要拥有更多的功能,⽐如说国际化⽀持和资源访问(xml,java配置类)等等。

纯XML方式
虽然文件名是可以自定义,但是一般都命名为applicationContext.xml。实现Bean的三种方式:
- 使⽤⽆参构造函数
在默认情况下,它会通过反射调⽤⽆参构造函数来创建对象。如果类中没有⽆参构造函数,将创建失败。1
2<!--配置service对象-->
<bean id="userService" class="com.demo.service.impl.UserServiceImpl"></bean> - 使⽤静态⽅法创建
这种方法多用于将自定义的类加入到IOC容器。
在实际开发中,使⽤的对象有些时候并不是直接通过构造函数就可以创建出来的,它可能在创建的过程中会做很多额外的操作(比如初始化数据库连接要注册驱动,还要提供URL和凭证信息)。此时会提供⼀个创建对象的static修饰的⽅法,即是此种情况;1
2<!--使⽤静态⽅法创建对象的配置⽅式-->
<bean id="demoService" class="com.demo.factory.BeanFactory" factory-method="getDemoService"></bean> - 使⽤实例化⽅法创建
此种⽅式和上⾯静态⽅法创建其实类似,区别是⽤于获取对象的⽅法不再是static修饰的了,⽽是类中的⼀个普通⽅法。此种⽅式⽐静态⽅法创建的使⽤⼏率要⾼⼀些。1
2
3<!--使⽤实例⽅法创建对象的配置⽅式-->
<bean id="beanFactory" class="com.demo.factory.BeanFactory"></bean>
<bean id="demoService" factory-bean="beanFactory" factorymethod="getDemoService"></bean>
Bean的作用范围
具体可以参考官网文档地
| scope | 描述 |
|---|---|
| singleton | 默认值,单例模式,Bean在IOC容器中只有一份 |
| prototype | 原型,每次使用该类的对象,都返回一个新的对象 |
| request | 一个请求对应一个对象 |
| session | 一个会话对应一个对象 |
| application | 一个ServletContext对应一个对象 |
| websocket | 一个WebSocket对应一个对象 |
多例/原型模式的bean对象,spring框架只负责创建,不负责销毁。
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时起作⽤。
依赖注入
按照注⼊的⽅式分类
- 构造函数注⼊:顾名思义,就是利⽤带参构造函数实现对类成员的数据赋值。
它的使⽤要求是,类中提供的构造函数参数个数必须和配置的参数个数⼀致,且数据类型匹配。同时需要注意的是,当没有⽆参构造时,则必须提供构造函数参数的注⼊,否则Spring框架会报错。
在使⽤构造函数注⼊时,涉及的标签是constructor-arg,该标签有如下属性:- name:⽤于给构造函数中指定名称的参数赋值。
- index:⽤于给构造函数中指定索引位置的参数赋值。
- value:⽤于指定基本类型或者String类型的数据。
- ref:⽤于指定其他Bean类型的数据。写的是
其他bean的唯⼀标识。
- set⽅法注⼊:它是通过类成员的set⽅法实现数据的注⼊。(使⽤最多的)
在使⽤set⽅法注⼊时,需要使⽤property标签,该标签属性如下:- name:指定注⼊时调⽤的set⽅法名称。
(注:不包含set这三个字⺟) - value:指定注⼊的数据。它⽀持基本类型和String类型。
- ref:指定注⼊的数据。它⽀持其他bean类型。写的是其他bean的唯⼀标识。
- name:指定注⼊时调⽤的set⽅法名称。
按照注⼊的数据类型分类
- 基本类型和String
注⼊的数据类型是基本类型或者是字符串类型的数据。 - 其他Bean类型
注⼊的数据类型是对象类型,称为其他Bean的原因是,这个对象是要求出现在IoC容器中的。那么针对当前Bean来说,就是其他Bean了。 - 复杂类型(集合类型)
注⼊的数据类型是Aarry,List,Set,Map,Properties中的⼀种类型。
XML+注解方式
xml+注解结合模式,xml⽂件依然存在,所以,spring IOC容器的启动仍然从加载xml开始。
一般是第三⽅jar中的bean定义在xml,⾃⼰开发的bean定义使⽤注解。
xml中标签与注解的对应:
| xml标签或属性 | 对应的注解形式 |
|---|---|
| 标签 | @Component(“accountDao”),注解加在类上, bean的id属性内容直接配置在注解后⾯ 如果不配置,默认定义个这个bean的id为类的类名⾸字⺟⼩写; 另外,针对分层代码开发提供了@Componenet的三种别名 @Controller、@Service、@Repository分别⽤于控制层类、服务层类、dao层类的bean定义, 这四个注解的⽤法完全⼀样,只是为了更清晰的区分⽽已 |
| scope属性 | @Scope(“prototype”),默认单例,注解加在类上 |
| init-method属性 | @PostConstruct,注解加在⽅法上,该⽅法就是初始化后调⽤的⽅法 |
| destroy-method属性 | @PreDestroy,注解加在⽅法上,该⽅法就是销毁前调⽤的⽅法 |
DI 依赖注⼊的注解:
| 注解 | 要求 |
|---|---|
| @Autowired | 推荐使用,采取的策略为按照类型注⼊,是Spring提供的注解,需要导⼊包org.springframework.beans.factory.annotation.Autowired |
| @Qualifier | 当有多个bean值的时候,根据此注解决定要使用那个 |
| @Resource | 默认按照ByName⾃动注⼊,由J2EE提供,需要导⼊包javax.annotation.Resource,在Jdk11中已经移除,如果要使⽤,需要单独引⼊jar包 |
注意,对于@Resource注解:
- 如果同时指定了 name 和 type,则从Spring上下⽂中找到唯⼀匹配的bean进⾏装配,找不到则抛出异常。
- 如果指定了 name,则从上下⽂中查找名称(id)匹配的bean进⾏装配,找不到则抛出异常。
- 如果指定了 type,则从上下⽂中找到类似匹配的唯⼀bean进⾏装配,找不到或是找到多个,都会抛出异常。
- 如果既没有指定name,⼜没有指定type,则⾃动按照byName⽅式进⾏装配;
纯注解方式
@Configuration: 表明当前类是⼀个配置类;@ComponentScan: 替代 context:component-scan;@PropertySource: 引⼊外部属性配置⽂件@Import: 引⼊其他配置类@Value: 对变量赋值,可以直接赋值,也可以使⽤${}读取资源配置⽂件中的信息@Bean: 将⽅法返回对象加⼊ SpringIOC 容器
延迟加载
ApplicationContext容器的默认⾏为是在启动服务器时将所有singleton bean提前进⾏实例化。即启动时创建并配置所有的singleton bean。
延迟加载对应的属性值为lazy-init,默认为false,例如:
1 | <bean id="testBean" class="cn.demo.LazyBean" /> |
lazy-init="false",为⽴即加载,表示在spring启动时,⽴刻进⾏实例化。
设置lazy-init为true的 bean,将不会在ApplicationContext启动时提前被实例化,⽽是第⼀次向容器通过getBean索取bean时实例化的。
如果⼀个设置了lazy-init为true(⽴即加载)的 beanA,引⽤了⼀个lazy-init为false(延迟加载)的beanB,那么beanA在容器启动时被实例化,⽽beanB由于被beanA引⽤,所以也被实例化。
如果⼀个bean的scope属性为scope="pototype"时,即使设置了lazy-init="false",容器启动时也不会实例化bean,⽽是调⽤getBean⽅法实例化的。
BeanFactory与FactoryBean
BeanFactory接⼝是容器的顶级接⼝,定义了容器的⼀些基础⾏为,负责⽣产和管理Bean的⼀个⼯⼚,具体使⽤它下⾯的⼦接⼝类型,⽐如ApplicationContext;
BeanFactory源码如下:
1 | public interface BeanFactory { |
Spring中Bean有两种,⼀种是普通Bean,⼀种是⼯⼚Bean(FactoryBean)。
FactoryBean可以⽣成某⼀个类型的Bean实例(返回给我们),也就是说我们可以借助于它⾃定义Bean的创建过程。
FactoryBean源码如下:
1 | // 可以让我们⾃定义Bean的创建过程(完成复杂Bean的定义) |
最终通过FactoryBean获取到的是具体的Bean,如果想要获取FactoryBean,只需要在获取时加”&”。
后置处理
Spring提供了两种后处理bean的扩展接⼝,分别为BeanPostProcessor和BeanFactoryPostProcessor,两者在使⽤上是有所区别的。
- BeanFactoryPostProcessor: 在BeanFactory初始化之后可以使⽤BeanFactoryPostProcessor进⾏后置处理做⼀些事情;
- BeanPostProcessor: 在Bean对象实例化(并不是Bean的整个⽣命周期完成)之后可以使⽤BeanPostProcessor进⾏后置处理做⼀些事情;




