分享

SpringBean初始化过程

 云澳 2019-10-30

类属性初始化

1、静态属性:static 开头定义的属性

2、静态方法块: static {} 圈起来的方法块

3、普通属性: 未带static定义的属性

4、普通方法块: {} 圈起来的方法块

5、构造函数: 类名相同的方法

6、方法: 普通方法

public class LifeCycle {

    // 静态属性

    private static String staticField = getStaticField();

    // 静态方法块

    static {

        System.out.println(staticField);

        System.out.println("静态方法块初始化");

        System.out.println("Static Patch Initial");

    }

    // 普通属性

    private String field = getField();

    // 普通方法块

    {

        System.out.println(field);

        System.out.println("普通方法块初始化");

        System.out.println("Field Patch Initial");

    }

    // 构造函数

    public LifeCycle() {

        System.out.println("构造函数初始化");

        System.out.println("Structure Initial ");

    }

    public static String getStaticField() {

        String statiFiled = "Static Field Initial";

        System.out.println("静态属性初始化");

        return statiFiled;

    }

    public static String getField() {

        String filed = "Field Initial";

        System.out.println("普通属性初始化");

        return filed;

    } 

    // 主函数

    public static void main(String[] argc) {

        new LifeCycle();

    }

}

执行结果:

静态属性初始化

Static Field Initial

静态方法块初始化

Static Patch Initial

普通属性初始化

Field Initial

普通方法块初始化

Field Patch Initial

构造函数初始化

Structure Initial

1、Spring Bean初始化回调

1.1 Bean初始化4种方式

1、如果要对多种Bean进行Hook,可以使用BeanPostProcessor来实现。

2、Bean类实现InitializingBean接口。

3、在bean的初始化方法中添加PostConstruct注解

4、bean创建的时候指定init-method

初始化执行顺序:

构造方法->Before Initialization->使用PostConstruct注解->InitializingBean接口->init-method指定的初始化方法->After Initialization

1.2 Bean初始化时Hook的实现原理

PostConstruct注解的初始化功能也是通过实现了BeanPostProcessor接口的bean来完成的。这个BeanPostProcessor会查找初始化类里面具有PostConstruct方法,然后进行调用。

接着我们在堆栈向上几层,可以看到一个非常关键的方法:initializeBean,bean初始化过程就是在这里完成的。

invokeInitMethods主要功能就是调用InitializingBean和init-method指定的初始化方法,使用的是反射调用

1.3 BeanPostProcessor的实现原理

BeanFactory中添加PostProcessor入缓存AbstractBeanFactory.java

遍历缓存好的PostProcessor实例的postProcessBeforeInitialization方法AbstractAutowireCapableBeanFactory.java

2、Spring Bean扩展接口

Spring框架运用了非常多的设计模式,从整体上看,它的设计严格遵循了OCP----开闭原则,即:

1、保证对修改关闭,即外部无法修改Spring整个运作的流程

2、提供对扩展开放,即可以通过继承、实现Spring提供的众多抽象类与接口来改变类加载的行为

2.1 InitialingBean和DisposableBean

InitialingBean是一个接口,提供了一个唯一的方法afterPropertiesSet()。

DisposableBean也是一个接口,提供了一个唯一的方法destory()。

这两个接口是一组的,功能类似,因此放在一起:前者顾名思义在Bean属性都设置完毕后调用afterPropertiesSet()方法做一些初始化的工作,后者在Bean生命周期结束前调用destory()方法做一些收尾工作

关于这两个接口,总结几点:

1、InitializingBean接口、Disposable接口可以和init-method、destory-method配合使用,接口执行顺序优先于配置

2、InitializingBean接口、Disposable接口底层使用类型强转.方法名()进行直接方法调用,init-method、destory-method底层使用反射,前者和Spring耦合程度更高但效率高,后者解除了和Spring之间的耦合但是效率低

3、afterPropertiesSet()方法是在Bean的属性设置之后才会进行调用,某个Bean的afterPropertiesSet()方法执行完毕才会执行下一个Bean的afterPropertiesSet()方法,因此不建议在afterPropertiesSet()方法中写处理时间太长的方法

2.2 BeanNameAware、ApplicationContextAware和BeanFactoryAware

这三个接口放在一起写,是因为它们是一组的,作用相似。

"Aware"的意思是"感知到的",那么这三个接口的意思也不难理解:

1、实现BeanNameAware接口的Bean,在Bean加载的过程中可以获取到该Bean的id

