IOC&DI概述
1.IOC(Inversion of Control):其思想是反转资源获取的方向.传统的资源查找方式要求组件向容器发起请求查找资源.作为回应,容器适时的返回资源.而应用了IOC之后,则是容器主动地将资源推送给它所管理的组件,组件所要做的仅是选择一种合适的方式来接受资源.这种行为也被称为查找的被动形式
2.DI(Dependency Injection)——IOC的另一种表述方式:即组件以一些预先定义好的方式(例如setter方法)接受来自如容器的资源注入.相对于IOC而言,这种表述更直接
配置bean
- 配置形式:基于XML文件的方式;基于注解的方式
- ApplicationContext主要实现类:
- ClassPathXmlApplicationContext:从类路径下加载配置文件
- FileSystemXmlApplicationContext:从文件系统中加载配置文件
- ConfigurableApplicationContext扩展于ApplicationContext,新增加两个主要方法:refresh()和close(),让ApplicatContext具有启动、刷新、和关闭上下文的能力
- ApplicationContext在初始化上下文时就实例化所有单例的Bean
- WebApplicationContext是专门为WEB应用而准备的,它允许从相对于WEB根目录的路径中完成初始化工作
- ApplicationContext主要实现类:
自动装配
- Spring IOC容器可以自动装配Bean.需要做的仅仅是在
<bean>
的autowire属性里指定自动装配的模式
- byType(根据类型自动装配):若IOC容器中有多个与目标Bean类型一致的Bean.在这种情况下,Spring将无法判定拿个Bean最合适该属性,所以不能执行自动装配(需要唯一)
- byName(根据名称自动装配):必须将目标Bean的名称和属性名设置的完全相同(需要唯一)
- constructor(通过构造器自动装配):当Bean中存在多个构造器时,此种自动装配方式将会很复杂(不推荐使用)
- 自动装配不够灵活
Bean之间的关系(继承、依赖)
- 继承:使用
<bean>
标签的parent属性
- Spring允许继承bean的配置,被继承的bean称为父bean.继承这个父Bean的Bean称为子Bean
- 子Bean从父Bean中继承配置,包括Bean的属性配置
- 子Bean也可以覆盖从父Bean继承过来的配置
- 父Bean可以作为配置模板,也可以作为Bean实例.若只想把父Bean作为模板,可以设置
<bean>
的abstract属性为true,这样Spring将不会实例化这个Bean - 并不是
<bean>
元素里的所有属性都会被继承.比如:autowire,abstract等 - 也可以忽略父Bean的class属性,让子Bean指定自己的类,而共享相同的属性配置.但此时abstract必须设为true
- 依赖:Spring允许用户通过depends-on属性设定Bean前置依赖的Bean,前置依赖的Bean会在本Bean实例化之前创建好
- 如果前置依赖于多个Bean,则可以通过逗号,空格或的方式配置Bean的名称
Bean的作用域:singleton;prototype;WEB环境作用域
- 用bean标签的scope属性设置作用域
- 默认是单例模式/singleton。(每次调用都是同一个实例,在加在配置文件时就会创建实例)
- prototype:原型。每次都会获取一个新的实例,在请求实例时才会创建实例
使用外部属性文件
- 在配置文件里配置Bean时,有时需要在Bean的配置里混入系统部署的细节信息(例如:文件路径,数据源配置信息等)。而这些部署细节实际上需要和Bean配置相分离
- Spring提供了一个PropertyPlaceholderConfigurer的BeanFactory后置处理器(即
<context:property-placeholder>
标签),这个处理器允许用户将Bean配置的部分内容外移到属性文件中。可以在Bean配置文件里使用形式为${var}的变量,并使用这些属性来替代变量 - Spring还允许在属性文件中使用${propName},以实现属性之间的相互引用
SpEL(Spring表达式语言)
- Spring表达式语言(简称SpEL):是一个支持运行时查询和操作对象图的强大的表达式语言
- 语法类似EL:SpEL使用#{…}作为定界符,所有在大括号中的字符都将被认为是SpEL
- SpEL为bean的属性进行动态赋值提供了便利
- 通过SpEL可以实现:
- 通过bean的id对bean进行引用
- 调用方法以及引用对象中的属性
- 计算表达式的值
- 正则表达式的匹配
- 字面量的表示:
- 整数:
<property name="count" value="#{5}" / >
- 小数:
<property name="frequency" value="#{89.7}" / >
- 科学计数法:
<property name="capacity" value="#{1e4}" / >
- String可以使用单引号或者双引号作为字符串的定界符号:
<property name="name" value="#{"Chuck"}" / >
或<property name='name' value='#{"Chuck"}' / >
- Boolean:
<property name="enabled" value="#{false}" / >
- 整数:
- 引用Bean、属性和方法:
- 引用其他对象
- 引用其他对象的属性
- 调用其他方法,还可以链式操作
- 调用静态方法或静态属性:通过T(className)调用一个类的静态方法,它将返回一个Class Object,然后再调用相应的方法或属性
- SpEL支持的运算符号
- 算术运算符:+、-、*、/、%、^
- 加号还可以用作字符串连接
- 比较运算符:<、>、==、<=、>=、lt、gt、eq、le、ge
- 逻辑运算符:and、or、not、|
- if-else运算符:?:(temary),?:(Elvis)
- if-else的变体
- 正则表达式:matches
Spring管理Bean的生命周期
- Spring IOC容器可以管理Bean的生命周期,Spring允许在Bean生命周期的特定点执行定制的任务
- Spring IOC容器对Bean的生命周期进行管理的过程:
- 通过构造器或工厂方法创建Bean实例
- 为Bean的属性设置值和对其他Bean的引用
- 调用Bean的初始化方法
- Bean可以使用了
- 当容器关闭时,调用Bean的销毁方法
- 在Bean的声明里设置init-method和destory-method属性,为Bean指定初始化和销毁方法
- 创建Bean后置处理器
- Bean后置处理器允许在调用初始化方法前后对Bean进行额外的处理
- Bean后置处理器对IOC容器里的所有Bean实例逐一处理,而非单一实例。其典型应用是:检查Bean属性的正确性或根据特定的标准更改Bean的属性
- 对Bean后置处理器而言,需要实现Interface BeanPostProcessor接口。在初始化方法被调用前后,Spring将把每个Bean实例分别传递给上述接口的以下两个方法:postprocessafterinitialization(Object bean, String beanName)和postprocessbeforeinitialization(Object bean, String beanName)
- 可以在以上两个方法中修改返回的Bean,甚至返回一个新的Bean
- 配置Bean的后置处理器不需要配置id,IOC容器会自动识别BeanPostProcessor
- Spring IOC容器对Bean的生命周期进行管理的过程:
- 通过构造器或工厂方法创建Bean实例
- 为Bean的属性设置值和对其他Bean的引用
- 将Bean实例传递给Bean后置处理器的和postprocessbeforeinitialization方法
- 调用Bean实例传递给Bean后置处理器的postprocessafterinitialization方法
- Bean可以使用了
- 当容器关闭时,调用了Bean的销毁方法
通过工厂方法配置Bean
- 静态工厂方法:
- 在bean的class属性里指定拥有该工厂方法的Bean
- 在factory-method属性里指定该工厂方法的名称
- 使用construtor-arg元素为工厂方法传递方法参数
- 实例工厂方法:将对象的创建过程封装到另外一个对象实例的方法里。当客户端需要请求对象时,只需要简单的调用该实例方法而不需要关心对象的创建细节
- 要声明通过实例工厂方法创建的Bean
- 在bean的factory-bean属性里指定拥有该工厂方法的Bean
- 在factory-method属性里指定该工厂方法的名称
- 使用construtor-arg元素为工厂方法传递方法参数
通过FactoryBean配置Bean
- 自定义的FactoryBean需要实现FactoryBean接口
- 配置文件中通过FactoryBean来配置Bean的实例,class指向FactoryBean的属性,但实际返回的实例却是FactoryBean的getObject()方法返回的实例
通过注解配置Bean
- 组件扫描(component scanning):Spring能够从classpath下自动扫描,侦测和实例化具有特定注解的组件
- 当在组件类上使用了特定的注解之后,还需要在Spring的配置文件中声明
<context:component-scan>
- base-package属性指定一个需要扫描的基类包,Spring容器将会扫描这个基类包里及其子包中的所有类
- 当需要扫描多个包时,可以使用逗号分隔
- 如果仅希望扫描特定的类而非基包下的所有类,可使用resource-pattern属性指定特定的类,实例:
<context:component-scan base-package="com.beans" resource-pattern="autowire/*.class">
<context:include-filter>
子节点表示要包含的目标类,使用这个节点时需要将use-default-filters属性设置为false<context:exclude-filter>
子节点表示要排除在外的目标类<context:component-scan>
下可以拥有若干个<context:include-filter>
和<context:exclude-filter>
子节点
<context:include-filter>
和<context:exclude-filter>
子节点支持多种类型的过滤表达式:
- 当在组件类上使用了特定的注解之后,还需要在Spring的配置文件中声明
类别 | 示例 | 说明 |
---|---|---|
annotation | com.XxxAnnotation | 所有标注了XxxAnnotation的类,该类型采用目标类是否标注了某个注解进行过滤 |
assignable | com.XxxService | 所有继承或扩展XxxService的类,该类型采用目标类是否继承或扩展某个特定类进行过滤 |
aspectj | com.*Service+ | 所有类名以Service结束的类及继承或扩展它们的类。该类型采用AspejctJ表达式进行过滤 |
regex | com.\anno.* | 所有com.anno包下的类,该类型采用正则表达式根据类的类名进行过滤 |
custom | com.XxxTypeFilter | 采用XxxTypeFilter通过代码的方式定义过滤规则。该类必须实现org.springframework.core.type.TypeFilter接口 |
2. 特定组件包括:
1. @Component:基本注解,标识了一个受Spring管理的组件
2. @Respository:标识持久层组件
3. @Service:标识服务层(业务层)组件
4. @Controller:标识表现层组件
3. 对于扫描到的组件,Spring有默认的命名策略:使用非限定类名,第一个字母小写.也可以在注解中通过value属性值标识组件的名称
4. 组件装配:<context:component-scan>
元素还会自动注册AutowiredAnnotationBeanPostProcessor实例,该实例可以自动装配具有@Autowired和@Resource、@Inject注解的属性
1. @Autowired注解自动装配具有兼容类型的单个Bean属性
1. 构造器、普通字段(即使是非public),一切具有参数的方法都可以应用@Autowired注解
2. 默认情况下,所有使用@Autowired注解的属性都需要被设置,当Spring找不到匹配的Bean装配属性时,会抛出异常,若一属性允许不被设置,可以设置@Autowired注解的required属性为false
3. 默认情况下,当IOC容器里存在多个类型兼容的Bean时,通过类型的自动装配将无法工作.此时可以在@Qualifler注解里提供Bean的名称.Spring允许对方法的入参标注@Qualifiter已指定注入Bean的名称
4. @Autowired注解也可以应用在数组类型的属性上,此时Spring将会把所有匹配的Bean进行自动装配
5. @Autowired注解也可以应用在集合属性上,此时Spring读取该集合的类型信息,然后自动装配所有与之兼容的Bean.
6. @Autowired注解在java.util.Map上时,若该Map的键值为String,那么Spring将自动装配与之Map值类型兼容的Bean,此时Bean的名称作为键值
2. 使用@Resource或@Inject自动装配Bean
1. Spring还支持@Resource和@Inject注解,这两个注解和@Autowired注解的功能类似
2. @Resource注解要求提供一个Bean名称的属性,若该属性为空,则自动采用标注处的变量或方法名作为Bean的名称
3. @Inject和@Autowired注解一样也是按类型匹配注入的Bean,但没有reqired属性
4. 建议使用@Autowired注解
泛型依赖注入
Spring 4.x中可以为子类注入子类对应的泛型类型的成员变量的引用