(四)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>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,681评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,710评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,623评论 0 334
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,202评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,232评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,368评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,795评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,461评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,647评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,476评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,525评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,226评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,785评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,857评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,090评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,647评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,215评论 2 341

推荐阅读更多精彩内容