Spring之Bean的配置(二)

目录

一、Bean的配置

1.自动装配

(1)简介

(2)缺点

2.继承Bean

3.依赖Bean配置

4.Bean的作用域

5.使用外部属性文件

6.注册PropertyPlaceholderConfigurer

7.通过工厂方法配置Bean

扫描二维码关注公众号,回复: 3554180 查看本文章

(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

  1. Spring 允许继承 bean 的配置, 被继承的 bean 称为父 bean. 继承这个父 Bean 的 Bean 称为子 Bean

  2. 子 Bean 从父 Bean 中继承配置, 包括 Bean 的属性配置

  3. 子 Bean 也可以覆盖从父 Bean 继承过来的配置

  4. 父 Bean 可以作为配置模板, 也可以作为 Bean 实例. 若只想把父 Bean 作为模板, 可以设置 <bean> 的abstract 属性为 true, 这样 Spring 将不会实例化这个 Bean

  5. 并不是 <bean> 元素里的所有属性都会被继承. 比如: autowire, abstract 等

  6. 也可以忽略父 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 属性里设置 Bean 的作用域

  • 默认情况下, 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>

  • context:include-filtercontext: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), 一切具有参数的方法都可以应用@Authwired 注解

    • 默认情况下, 所有使用 @Authwired 注解的属性都需要被设置. 当 Spring 找不到匹配的 Bean 装配属性时, 会抛出异常, 若某一属性允许不被设置, 可以设置 @Authwired 注解的 required 属性为 false

    • 默认情况下, 当 IOC 容器里存在多个类型兼容的 Bean 时, 通过类型的自动装配将无法工作. 此时可以在 @Qualifier 注解里提供 Bean 的名称. Spring 允许对方法的入参标注 @Qualifiter 已指定注入 Bean 的名称

    • @Authwired 注解也可以应用在数组类型的属性上, 此时 Spring 将会把所有匹配的 Bean 进行自动装配

    • @Authwired 注解也可以应用在集合属性上, 此时 Spring 读取该集合的类型信息, 然后自动装配所有与之兼容的 Bean

    • @Authwired 注解用在 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 的销毁方法

猜你喜欢

转载自blog.csdn.net/fy_java1995/article/details/82862094