目录
一、Bean的配置
1.自动装配
(1)简介
(2)缺点
2.继承Bean
3.依赖Bean配置
4.Bean的作用域
5.使用外部属性文件
6.注册PropertyPlaceholderConfigurer
7.通过工厂方法配置Bean
(1)静态工厂
(2)实例工厂
8.通过FactoryBean配置Bean
9.基于注解配置Bean
10.组件装配
11.泛型依赖注入
二、spEL表达式
1.字面量
2.引用Bean、属性和方法
3.运算符
三、IOC中 Bean 的生命周期方法
1.创建Bean后置处理器
2.添加后置处理器后 Bean 的生命周期
一、Bean的配置
1.自动装配
(1)简介
- Spring IOC 容器可以自动装配 Bean. 需要做的仅仅是在 <bean> 的 autowire
- byType(根据类型自动装配): 若 IOC 容器中有多个与目标 Bean 类型一致的 Bean. 在这种情况下, Spring 将无法判定哪个 Bean 最合适该属性, 所以不能执行自动装配
- byName(根据名称自动装配): 必须将目标 Bean 的名称和属性名设置的完全相同
- constructor(通过构造器自动装配): 当 Bean 中存在多个构造器时, 此种自动装配方式将会很复杂. 不推荐使用
(2)缺点
- 在 Bean 配置文件里设置 autowire 属性进行自动装配将会装配 Bean 的所有属性. 然而, 若只希望装配个别属性时, autowire 属性就不够灵活了
- autowire 属性要么根据类型自动装配, 要么根据名称自动装配, 不能两者兼而有之
- 一般情况下,在实际的项目中很少使用自动装配功能,因为和自动装配功能所带来的好处比起来,明确清晰的配置文档更有说服力一些
2.继承Bean
- 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
<!-- 抽象Bean,abstract的属性为true,这样的Bean不能被IOC容器实例化,只能用来被继承配置
若某一个bean的class属性没有指定,则该bean必然是一个抽象bean
-->
<bean id="street1" class="com.itheima.spring.Address"
p:city="beijing" p:street="xierqi" abstract="true"></bean>
<!-- 使用bean的parent属性指定要继承那个bean的配置 -->
<bean id="street2" class="com.itheima.spring.Address" parent="street1"></bean>
3.依赖Bean配置
- Spring 允许用户通过 depends-on
- Bean 前置依赖的Bean会在本 Bean 实例化之前创建好
- 如果前置依赖于多个 Bean,则可以通过逗号,空格或的方式配置 Bean 的名称
<!--如果依赖的street2无法实例化,则会报异常 -->
<bean id="street3" class="com.itheima.spring.Address" parent="street1" depends-on="street2"></bean>
4.Bean的作用域
- 在 Spring 中, 可以在 <bean> 元素的 scope
- 默认情况下, Spring 只为每个在 IOC 容器里声明的 Bean 创建唯一一个实例, 整个 IOC 容器范围内都能共享该实例:所有后续的 getBean() 调用和 Bean 引用都将返回这个唯一的 Bean 实例.该作用域被称为 singleton, 它是所有 Bean 的默认作用域
5.使用外部属性文件
- 在配置文件里配置 Bean 时, 有时需要在 Bean 的配置里混入系统部署的细节信息(例如: 文件路径, 数据源配置信息等). 而这些部署细节实际上需要和 Bean 配置相分离
- Spring 提供了一个 PropertyPlaceholderConfigurer 的 BeanFactory 后置处理器, 这个处理器允许用户将 Bean 配置的部分内容外移到属性文件中. 可以在 Bean 配置文件里使用形式为 ${var} 的变量, PropertyPlaceholderConfigurer 从属性文件里加载属性, 并使用这些属性来替换变量
- Spring 还允许在属性文件中使用 ${propName},以实现属性之间的相互引用
6.注册PropertyPlaceholderConfigurer
- Spring 2.5 之后: 可通过 context:property-placeholder 元素简化:
- <beans> 中添加 context Schema 定义
- 在配置文件中加入如下配置(以下为C3P0连接池配置的示范)
<!-- 引入数据库的配置文件 -->
<context:property-placeholder location="classpath:dbconfig.properties" />
<!-- Spring用来控制业务逻辑。数据源、事务控制、aop -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?allowMultiQueries=true
jdbc.username=root
jdbc.password=123456
7.通过工厂方法配置Bean
(1)静态工厂
/*
静态工厂方法:直接调用类的静态方法返回Bean的实例
*/
public class StaticStuFactory {
private static Map<String, Student> stus = new HashMap<>();
static {
stus.put("001", new Student("jack", 18));
stus.put("002", new Student("rose", 20));
}
public static Student getStus(String id) {
return stus.get(id);
}
}
<!--通过静态工厂方法来配置Bean,注意不是配置静态工厂方法实例,而是配置bean实例 -->
<!--
class:指向静态方法的全类名
factory-method:指向静态工厂方法的名字
constructor-arg:如果工厂方法需要传入参数,则必须使用此标签配置参数
-->
<bean id="stu" class="com.itheima.spring.beans.StaticStuFactory" factory-method="getStus">
<constructor-arg value="001"></constructor-arg>
</bean>
(2)实例工厂
public class InstanceStuFactory {
private Map<String, Student> stus = null;
public InstanceStuFactory() {
stus=new HashMap<>();
stus.put("001", new Student("tom", 15));
stus.put("002", new Student("marry", 16));
}
public Student getStudent(String id) {
return stus.get(id);
}
}
<!-- 配置工厂的实例-->
<bean id="stuFactory" class="com.itheima.spring.beans.InstanceStuFactory"></bean>
<!-- 通过实例工厂来配置bean -->
<bean id="stu2" factory-bean="stuFactory" factory-method="getStudent" >
<constructor-arg value="001"></constructor-arg>
</bean>
8.通过FactoryBean配置Bean
public class StuFactoryBean implements FactoryBean<Student> {
private String name;
private int age;
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
@Override
public Student getObject() throws Exception {
return new Student(name, age);
}
@Override
public Class<?> getObjectType() {
return Student.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
<!--
通过FactoryBean来配置Bean的实例
class:指向FactoryBean的全类名
property:配置FactoryBean的属性
-->
<bean id="stu3" class="com.itheima.spring.beans.StuFactoryBean">
<property name="name" value="allen"></property>
<property name="age" value="25"></property>
</bean>
9.基于注解配置Bean
- 组件扫描(component scanning): Spring 能够从 classpath 下自动扫描, 侦测和实例化具有特定注解的组件
- 特定组件包括:
- @Component: 基本注解, 标识了一个受 Spring 管理的组件
- @Respository: 标识持久层组件
- @Service: 标识服务层(业务层)组件
- @Controller: 标识表现层组件
- 对于扫描到的组件, Spring 有默认的命名策略: 使用非限定类名, 第一个字母小写. 也可以在注解中通过 value 属性值标识组件的名称
- 当在组件类上使用了特定的注解之后, 还需要在 Spring 的配置文件中声明 <context:component-scan>
- base-package 属性指定一个需要扫描的基类包,Spring 容器将会扫描这个基类包里及其子包中的所有类
- 当需要扫描多个包时, 可以使用逗号分隔
- 如果仅希望扫描特定的类而非基包下的所有类,可使用 resource-pattern 属性过滤特定的类
- context:include-filter 子节点表示要包含的目标类
- context:exclude-filter 子节点表示要排除在外的目标类
- context:component-scan 下可以拥有若干个 context:include-filter 和 context:exclude-filter 子节点
- context:include-filter 和 context:exclude-filter 子节点支持多种类型的过滤表达式
<context:component-scan base-package="com.itheima.spring.annotation.generic"></context:component-scan>
10.组件装配
- context:component-scan 元素还会自动注册 AutowiredAnnotationBeanPostProcessor 实例, 该实例可以自动装配具有 @Autowired 和 @Resource 、@Inject注解的属性
- @Autowired 注解自动装配具有兼容类型的单个 Bean属性
- 构造器, 普通字段(即使是非 public), 一切具有参数的方法都可以应用@Autowired 注解
- 默认情况下, 所有使用 @Autowired 注解的属性都需要被设置. 当 Spring 找不到匹配的 Bean 装配属性时, 会抛出异常, 若某一属性允许不被设置, 可以设置 @Autowired 注解的 required 属性为 false
- 默认情况下, 当 IOC 容器里存在多个类型兼容的 Bean 时, 通过类型的自动装配将无法工作. 此时可以在 @Qualifier 注解里提供 Bean 的名称. Spring 允许对方法的入参标注 @Qualifiter 已指定注入 Bean 的名称
- @Autowired 注解也可以应用在数组类型的属性上, 此时 Spring 将会把所有匹配的 Bean 进行自动装配
- @Autowired 注解也可以应用在集合属性上, 此时 Spring 读取该集合的类型信息, 然后自动装配所有与之兼容的 Bean
- @Autowired 注解用在 java.util.Map 上时, 若该 Map 的键值为 String, 那么 Spring 将自动装配与之 Map 值类型兼容的 Bean, 此时 Bean 的名称作为键值
- Spring 还支持 @Resource 和 @Inject 注解,这两个注解和 @Autowired 注解的功用类似
- @Resource 注解要求提供一个 Bean 名称的属性,若该属性为空,则自动采用标注处的变量或方法名作为 Bean 的名称
- @Inject 和 @Autowired 注解一样也是按类型匹配注入的 Bean, 但没有 reqired 属性
- 建议使用 @Autowired 注解
11.泛型依赖注入
- Spring 4.x 中可以为子类注入子类对应的泛型类型的成员变量的引用
- Spring 允许通过 <import> 将多个配置文件引入到一个文件中,进行配置文件的集成。这样在启动 Spring 容器时,仅需要指定这个合并好的配置文件就可以
- import 元素的 resource 属性支持 Spring 的标准的路径资源
二、spEL表达式
- Spring 表达式语言(简称SpEL):是一个支持运行时查询和操作对象图的强大的表达式语言
- 语法类似于 EL:SpEL 使用 #{…} 作为定界符,所有在大框号中的字符都将被认为是 SpEL
- SpEL 为 bean 的属性进行动态赋值提供了便利
- 通过 SpEL 可以实现:
- 通过 bean 的 id 对 bean 进行引用
- 调用方法以及引用对象中的属性
- 计算表达式的值
- 正则表达式的匹配
1.字面量
- 整数:
<property name="count" value="#{5}"/>
- 小数:
<property name="frequency" value="#{89.7}"/>
- 科学计数法:
<property name="capacity" value="#{1e4}"/>
- Boolean:
<property name="enabled" value="#{false}"/>
2.引用Bean、属性和方法
(1)引用其它对象
<property name="enabled" value="#{对象}"/>
(2)引用其它对象的属性
<property name="enabled" value="#{对象.指定属性值}"/>
(3)调用其它对象的方法,支持链式操作
<property name="enabled" value="#{对象.方法名()}"/>
(4)调用静态方法或静态属性
通过 T() 调用一个类的静态方法,它将返回一个 Class Object,然后再调用相应的方法或属性
<property name="initValue" value="#{T(java.lang.Math).PI}"/>
3.运算符
- 算术运算符:+, -, *, /, %, ^
- 比较运算符: <, >, ==, <=, >=, lt, gt, eq, le, ge
- 逻辑运算符号: and, or, not, |
- if-else 运算符:?: (ternary): (Elvis)
<property name="gender" value="#{person.gender=='1'?'男':'女'}"/>
- 正则表达式:matches
<property name="email" value="#{admin.email matches '/^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/'}"/>
三、IOC中 Bean 的生命周期方法
- Spring IOC 容器可以管理 Bean 的生命周期, Spring 允许在 Bean 生命周期的特定点执行定制的任务
- Spring IOC 容器对 Bean 的生命周期进行管理的过程:
- 通过构造器或工厂方法创建 Bean 实例
- 为 Bean 的属性设置值和对其他 Bean 的引用
- 调用 Bean 的初始化方法
- Bean 可以使用了
- 当容器关闭时, 调用 Bean 的销毁方法
- 在 Bean 的声明里设置 init-method 和 destroy-method 属性, 为 Bean 指定初始化和销毁方法
1.创建Bean后置处理器
- Bean 后置处理器允许在调用初始化方法前后对 Bean 进行额外的处理.
- Bean 后置处理器对 IOC 容器里的所有 Bean 实例逐一处理, 而非单一实例. 其典型应用是: 检查 Bean 属性的正确性或根据特定的标准更改 Bean 的属性
- 对Bean 后置处理器而言, 需要实现BeanPostProcessor接口. 在初始化方法被调用前后, Spring 将把每个 Bean 实例分别传递给上述接口的以下两个方法:
Object postProcessBeforeInitialization(Object var1, String var2) throws BeansException;
Object postProcessAfterInitialization(Object var1, String var2) throws BeansException;
2.添加后置处理器后 Bean 的生命周期
- 通过构造器或工厂方法创建 Bean 实例
- 为 Bean 的属性设置值和对其他 Bean 的引用
- 将 Bean 实例传递给 Bean 后置处理器的 postProcessBeforeInitialization 方法
- 调用 Bean 的初始化方法
- 将 Bean 实例传递给 Bean 后置处理器的 postProcessAfterInitialization方法
- Bean 可以使用了
- 当容器关闭时, 调用 Bean 的销毁方法