(四)SpEL语言及Bean的生命周期

一、SpEL简述

 1.1 基本定义
  SpEL是一个支持运行时查询和操作对象图的强大表达式语言,语法类似于EL所有在#{}中的的字符都被认定为SpEL.
 1.2 SpEL的作用

  •   通过id引用Bean
  •   调用方法引用对象中的属性
  •   计算表达式的值
  •   正则表达式的匹配

二、SpEL使用

 2.1 字面量
  即直接根据字面值进行赋值,示例如下:

    整数:    <property name="age" value="#{25}"/>
    整数:    <property name="money" value="#{1e7}"/>
    布尔:    <property name="isValid" value="#{true}"/>
    字符串:需要使用单引号或者双引号作为字符串的定界符
    <property name="name" value="#{'张三'}"/>

 2.2 引用Bean,属性,及方法

  •   引用其他对象
<property name="prefix" value="#{prefixGenerator}"/>
  •   引用其他对象的属性
<property name="suffix" value="#{prefixGenerator.suffix}"/>
  •   同方法一样,可以进行链式操作。
  •   逻辑运算符:and or not !
  •   算术运算符+, -, *, /, %, ^,+还可直接连接字符串
  •   算比较运算符:<, >, ==, <=, >=, lt, gt, eq, le, ge
  •   if-else运算符:?(temary) 用法同三目运算符
  •   正则表达式
  •   调用静态方法或属性,用法:T(java.lang.Math).abs(-20)/>
    <!-- SpEL 基本示例 -->
    <bean id="personSPEL" class="com.spring.learn.bean_relation.Person" depends-on="personAuto">
        <property name="name" value="#{personAuto.getName()}"/>
        <property name="car" value="#{personAuto.car}"/>
        <property name="age" value="#{T(Math).abs(-18)*2}"/>
        <property name="address" value="#{address2}"/>
    </bean>
    <!-- SpEL 示例 -->
    <bean id="personSPEL1" class="com.spring.learn.bean_relation.Person" depends-on="personAuto">
        <property name="name" value="#{personAuto.getName()}"/>
        <property name="age" value="#{T(Math).abs(-18)*2}"/>
        <property name="car" value="#{car.years>5?car:null}"/>
        <property name="address" value="#{address2}"/>
        <!-- 覆写属性 -->
    </bean>

三、Bean的生命周期

3.1 Bean的生命周期过程

  •   通过构造器或工厂方法创建 Bean 实例
  •    Bean 的属性设置值和对其他 Bean 的引用
  •   调用 Bean 的初始化方法,对属性赋值。
  •   Bean 初始化完成,对外可用
  •   当容器关闭时, 调用 Bean 的销毁方法

3.2 Bean初始化和销毁设置

  在Bean声明里设置init-methoddestroy-method属性,可以为Bean指定初始化和销毁方法,初始化前调用一次初始化方法,容器关闭前调用销毁方法,示例修改上述Bean personSPEL1,为其添加初始化和销毁方法,需要显式调用ClassPathXmlApplicationContext的close方法,此处直接使用子类即可,不需要复制给其父类ApplicationContext

//需要显式调用ClassPathXmlApplicationContext的关闭方法
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean-relation.xml");
        Person spel = applicationContext.getBean("personSPEL1", Person.class);
        System.out.println(spel);
        // 关闭IOC容器
        applicationContext.close();
// 输出 在初始化前调用了一次init,关闭容器前调用一次destroy
// 调用顺序先调用Bean的属性设置或者构造器方法,然后调用init

  Bean的修改配置如下:

    <!-- 为该Bean添加init和destroy方法  -->
    <bean id="personSPEL1" class="com.spring.learn.bean_relation.Person" depends-on="personAuto" init-method="init" destroy-method="destroy">
        <property name="name" value="#{personAuto.getName()}"/>
        <property name="age" value="#{T(Math).abs(-18)*2}"/>
        <property name="car" value="#{car.years>5?car:null}"/>
        <property name="address" value="#{address2}"/>
        <!-- 覆写属性 -->
    </bean>

3.3 Bean的后置处理器

  •   Bean 后置处理器允许在调用初始化方法前后对 Bean 进行额外的处理.
  •   Bean 后置处理器对IOC 容器里的所有 Bean 实例逐一处理, 而非单一实例. 其典型应用是: 检查 Bean 属性的正确性或根据特定的标准更改 Bean 的属性.
  •   可以在后期处理器中修改Bean的属性,甚至返回一个新的Bean
  •   需要实现BeanPostProcessor接口,Spring将每个Bean实例分别传递给上述接口的以下两个方法:
    image.png
  •   添加一个类实现对应的方法即可:
