今天小编给大家分享一下spring初始化源码之关键类和扩展接口怎么应用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。
1、关键接口和类
1.1、关键类之 DefaultListablebeanfactory
该类核心功能:
1、提供注册、获取等等与BeanDeFinition对象操作相关的方法,BeanDeFinition缓存在DefaultListablebeanfactory的beanDeFinitionMap变量(ConcurrentHashMap类型)
2、提供创建、注册、获取、单例等等跟bean对象操作相关的方法供ApplicationContext使用,bean对象缓存在DefaultSingletonBeanRegistry的singletonObjects 变量(ConcurrentHashMap类型)
类关系图如下:
从类图中看到DefaultListablebeanfactory实现了很多接口,spring 根据该类的功能定义了不同层次的接口。接口核心功能主要分两类:1、AliasRegistry、BeanDeFinitionRegistry接口主要提供BeanDeFinition和alias注册、获取的方法,2、左半部分*beanfactory相关接口、SingletonBeanRegistry接口提供对象的创建、缓存和获取等方法
1.2、关键类之XmlBeanDeFinitionReader
该类负责分析xml中bean的定义,并解析成BeanDeFinition对象,然后调用DefaultListablebeanfactory的注册方法缓存到DefaultListablebeanfactory中
1.3、关键类之ClasspathXmlApplicationContext
先上类关系图:
这个就是spring上下文,是spring启动的入口类,从父类AbstractApplicationContext的refresh()方法中可以看出该类的主要功能:设置springContext.xml路径、创建DefaultListablebeanfactory、提供对象创建过程中的各种扩展点、事件的注册和分发等等。
2、spring初始化过程中对外暴露的扩展接口
1、BeanNameAware:void setBeanName(String name);
该bean获取自己在DefaultListablebeanfactory中的id或name ,在spring框架里用的多,我们一般很少用到。
2、beanfactoryAware:void setbeanfactory(beanfactory beanfactory)
获取创建该bean的DefaultListablebeanfactory对象,可以从该对象中回去bean对象,不过绝大多数时候我们是从ApplicationContext中来获取。
3、ApplicationContextAware:void setApplicationContext(ApplicationContext applicationContext)
获取该bean所属的applicationContext,从而可以获取到该上下文的bean对象。自己写一个工具类实现该接口然后在配置文件中配置或加上@Component注解,通过这个工具类就很方便的在应用中动态获取bean对象,这种工具类在很多老的项目中几乎是一个标配。
4、InitializingBean:void afterPropertiesSet()
spring提供两中方式来对bean初始化后的扩展,一种是实现InitializingBean接口,一种是使用通过init-method方法指定,spring初始化bean时在执行InitializingBean接口的afterPropertiesSet方法后就紧接着执行init-method指定的方法。使用init-method不会对spring产生依赖因此使用频率较高,但由于这种方式使用反射方式来调用所以性能上低于直接调用 InitializingBean接口的afterPropertiesSet方法,后面会有相应的代码分析。
5、指定init-method
用的较多,可以理解为spring在bean对象初始化完后会通过反射的方式来执行该bean中init-method指定的方法。通过在xml文件中的bean标签配置init-method或在该bean的方法上使用@postconstruct注解达到效果。
6、beanfactoryPostProcessor:void postProcessbeanfactory(ConfigurableListablebeanfactory beanfactory)
从后面的代码分析中我们发现,实现beanfactoryPostProcessor接口的bean的创建及接口方法的调用时间早于普通bean的创建。实现该接口可以拿到beanfactory对象,然后就看可以在普通bean对象创建之前进行干预调整,PropertyPlaceholderConfigurer类大家应该比较熟悉,该类实现beanfactoryPostProcessor接口,在postProcessbeanfactory方法中将beanDeFinitionMap中所有的BeanDeFinition中的含有占位符的值修改为指定属性文件中的值,这样在创建对象的时候就能获取到真实值。
7、BeanPostProcessor:Object postProcessBeforeInitialization(Object bean, String beanName);
BeanPostProcessor:Object postProcessAfterInitialization(Object bean, String beanName);
该接口需要注意与beanfactoryPostProcessor接口的区别:
beanfactoryPostProcessor接口:A实现了该接口,spring启动的时候,在所有普通bean对象创建之前会先创建A对象并调用其postProcessbeanfactory方法,方法参数为beanfactory。
BeanPostProcessor接口:A实现了该接口,spring在创建普通的bean 对象B时,在B对象初始化之前将B对象的实例和beanname作为入参调用A的前置方法postProcessBeforeInitialization,在B对象初始化之后将B对象的实例和beanname作为入参调用A的后置方法postProcessAfterInitialization。由此也可知实现该接口bean的创建时间早于普通bean的创建。
通过实现该接口也可以完成对bean对象的调整,但与beanfactoryPostProcessor还是有本质的区别,实现beanfactoryPostProcessor可以理解为对创建的模板的调整,是对BeanDeFinition对象的调整,而BeanPostProcessor则是在对象过程中做的临时的调整,是对创建好的bean对象的调整
使用BeanPostProcessor需要注意:
①、前置、后置方法需要将修改后的bean对象返回这样getbean时才能获取到正确的bean对象
8、ApplicationListener:void onApplicationEvent(E event)
spring上下文启动完成后回调该接口,比较常用。
3、扩展点的启动顺序
1、HelloWorldService bean对象
public class HelloWorldService implements beanfactoryAware,BeanNameAware,beanfactoryPostProcessor, BeanPostProcessor,InitializingBean , ApplicationListener<ContextRefreshedEvent>,ApplicationContextAware { private String name; private AtomicInteger count = new AtomicInteger(1); private String getSeq(){ return count.getAndIncrement()+"->"; } public HelloWorldService(){ System.err.println(getSeq()+"HelloWorldService constructor"); } public void initMethod(){ System.err.println(getSeq()+"init method"); } public void sayHello(){ System.err.println(getSeq()+name+"say:hello,world"); } public String getName() { return name; } public void setName(String name) { this.name = name; } public void setBeanName(String name) { System.err.println(getSeq()+"BeanNameAware.setBeanName:"+name); } public void setbeanfactory(beanfactory beanfactory) throws BeansException { System.err.println(getSeq()+"beanfactoryAware.setbeanfactory:"+beanfactory); } public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { System.err.println(getSeq()+"ApplicationContextAware.setApplicationContext:->"+applicationContext); } public void afterPropertiesSet() { System.err.println(getSeq()+"InitializingBean.afterPropertiesSet"); } public void postProcessbeanfactory(ConfigurableListablebeanfactory configurableListablebeanfactory) throws BeansException { BeanDeFinition beanDeFinition = configurableListablebeanfactory.getBeanDeFinition("peopleService"); beanDeFinition.getPropertyValues(); MutablePropertyValues m = beanDeFinition.getPropertyValues(); m.addPropertyValue("content", "i am ok"); System.err.println(getSeq()+"beanfactoryPostProcessor.postProcessbeanfactory 将peopleService的content属性修改为i am ok"); } public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.err.println(getSeq()+"BeanPostProcessor.postProcessBeforeInitialization->"+beanName); return bean; } public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.err.println(getSeq()+"BeanPostProcessor.postProcessAfterInitialization->"+beanName); return bean; } public void onApplicationEvent(ContextRefreshedEvent event) { System.err.println(getSeq()+"ApplicationListener.onApplicationEvent: Refreshed->"+event.getApplicationContext()); } }
2 、非lazy的普通bean对象,PeopleService
public class PeopleService{ private String content=""; public PeopleService(){ System.err.println("PeopleService constructor"); } public void say(){ System.err.println("PeopleService say:["+content+"]"); } public String getContent() { return content; } public void setContent(String content) { this.content = content; } }
3、启动类
public class AppMain { public static void main(String[] args) { ApplicationContext applicationContext = new ClasspathXmlApplicationContext("applicationContext.xml"); System.err.println("==============================================="); HelloWorldService helloWorldService = applicationContext.getBean("helloWorldService",HelloWorldService.class); helloWorldService.sayHello(); PeopleService peopleService = applicationContext.getBean("peopleService",PeopleService.class); peopleService.say(); } }
代码执行结果:
从输入结果中我们得到以下信息:
1、HelloWorldService 实现 beanfactoryPostProcessor接口所以创建时间早于普通非lazy的bean对象PeopleService
2、1-7为HelloWorldService 创建过程输出的日志,可以看到各扩展接口的执行顺序
3、第7步之后开始创建PeopleService对象,创建过程中回调用HelloWorldService(实现了BeanPostProcessor接口) 的前置和后置方法
4、spring上下文启动完成后发布ContextRefreshedEvent事件,输出第10步日志
以上就是“spring初始化源码之关键类和扩展接口怎么应用”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注编程之家行业资讯频道。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。