类属性初始化 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这个抽象类的方式来使用。 |
|