Spring中级 IOC

Spring中级 IOC

1. 对象的生命周期

1.1什么是对象的声明周期

指的是一个对象创建、存活、消亡的一个完成过程

1.2.为什么学习对象的生命周期

由Spring负责对象的创建、存活、销毁。了解生命周期,有利于我们使用好Spring为我们创建的对象

1.3.生命周期的3个阶段

1.3.1创建阶段
Spring工厂何时创建对象
  • scope=“singleton”

    Spring工厂创建的同时,对象的创建
    注意:设置sope=singleton 也需要在获取对象的同时,创建对象,设置配置文件:layz-init
    
  • scope=“prototype”

    Spring工厂会在获取对象的同时,创建对象
    ctx.getBean("")
    
1.3.2初始化阶段
Spring工厂在创建完对象后,调用对象的初始化方法,完成对应的初始化操作
	1.初始化方法提供:程序员跟据需求,提供初始化方法,最终完成初始化操作
	2.初始化方法调用:Spring工厂进行调用
  • initializingBean接口

    //初始化方法
    //耦合了Spring框架
    public void afterPropertiesSet()
    
  • 对象中提供方法

    public void myInit(){
        
    }
    <bean id ="person" class="**.person" init-method="myInit"/>
    

    细节:

    • 如果都提供了两种方法,先执行接口初始化操作,在执行自定义初始化方法

    • 当使用init-method 调用实现initializingBean接口的方法时,init-method会失效

    • 注入发生在初始化之前

      • 如果bean标签中还存在注入,则先执行注入,在执行初始化方法。所以接口方法名叫afterPropretiesSet 属性之后写入.
    • 什么叫初始化操作

      资源的初始化:数据库、IO、网络....
      

      实际项目开发中 不常用

1.3.3销毁阶段
Spring销毁对象前,会调用对象的销毁的方法。完成销毁操作

1.Spring什么时候会销毁所创建的对象
	ctx.close();
2.销毁方法,程序员定义的方法
	调用:Spring工厂完成调用
  • disposableBean接口

     @Override
    //实现销毁方法
    public void destroy() throws Exception {
        System.out.println("OldPerson.destroy");
    }
    
  • 定义一个普通的销毁方法

    @Override
    public void myDestroy() throws Exception {
        System.out.println("OldPerson.myDestroy");
    }
<bean id ="person" class="**.person" destroy-method="destroy1"/>

细节分析

  • 对象销毁只适用于 scope=“singleton”

  • 原型对象不受Spring管理,单例对象保存在Spring中的一个单例map中。

  • 什么叫做销毁操作

  • 主要指的就是 资源的释放操作 io.close() connection.close()

  • 当两种方式同时存在时,优先级为

    1.disposableBean
    2.destroy-method 
    
  • 实战中很少用

image-20200906225940195

1.4总结

singleton 对象 默认在 spring工厂初始化时创建,如果需要在对象第一次调用时创建。则需在配置文件中配置 lazy-init开启懒加载。

prototype对象在用户调用的时候创建。不受Spring控制,所以prototype不支持销毁操作

注入成员变量操作在对象初始化之前

2.配置文件参数化

把Spirng配置文件中需要经常修改的字符串信息,转移到更小的配置文件中
	1.Spring的配置文件存在需要经常修改的字符串吗
		存在:以数据库连接相关的参数 代表
    2.什么场景需要配置文件参数化
    	经常修改的字符串
    3.好与不好,在于维护好不好
    	运维工程师可能不懂java代码不懂spring。你要他如何在几千行的配置文件中找到要修改的字符串
    	不利于项目维护(修改)
    4.转移到一个小的配置文件(properties)

image-20200906231527242

2.1 配置文件参数化的开发步骤

image-20200906233220129

2.1.1 提供一個小的配置文件 (properties)
名字可以随意
位置可以随意

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/userdb?useUnicode=utf-8&characterEncoding=utf-8serverTimezone=GMT%2B8useSSL=true
jdbc.username=root
jdbc.password=root
2.1.2 Spring配置文件与小配置文件的整合
<!--application.xml-->
<context:property-placeholder location="classpath:db.properties"/>

<!--Spring特有xml/yml 
	classpath: 代表类路径目录 spring会从这里去寻找一个指定的配置文件
	classpath*: 代表类路根目录 Spring会从这里去寻找多个符合条件的配置文件。

-->

细节: classpath:不支持* 通配符。当location出现此符号时,此条配置作废,但不会抛出异常

2.1.3 在Spring配置文件中通过${key} 获取小配置文件中对应的值
    <bean class="com.spring.factorybean.DruidDataSource" id="dataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
</bean>

3 自定义类型转换器

3.1.类型转换器

作用:Spring通过类型转换器把配置文件中字符串类型的数据,转换成了对象中成员变量对应类型的数据,进而完成了注入

image-20200907005008680

3.2 自定义类型转换器

原因:当Spring内部没有提供特定类型转换器时,而程序员在应用的过程中还需要使用,那么就需要程序员自己定义类型转换器