/**
 * Created with IntelliJ IDEA.
 * User: gxm
 * Date: 2020/4/10
 * Time: 11:59
 * To change this template use File | Settings | File Templates.
 * Description:
 **/
package com.spring.learn.bean_relation;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // 完成对Bean的检查
        System.out.println("postProcessBeforeInitialization: "+bean+","+beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization: "+bean+","+beanName);
        return bean;
    }
}

  Bean的配置:

    <!-- 配置Bean的后置处理器 -->
    <bean class="com.spring.learn.bean_relation.MyBeanPostProcessor"/>

  输出结果:

postProcessBeforeInitialization: com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, dataSourceName -> 2tdca1a9r9jr4i105geao|402120, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, identityToken -> 2tdca1a9r9jr4i105geao|402120, idleConnectionTestPeriod -> 0, initialPoolSize -> 3, jdbcUrl -> jdbc:mysql://192.168.0.240:3306/MeasureAgent, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 15, maxStatements -> 0, maxStatementsPerConnection -> 0, minPoolSize -> 3, numHelperThreads -> 3, numThreadsAwaitingCheckoutDefaultUser -> 0, preferredTestQuery -> null, properties -> {user=******, password=******}, propertyCycle -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, usesTraditionalReflectiveProxies -> false ],dataSourceDB
postProcessAfterInitialization: com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, dataSourceName -> 2tdca1a9r9jr4i105geao|402120, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, identityToken -> 2tdca1a9r9jr4i105geao|402120, idleConnectionTestPeriod -> 0, initialPoolSize -> 3, jdbcUrl -> jdbc:mysql://192.168.0.240:3306/MeasureAgent, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 15, maxStatements -> 0, maxStatementsPerConnection -> 0, minPoolSize -> 3, numHelperThreads -> 3, numThreadsAwaitingCheckoutDefaultUser -> 0, preferredTestQuery -> null, properties -> {user=******, password=******}, propertyCycle -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, usesTraditionalReflectiveProxies -> false ],dataSourceDB
postProcessBeforeInitialization: Person{name='auto', age=36, car=Car{type='红旗', yeas=1}, address=Address{city='重庆', street='南山街道'}},personSPEL
postProcessAfterInitialization: Person{name='auto', age=36, car=Car{type='红旗', yeas=1}, address=Address{city='重庆', street='南山街道'}},personSPEL
postProcessBeforeInitialization: Person{name='auto', age=36, car=null, address=Address{city='重庆', street='南山街道'}},personSPEL1
init...
postProcessAfterInitialization: Person{name='auto', age=36, car=null, address=Address{city='重庆', street='南山街道'}},personSPEL1
Person{name='auto', age=0, car=Car{type='红旗', yeas=1}, address=null}

  添加Bean后置处理器后的Bean生命周期

  •   通过构造器或工厂方法创建 Bean 实例
  •   为 Bean 的属性设置值和对其他 Bean 的引用
  •   将 Bean 实例传递给 Bean 后置处理器的 postProcessBeforeInitialization 方法
  •   调用 Bean 的初始化方法
  •   将 Bean 实例传递给 Bean 后置处理器的
  •   postProcessAfterInitialization方法
  •   Bean 可以使用了
  •   当容器关闭时, 调用 Bean 的销毁方法

四、工厂模式

 测试类有如下方法:

    // 静态方法
    public static Person factory(String name,int age){
        return new Person(name,age,null);
    }
    // 普通方法,返回本类
    public Person createFactory(String name,int age){
        return new Person(name,age,null);
    }

 4.1非静态方法的工厂模式

  指定class和factory-method及factory-bean,使需要一个已有的Bean,然后通过该实例调用工程方法值作为另一个Bean,使用factory-bean指定该该实例,然后用factory-method指向返回该类的方法。

    <!-- 工厂模式1 : 非静态方法:必须实例化工厂类(factory-bean)后才能调用工厂方法 -->
    <bean id="personFactory2" class="com.spring.learn.bean_relation.Person"/>
    <bean id="person22" factory-bean="personFactory2" factory-method="createFactory">
        <constructor-arg index="0" value="gxm"/>
        <constructor-arg index="1" value="12"/>
    </bean>

 4.2静态方法的工厂模式

  指定class和factory-method即可

    <!-- 工厂模式2 : 静态方法:直接指定类和factory-method即可 -->
    <bean id="personFactory1" class="com.spring.learn.bean_relation.Person" factory-method="factory">
        <constructor-arg index="0" value="gxm"/>
        <constructor-arg index="1" value="15"/>
    </bean>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容