2、实现ApplicationContextAware接口的Bean,在Bean加载的过程中可以获取到Spring的ApplicationContext,这个尤其重要,ApplicationContext是Spring应用上下文,从ApplicationContext中可以获取包括任意的Bean在内的大量Spring容器内容和信息

3、实现BeanFactoryAware接口的Bean,在Bean加载的过程中可以获取到加载该Bean的BeanFactory

关于这三个接口以及上面的打印信息,总结几点:

1、如果你的BeanName、ApplicationContext、BeanFactory有用,那么就自己定义一个变量将它们保存下来,如果没用,那么只需要实现setXXX()方法,用一下Spring注入进来的参数即可

2、如果Bean同时还实现了InitializingBean,容器会保证BeanName、ApplicationContext和BeanFactory在调用afterPropertiesSet()方法被注入

2.3 FactoryBean

FactoryBean在Spring中是非常有用的,使用Eclipse/MyEclipse的朋友可以对FactoryBean使用ctrl+t查看一下,FactoryBean这个接口在Spring容器中有大量的子实现。

传统的Spring容器加载一个Bean的整个过程,都是由Spring控制的,换句话说,开发者除了设置Bean相关属性之外,是没有太多的自主权的。FactoryBean改变了这一点,开发者可以个性化地定制自己想要实例化出来的Bean,方法就是实现FactoryBean接口。

FactoryBean总结:

看到最后得到的并不是FactoryBean本身,而是FactoryBean的泛型对象,这就是FactoryBean的作用。FactoryBean的几个方法:

1、getObject()方法是最重要的,控制Bean的实例化过程

2、getObjectType()方法获取接口返回的实例的class

3、isSingleton()方法获取该Bean是否为一个单例的Bean

像我这段代码的功能就是传入一个String类型的参数,可以动态控制生成出来的是接口的哪种子类。有了FactoryBean,同样的我们也可以灵活地操控Bean的生成。

2.4 BeanPostProcessor

之前的InitializingBean、DisposableBean、FactoryBean包括init-method和destory-method,针对的都是某个Bean控制其初始化的操作,而似乎没有一种办法可以针对每个Bean的生成前后做一些逻辑操作,PostProcessor则帮助我们做到了这一点,先看一个简单的BeanPostProcessor。

BeanPostProcess接口有两个方法,都可以见名知意:

1、postProcessBeforeInitialization:在初始化Bean之前

2、postProcessAfterInitialization:在初始化Bean之后

值得注意的是,这两个方法是有返回值的,不要返回null,否则getBean的时候拿不到对象

Bean初始化前后都会分别执行postProcessorBeforeInitiallization()方法与postProcessorAfterInitialization()方法

ConfigurableListableBeanFactory还有很多的功能,比如添加BeanPostProcessor

2.5 BeanFactoryPostProcessor

接下来看另外一个PostProcessor----BeanFactoryPostProcessor。

Spring允许在Bean创建之前,读取Bean的元属性,并根据自己的需求对元属性进行改变,比如将Bean的scope从singleton改变为prototype,最典型的应用应当是PropertyPlaceholderConfigurer,替换xml文件中的占位符,替换为properties文件中相应的key对应的value,这将会在下篇文章中专门讲解PropertyPlaceholderConfigurer的作用及其原理。

1、BeanFactoryPostProcessor的执行优先级高于BeanPostProcessor

2、BeanFactoryPostProcessor的postProcessBeanFactory()方法只会执行一次

注意到postProcessBeanFactory方法是带了参数ConfigurableListableBeanFactory的,这就和我之前说的可以使用BeanFactoryPostProcessor来改变Bean的属性相对应起来了。ConfigurableListableBeanFactory功能非常丰富,最基本的,它携带了每个Bean的基本信息

2.6 InstantiationAwareBeanPostProcessor

最后写一个叫做InstantiationAwareBeanPostProcessor的PostProcessor。

InstantiationAwareBeanPostProcessor又代表了Spring的另外一段生命周期:实例化。先区别一下Spring Bean的实例化和初始化两个阶段的主要作用:

1、实例化----实例化的过程是一个创建Bean的过程,即调用Bean的构造函数,单例的Bean放入单例池中

2、初始化----初始化的过程是一个赋值的过程,即调用Bean的setter,设置Bean的属性

InstantiationAwareBeanPostProcessor作用的是Bean实例化前后,即:

1、Bean构造出来之前调用postProcessBeforeInstantiation()方法

2、Bean构造出来之后调用postProcessAfterInstantiation()方法

不过通常来讲,我们不会直接实现InstantiationAwareBeanPostProcessor接口,而是会采用继承InstantiationAwareBeanPostProcessorAdapter这个抽象类的方式来使用。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多