image-20200907010430766

image-20200907010444301

抛出异常:非法状态异常 :没有扫描到指定类型转换器。

原因:太难为spring了。每个国家的日期转换都不一样

  • 中国: yyyy-MM-dd

  • 美国:dd/MM/yyyy

    sping并不知道你想要哪一种转换。所以自身不提供类型转换器。此时,便需要程序员自己配置

image-20200907010505770

image-20200907120705320

3.2.1 开发步骤
类 implements Converter 接口
/**
 * convert 方法:Spring ---->LocalDateTime
 		DateTimeFormatter dtf = DateTimeFormatter.ofPatten("yyyy-MM-dd"); ---> LocalDateTime
 param:source 代表的是配置文件中 日期字符串 <value>2020-10-11</value>
 
 return:当把转换好的Date作为convert 方法的返回值后,Spring自动的为birthday 属性进行注入(赋值)
 *
 */
public class MyDateConverter implements Converter<String, LocalDateTime> {
    DateTimeFormatter dateTimeFormatter;

    public void init(){
        DateTimeFormatter.ofPattern("yyyy-MM-dd");
    }
    @Override
    public LocalDateTime convert(String source) {
        return LocalDateTime.parse(source,dateTimeFormatter);
    }
}

在Spring的配置文件中进行配置
  • 创建MyDateConverter Bean
<bean id ="myDateConverter" class="xxxx.myDateCOnverter"/>
  • 创建转换服务工厂组件并注册(注入)类型转换器
目的:告知Spring框架 ,我们所创建的MyDateConverter是一个类型转换器
<!--用于注册类型转换器-->
<bean class="org.springframework.context.support.ConversionServiceFactoryBean" id="conversionService">
    <property name="converters">
        <set>
            <ref bean="myDateConverter"/>
        </set>
    </property>
</bean>
细节
  • MyDateConverter 中的日期的格式,通过依赖注入的方式,由配置文件完成赋值。
 //MyDateConverter
public class MyDateConverter implements Converter<String, LocalDate> {
    DateTimeFormatter dateTimeFormatter;
    String datePattern;

    public void setDatePattern(String datePattern) {
        this.datePattern = datePattern;
    }

    public void init() {
        dateTimeFormatter = DateTimeFormatter.ofPattern(datePattern);
    }

    @Override
    public LocalDate convert(String source) {
        return LocalDate.parse(source, dateTimeFormatter);
    }
}
//Person
public class Person {
    public String name;
    private LocalDate birthday;
    ...
}

<!--application.xml-->
 <context:property-placeholder location="classpath:date.properties"/>
<bean class="com.spring.converter.MyDateConverter" init-method="init" id="myDateConverter">
    <property name="datePattern" value="${date.pattern}"/>
</bean>

<bean class="org.springframework.context.support.ConversionServiceFactoryBean" id="conversionService">
    <property name="converters">
        <set>
            <ref bean="myDateConverter"/>
        </set>
    </property>
</bean>

<bean class="com.spring.converter.Person" id="person">
    <property name="name" value="菅江晖"/>
    <property name="birthday" value="2002-07-24"/>
</bean>
# date.properties
date.pattern=yyyy-MM-dd
dateTime.pattern=yyyy-MM-dd HH:mm:ss
  • ConverterServiceFactoryBean id必须为 conversionService
    • 因为Spring是通过id来寻找转换服务工厂的,如果不存在id为conversionService 的转换工厂。spring默认啥也不做
Spring内置日期类型的转换器。
  • 日期格式:2020/05/01(不支持:2020-05-01)
    

image-20200907153401045

4 后置处理 Bean

BeanPostProcessor 对Spring工厂所创建的对象,进行在加工

AOP底层实现

注意:BeanPostProcessor 接口 
		xxxx(){
		
		}

Spring工厂所创建的对象

image-20200907161914452

BeanPostProcessor运行原理分析

image-20200907163430282

程序员实现BeanPostProcessor接口中的方法:

Object postProcessorBeforeInitialization(Object bean ,String beanName)
作用:Spring创建完对象并进行注入后,可以运行Before方法进行加工
获得Spring创建好的对象:通过方法的参数
最终通过返回值交给Spring框架

Object postProcessorAfterInitializetion(Object bean,String beanName)
作用:Spring执行完对象的初始化操作后,可以运行after方法进行加工
获得Spring创建好的对象:通过方法的参数
最终通过返回值交给Spring框架

实战中:很少进行初始化操作,没有必要区分Before After,只需要其中的一个方法即可
注意:
	postProcesserinitialization
	return bean对象
4.1 BeanPostProcessor开发步骤
  • 1 类实现BeanPostProcessor接口
public class MyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        //do thing
        System.out.println(bean);
        return bean;
    }
}

  • 2.Spring的配置文件中继续配置
     <bean class="com.spring.beanpost.MyBeanPostProcessor" id="beanPostProcessor"/>

BeanPostProcessor 细节

BeanPostProcessor会对Spring工厂中所有创建的对象继续加工

image-20200914150812144

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值