目录
文章图片
看现象
maven依赖 我们只测试IOC容器,因此只需要引入spring-context即可
junit
junit
RELEASE
test
com.github.javafaker
javafaker
1.0.2
org.springframework
spring-context
RELEASE
测试用例
/**
* 测试spring的ioc容器
*/
public class TestSpringIOC {@Test
public void test(){
// create and configure beans
ApplicationContext context = new ClassPathXmlApplicationContext("ioc/services.xml","ioc/daos.xml");
// retrieve configured instance
UserService service = context.getBean("userService", UserService.class);
// use configured instance
System.out.println();
System.out.println("测试注入-------------------------------------------------");
List userList = service.findUsers(20);
userList.stream().forEach(System.out::println);
AwareTestService awareTestService = (AwareTestService)context.getBean("awareTestService");
System.out.println();
System.out.println("测试Aware-------------------------------------------------");
awareTestService.test();
AwareTestService awareTestServiceAlias = (AwareTestService)context.getBean("awareTestServiceAlias");
System.out.println();
System.out.println("测试bean别名---------------------------------------------------");
System.out.println(awareTestServiceAlias == awareTestService);
//true
}
}
测试用例里面引入了两个配置文件:services.xml和daos.xml,看看里面写了啥(引用到的类文末有代码清单)
- services.xml
- daos.xml
运行结果
初始化 before--实例化的bean对象之前:com.spring.dao.impl.UserDaoImpl@3cb1ffe6userDao
初始化 after...实例化的bean对象之后:com.spring.dao.impl.UserDaoImpl@3cb1ffe6userDao
初始化 before--实例化的bean对象之前:com.spring.service.impl.UserServiceImpl@43bd930auserService
初始化 after...实例化的bean对象之后:com.spring.service.impl.UserServiceImpl@43bd930auserService
初始化 before--实例化的bean对象之前:com.spring.service.impl.AwareTestServiceImpl@33723e30awareTestService
初始化 after...实例化的bean对象之后:com.spring.service.impl.AwareTestServiceImpl@33723e30awareTestService测试注入-------------------------------------------------
User{name='范烨霖', age=17, phone='17647798623', location='瓦房店'}
User{name='尹擎苍', age=56, phone='17314101961', location='泸州'}
...测试Aware-------------------------------------------------
Spring中的6大自动注入aware接口
true
...测试bean别名---------------------------------------------------
true
思考 xml文件里面配置了bean,那么Spring是怎么将这些bean初始化到IOC容器的呢?IOC容器具体是什么呢?
IOC容器初始化流程 开局一张图
文章图片
几大主要的类 AbstractBeanDefinitionReader 抽象的bean定义reader,不管你是从哪里读取,是从XML,还是注解读取,都提供统一的接口对外暴露读取bean定义的接口,单独抽象了这一层出来屏蔽掉XML或者注解读取
文章图片
AbstractApplicationContext 抽象应用上下文,应用了模板方法模式,下面简称应用上下文或上下文
文章图片
AbstractBeanFactory 抽象Bean工厂,运用模板方法模式,下面简称bean工厂或工厂
[图片上传失败…(image-87e039-1615555942316)]
ConfigurableEnvironment 当前容器运行的环境,里面包含了一些JDK的系统属性等等,可以通过实现EnvironmentAware接口拿到当前的容器环境
文章图片
BeanFactoryPostProcessor 里面有一方法postProcessBeanFactory,顾名思义这是在工厂生产bean之前对工厂本身调用的回调函数,千万要和BeanPostProcessor区分开来
BeanPostProcessor 里面有俩方法postProcessBeforeInitialization和postProcessAfterInitialization,大腿想一想这应该是在bean初始化之前和初始化之后要调用的回调函数
ApplicationListener 用大腿想一下这玩意儿应该是注册事件用的,在容器初始化的不同阶段调回调函数
文章图片
IOC容器执行流程
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml");
就这么一句话就初始化了Spring的IOC容器,怎么初始化的?
1.初始化顶层对象AbstractApplicationContext 这方法
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
ClassPathXmlApplicationContext一看就是AbstractApplicationContext的子类,这里用了模板方法,其他的各种ApplicationContext公用AbstractApplicationContext中的通用方法,其他要自己实现的子类去实现即可 ,super(parent)这句话不断往父类调,调到AbstractApplicationContext为止,此时加载AbstractApplicationContext并且初始化其中的一些成员变量,比如容器ID,一些Map,一些锁之类的东西
题外话: AbstractApplicationContext中的一些锁是这么定义的,取名叫XXXmonitor,实际上就是个空对象,拿给容器启动关闭的时候配合syncronized使用,这也说明了java中的syncronized,锁的就是对象
/** Synchronization monitor for the "refresh" and "destroy". */
private final Object startupShutdownMonitor = new Object();
2.引入配置文件 引入配置就这句话,接收classpath下面的xml文件路径
setConfigLocations(configLocations);
这句话没啥好说的就赋个值,需要注意的是里面初始化了容器环境,就下面这句话,是在AbstractApplicationContext定义的
public ConfigurableEnvironment getEnvironment() {
if (this.environment == null) {
this.environment = createEnvironment();
}
return this.environment;
}
3.refresh 重点来了,refresh是在AbstractApplicationContext中定义的,字面叫刷新,刷新啥?人家源码里面注释都说了:加载或者刷新可能从XML文件,properties文件,数据库等文件的配置并持久化,说白了就是根据配置实例化bean,这里面又有很多步骤,不是简简单单实例化三个字可以表述清楚的
源码在此,别人每句话都写上了注释,我们挨个来看
synchronized (this.startupShutdownMonitor) {
// 3.1 Prepare this context for refreshing.
prepareRefresh();
// 3.2 Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 3.3 Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// 3.4 Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// 3.5 Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// 3.6 Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// 3.7 Initialize message source for this context.
initMessageSource();
// 3.8 Initialize event multicaster for this context.
initApplicationEventMulticaster();
// 3.9 Initialize other special beans in specific context subclasses.
onRefresh();
// 3.10 Check for listener beans and register them.
registerListeners();
// 3.11 Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// 3.12 Last step: publish corresponding event.
finishRefresh();
}catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
3.1 刷新前的准备工作:prepareRefresh 刷新之前的准备工作,准备啥?准备了容器启动时间,容器状态标志位的设置,初始化一些装事件监听器的容器,这些没啥说的,看源码就知道
注意:此处有一个回调函数,说的很清楚,准备的时候子类可以干点事情,干子类自己的事情,当然我们这个子类ClassPathXmlApplicationContext比较懒,它啥也没干
protected void initPropertySources() {
// For subclasses: do nothing by default.
}
3.2 初始化bean工厂 obtainFreshBeanFactory 这个是重点,重量级角色BeanFactory登上历史舞台,看注释:告诉子类让子类刷新内部的BeanFactory,啥意思?就是说这个BeanFactory你子类去实现,我(容器上下文)不管你子类new的啥工厂,反正你给我new好了,用的时候我调用模板方法你子类返回给我,我做一些公共的方法即可,这也是面向接口编程的好处,我不持有具体的引用
具体是那个类在new工厂?看下面
AbstractRefreshableApplicationContext.refreshBeanFactory()在new这个工厂,这个AbstractRefreshableApplicationContext是ClassPathXmlApplicationContext的父类,看到了吧,它就是一层包一层,一层实现一点点功能,然后组合嵌套起来实现大功能
...
DefaultListableBeanFactory beanFactory = createBeanFactory();
//new一工厂
beanFactory.setSerializationId(getId());
//工厂的序列化id和上下文的id是一样的,getId()就是上下文的id
customizeBeanFactory(beanFactory);
//
loadBeanDefinitions(beanFactory);
//重点来了,此处才在通过XML文件读取成bean的定义
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
...AbstractRefreshableApplicationContext#createBeanFactory()方法
protected DefaultListableBeanFactory createBeanFactory() {
return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}
我们可以看到new了一个DefaultListableBeanFactory工厂,loadBeanDefinitions将XML文件读取成bean定义,此时才真正开始读取XML文件,真正的读取是在XmlBeanDefinitionReader#doLoadBeanDefinitions和doRegisterBeanDefinitions方法中进行的,Spring中,凡是doXXX都是真正干活的方法,怎么读取的具体请看源码,大多都是一些很繁琐的细节,只要知道在这里读取就OK
3.3 为当前上下文准备一下bean工厂 prepareBeanFactory 配置工厂的标准上下文特征,例如上下文的类加载器和后处理器。这啥意思,就是说这个工厂我现在要准备在上下文用了,你给我初始化一些东西,初始化啥?就是把spring的一些内部对象给放到了bean工厂里面,可见,上下文需要的一些bean也是放在bean工厂里面的
- 注意此处注册了俩BeanPostProcessor,分别是ApplicationContextAwareProcessor和ApplicationListenerDetectorApplicationContextAwareProcessor:在bean初始化之前注入一些实现了特殊的Aware的接口的bean如果你的bean实现了下面六个Aware接口,分别是ApplicationContext、ApplicationEventPublisher、StringValueResolver、Environment、MessageSource、ResourceLoader这些都是spring内部对象,如果使用了他们,将和spring框架耦合,如非特殊情况不建议使用,具体使用方法见AwareTestServiceImpl.java,设置setter即可注入ApplicationListenerDetector:在bean初始化完成之后检测此bean是否是ApplicationListener,如果是的话在上下文里面注册一下
- 忽略一些bean工厂接口,上面那六个Aware接口是bean工厂自己用的,那实例化bean的时候就不管他们了,具体看代码
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
- 向bean工厂注册一些依赖,像容器上下文、事件发布器之类的东西注册给bean工厂,怎么注册?就是放到向bean工厂里面的map而已
- 还注册了一些系统需要的单例bean,名字都是写死的,比如environment、systemProperties、systemEnvironment
总之,这个方法完善了bean工厂,给bean工厂放入了一些自己需要的资源,我们来看下DefaultListableBeanFactory里面都有些啥成员变量
//TODO
3.4 预处理bean工厂 postProcessBeanFactory 预处理什么?谁来预处理?,这就是个空方法,留给具体的上下文实现,注释写的很清楚,这是留给具体上下文即子类来实现的,代码运行到这里
说明bean工厂已经初始化好了,但是还没有实例化bean,子类可以在这里注册一些特殊的BeanPostProcessors
所以预处理什么? 抽象上下文的子类想对bean工厂做点什么你可以做,做啥你子类自己应该知道
谁来预处理?当然是抽象上下文的子类来做,当然ClassPathXmlApplicationContext比较懒,他啥也没做
3.5 调用bean工厂的预处理 invokeBeanFactoryPostProcessors 什么叫调用bean工厂的处理?就是说在bean工厂配置好后,bean实例化之前对bean工厂本身要做的一些配置,就在这里进行,你可以看到一堆一堆的Processors,Processors顾名思义就是处理器嘛
看下抽象上下文的addBeanFactoryPostProcessor方法,就是往抽象上下文里面不断装BeanFactoryPostProcessor,当然你也可以拿到抽象上下文实例去往里面装自己的BeanFactoryPostProcessor,明白了么。框架的东西就是到处给提供了很多扩展,你可以往里面加自己的逻辑处理
这是抽象上下文里面进行处理的,看看具体处理了啥,目标方法为PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); ,这就是个静态方法嘛,你可以理解成工具方法
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
//对BeanDefinitionRegistry做了个特殊处理
if (beanFactory instanceof BeanDefinitionRegistry) {
...
} else {
// Invoke factory processors registered with the context instance.
//对于已经注册了的BeanFactoryPostProcessors,挨个开始应用
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
List priorityOrderedPostProcessors = new ArrayList<>();
List orderedPostProcessorNames = new ArrayList<>();
List nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {
// skip - already processed in first phase above
}
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
List orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
// Finally, invoke all other BeanFactoryPostProcessors.
List nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
// Clear cached merged bean definitions since the post-processors might have
// modified the original metadata, e.g. replacing placeholders in values...
beanFactory.clearMetadataCache();
仔细看看上面的源码,都有注释的,沉下心去看是个人肯定能看懂的:
- 最开始,初始化一个processedBeans的list,装已经执行过的processors,避免重复执行
- 首先,对BeanDefinitionRegistry这种特殊的工厂特殊处理,这个先略过,咱们这个不是BeanDefinitionRegistry
- 走else逻辑,挨个把从上下文传进来的beanFactoryPostProcessors执行了一遍,这样不就完了吗?还没完,继续看下面
- beanFactory.getBeanNamesForType从bean工厂里面拿出BeanFactoryPostProcessor!除了上下文传进来的Processor,bean工厂里面可能还有!
- 下面就比较有趣了,创建了仨list,看名字就知道和优先级有关系,就是说执行是有优先级的,优先级高的先执行,优先级低的后执行,没有优先级的最后执行
- 所以就这么个东西。把所有的processors,bean工厂里面的,上下文里面的拿出来执行一遍,虽然代码看起来多,但就干了这么个事
BeanPostProcessors是啥,看它接口的定义,俩方法:postProcessBeforeInitialization、postProcessAfterInitialization,一个是在bean被初始化之前调用,一个是在bean初始化之后调用,说白了就是回调函数,一定要和BeanFactoryPostProcessors区分开来,前者是针对bean的,后者是针对bean工厂的,名字里面都有个Factory嘛,已经很明显了
就一句话PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this); ,里面的逻辑和invokeBeanFactoryPostProcessors差不多,也是把processors分为了带优先级的,带顺序的和不带顺序的,还有一种叫做内部的,把这几种放入bean工厂的map里面,再次强调,此时只是注册,还没有开始执行!!!
其实,BeanPostProcessors运用了责任链的设计模式。重写自己的processors参考代码MyBeanPostProcessor,然后在xml文件里面注册这个bean,当然不注册也可以手动在context里面添加,不管怎么样只要能放到bean工厂里面的map就行了
多说一句:
- 在xml里面定义的processor会成为bean定义读取到bean工厂中,注册processor的时候有这样一段代码,从bean工厂的bean定义里面拿processor对应的就是xml注册的方式String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
- 直接调用addBeanPostProcessor,这就没啥好说的,直接放到bean工厂map里面,上面xml的方式最终其实也是调用了该方法而已
3.8 初始化事件广播 initApplicationEventMulticaster 怎么去初始化?有就不管,没有就创建一个嘛,刚开始明显没有,所以创建了一个SimpleApplicationEventMulticaster,SimpleApplicationEventMulticaster是个啥?就是一个事件广播器,啥叫广播器?就是广播一个事件,所有的监听器都去响应这个事件,监听器就是ApplicationListener,注册监听器就是registerListeners做的事情
- 思考一下:为什么要去检查此时有没有事件广播器?去哪里检查?去bean工厂检查为什么要检查?因为我们可以在xml文件中自定义SimpleApplicationEventMulticaster,向下面这样,这样定义的广播器在bean工厂里面,所以要去检查一下 其实我们可以在xml中定义很多spring自己的需要的对象,比如上面的广播器,定义的都在bean工厂里面,所以你会看到很多地方都会在bean工厂里面先检查一下有没有已经定义好的
- 事件广播器的最佳实践是用线程池进行异步调用,看下SimpleApplicationEventMulticaster的multicastEvent方法,里面判断了如果有线程池就放到线程池里执行xml里面类似于这样 注解类似于这样(springboot)
- springboor广播器的使用请参考模块springboot-mybatis-plus里面的TestEvent.java
3.10 注册事件监听器 registerListeners 注册监听器,不是注册给上下文,是注册给广播器,getApplicationEventMulticaster拿到的就是事件广播器,是在initApplicationEventMulticaster中初始化的,说白了就是放在了事件广播器的map里面
也就是说,有事件产生的时候,广播器挨个通知所有的监听器,让他们执行相应的动作,怎么通知?一个for循环挨个执行下就好了
3.11 重点来了:初始化所有非懒加载的bean finishBeanFactoryInitialization 上面铺垫了这么久,现在终于可以开始初始化所有bean了,再次强调,是初始化所有非懒加载!!的bean,用递归的来初始化bean以及bean里面的依赖!
核心是反射,里面有一堆一堆的判断条件,还有条件很深的递归,跟代码很容易就晕了,下面演示了空构造方法,里面依赖有一个bean的实例化,即userService,userService里面依赖了userDao
- DefaultListableBeanFactory.preInstantiateSingletons:开始挨个实例化bean,是bean工厂在干这事for (String beanName : beanNames) { //这里就在挨个循环处理 … else { getBean(beanName); } }AbstractBeanFactory.doGetBean:凡是带do的方法都是实际干活儿的方法,doGetBean也不例外,注意这里藏着条件很深的递归,用大腿想想都知道,我要实例化的bean里面依赖另外未实例化的bean,那么我是不是得实例化到最深处?答案是肯定的AbstractBeanFactory.createBean:是定义在AbstractBeanFactory的空方法,子类自己去实现AbstractAutowireCapableBeanFactory.doCreateBean:这才是真正干活的方法,和下面的populateBean是平级的instanceWrapper = createBeanInstance(beanName, mbd, args); AbstractAutowireCapableBeanFactory.createBeanInstance:返回的是BeanWrapper,是实例化bean外面又包装了一层,这里主要是检查了构造方法// No special handling: simply use no-arg constructor. return instantiateBean(beanName, mbd); AbstractAutowireCapableBeanFactory.instantiateBean:用空构造方法实例化beanInstantiationStrategy.instantiate:顾名思义,用这种实例化策略来实例化bean,具体调用的是SimpleInstantiationStrategy.instantiateBeanUtils.instantiateClass:最终调到了这里,这只是一个工具方法,重点就在这里,这里在用反射!!return ctor.newInstance(argsWithDefaultValues); 方法定义是这样的,这一看就是用构造方法来实例化bean,这不就是反射么 ```java public static T instantiateClass(Constructor ctor, Object… args); 当然这并没有完,这才是构建了它自己,也就是说到这里userService才构建完毕,它里面还有依赖的bean,难道你不初始化??答案是肯定要AbstractAutowireCapableBeanFactory.populateBean:这里和上面的doCreateBean是平级的AbstractAutowireCapableBeanFactory.applyPropertyValues:将解析到的userDao应用到userServiceBeanDefinitionValueResolver.resolveValueIfNecessary:bean定义的解析器开始解析userDao了BeanDefinitionValueResolver.resolveReference: 重点来了,它又在调bean工厂的getBean方法,里面其实调用了doGetBean!!!开始形成递归了,这一步其实是在初始化userDao!bean = this.beanFactory.getBean(resolvedName);
protected void finishRefresh() {
// Clear context-level resource caches (such as ASM metadata from scanning).
clearResourceCaches();
// Initialize lifecycle processor for this context.
initLifecycleProcessor();
// Propagate refresh to lifecycle processor first.
getLifecycleProcessor().onRefresh();
// Publish the final event.
publishEvent(new ContextRefreshedEvent(this));
// Participate in LiveBeansView MBean, if active.
LiveBeansView.registerApplicationContext(this);
}
比如,可以做一些在容器刷新完成后的事件:参考ContextRefreshApplicationListener.java
3.13 清掉缓存 resetCommonCaches 这个就没啥好说的,不用的东西清理掉而已
protected void resetCommonCaches() {
ReflectionUtils.clearCache();
AnnotationUtils.clearCache();
ResolvableType.clearCache();
CachedIntrospectionResults.clearClassLoader(getClassLoader());
}
Spring IOC BeanPostProcessor是在哪里进行回调的? 最简单的办法就是写一个BeanPostProcessor打断点观察调用堆栈,参考com.spring.config.MyBeanPostProcessor
postProcessBeforeInitialization的调用堆栈
postProcessBeforeInitialization:10, MyBeanPostProcessor
applyBeanPostProcessorsBeforeInitialization:416, AbstractAutowireCapableBeanFactory
initializeBean:1788, AbstractAutowireCapableBeanFactory
doCreateBean:595, AbstractAutowireCapableBeanFactory
createBean:517, AbstractAutowireCapableBeanFactory
lambda$doGetBean$0:323, AbstractBeanFactory
getObject:-1, 690339675
getSingleton:226, DefaultSingletonBeanRegistry
doGetBean:321, AbstractBeanFactory
getBean:202, AbstractBeanFactory
preInstantiateSingletons:895, DefaultListableBeanFactory
finishBeanFactoryInitialization:878, AbstractApplicationContext
refresh:550, AbstractApplicationContext
postProcessAfterInitialization调用堆栈
postProcessAfterInitialization:17, MyBeanPostProcessor
applyBeanPostProcessorsAfterInitialization:431, AbstractAutowireCapableBeanFactory
initializeBean:1800, AbstractAutowireCapableBeanFactory
doCreateBean:595, AbstractAutowireCapableBeanFactory
createBean:517, AbstractAutowireCapableBeanFactory
lambda$doGetBean$0:323, AbstractBeanFactory
getObject:-1, 690339675
getSingleton:226, DefaultSingletonBeanRegistry
doGetBean:321, AbstractBeanFactory
getBean:202, AbstractBeanFactory
preInstantiateSingletons:895, DefaultListableBeanFactory
finishBeanFactoryInitialization:878, AbstractApplicationContext
refresh:550, AbstractApplicationContext
重点方法 通过观察堆栈,最后的公共调用堆栈为AbstractAutowireCapableBeanFactory.initializeBean,拿出来看看长啥样
看到了吧,在调用invokeInitMethods之前调用applyBeanPostProcessorsBeforeInitialization,之后调用applyBeanPostProcessorsAfterInitialization
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
...
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
} catch (Throwable ex) {...}if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
...
return wrappedBean;
}
需要注意的是,如果A依赖B,那么B的postProcessBeforeInitialization和postProcessAfterInitialization会先调用,然后B创建并返回,此时A的Before…和After…才会调用,也就是说,从最深层开始调用
总结
- Spring是怎么将这些bean初始化到IOC容器的呢?
- IOC容器具体是什么呢?
/** Cache of singleton objects: bean name --> bean instance */
private final Map singletonObjects = new ConcurrentHashMap(64);
代码清单
- UserDao与UserDaoImpl
public interface UserDao {List findUsers(int howMany);
}public class UserDaoImpl implements UserDao {
@Override
public List findUsers(int howMany) {
List list = new ArrayList<>();
Faker faker = new Faker(new Locale("zh-CN"));
for (int i = 0;
i < howMany;
i++) {
User user = new User();
user.setName(faker.name().fullName());
user.setAge(faker.number().numberBetween(0,100));
user.setPhone(faker.phoneNumber().cellPhone());
user.setLocation(faker.address().city());
list.add(user);
}
return list;
}
}
- UserService与UserServiceImpl
public interface UserService {List findUsers();
List findUsers(int howMany);
}public class UserServiceImpl implements UserService {private UserDao userDao;
/*如果是配置文件注入要使用setter*/
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}@Override
public List findUsers() {
return userDao.findUsers(10);
}@Override
public List findUsers(int howMany) {
return userDao.findUsers(howMany);
}}
- AwareTestService与AwareTestServiceImpl
public interface AwareTestService extends EnvironmentAware, EmbeddedValueResolverAware,ResourceLoaderAware,ApplicationEventPublisherAware,MessageSourceAware,ApplicationContextAware {
void test();
}/**
* spring框架提供了多个*Aware接口,用于辅助Spring Bean编程访问Spring容器。
* 通过实现这些接口,可以增强Spring Bean的功能,将一些特殊的spring内部bean暴露给业务应用。
*
*/
public class AwareTestServiceImpl implements AwareTestService {ApplicationContext applicationContext;
ApplicationEventPublisher applicationEventPublisher;
StringValueResolver stringValueResolver;
Environment environment;
MessageSource messageSource;
ResourceLoader resourceLoader;
public void test(){
System.out.println("Spring中的6大自动注入aware接口");
System.out.println(this.applicationContext.containsBean("awareTestService"));
System.out.println(this.environment.getProperty("java.home"));
System.out.println(this.stringValueResolver.resolveStringValue("${java.runtime.version}"));
System.out.println(this.resourceLoader.getResource("classpath:src/main/resources/ioc/services.xml"));
System.out.println(this.applicationEventPublisher);
System.out.println(this.messageSource.getMessage("Message", null, "not exist", Locale.JAPAN));
}@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
this.stringValueResolver = resolver;
}@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}@Override
public void setMessageSource(MessageSource messageSource) {
this.messageSource = messageSource;
}@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
}
- MyBeanPostProcessor
public class MyBeanPostProcessor implements BeanPostProcessor {@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化 before--实例化的bean对象之前:"+bean+"\t"+beanName);
return bean;
}@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化 after...实例化的bean对象之后:"+bean+"\t"+beanName);
return bean;
}
}
- User
public class User {
private String name;
private int age;
private String phone;
private String location;
...
}
推荐阅读
- Java|Java基础——数组
- 人工智能|干货!人体姿态估计与运动预测
- java简介|Java是什么(Java能用来干什么?)
- Java|规范的打印日志
- Linux|109 个实用 shell 脚本
- 程序员|【高级Java架构师系统学习】毕业一年萌新的Java大厂面经,最新整理
- Spring注解驱动第十讲--@Autowired使用
- =======j2ee|spring用注解实现注入的@resource,@autowired,@inject区别
- SqlServer|sql server的UPDLOCK、HOLDLOCK试验
- jvm|【JVM】JVM08(java内存模型解析[JMM])