前言:Spring是我们日常Java web开发必不可少的框架,有着很优秀的设计思想,在熟练使用它的基础上,很有必要了解其源码,Spring主要有七大模块,分别为(IOC容器)Spring Core,应用上下文(Spring Context),Spring面向切面编程(Spring AOP),JDBC和DAO模块(Spring DAO),对象实体映射(Spring ORM),Web模块(Spring Web),MVC模块(Spring Web MVC)。最核心的模块为IOC和AOP,也是面试常问及的内容,本文将从比较宏观的角度分析IOC的源码,不会太深入一些细节,希望能起到抛砖引玉的作用。
IOC也就是控制反转,让对象的创建的权力反转给IOC容器,具体通过Spring配置来创建对象,它的底层原理包括xml配置文件,dom4j解析,工厂设计模式,反射等等。使用Spring IOC容器,可以通过使用注解或xml配置的方式,Spring容器在启动的时候,先会从xml配置或者注解中保存所有注册进来的Bean定义信息。很经典的xml方式配置bean方式如下
<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="boss" class="com.baobaotao.simple.Boss"></bean>
</beans>
由于现在普遍是Spring Boot项目,xml配置的方式也渐渐被注解方式取代了,注解方式更加方便,避免了xml文件一些繁琐的配置,因此分析Spring源码过程中也是以注解方式,但是原理是一样的,配置xml只是多了一层解析xml文件罢了。
OK,我们先看看bean的创建。这是主类
public class SpringIOCTest {
@SuppressWarnings("resource")
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(IOCConfig.class);
// 获取Person bean
Person bean = applicationContext.getBean(Person.class);
System.out.println(bean.toString());
}
}
配置类:
@Configuration //告诉Spring这是一个配置类
public class IOCConfig {
//给容器中注册一个Bean
@Bean
public Person person(){
return new Person("lisi", 20);
}
}
这就配置好一个Person类 bean,是不是很简单!AnnotationConfigApplicationContext是注解的Spring上下文类,加载配置类,就可以完成配置,运行主类,就可以从Spring上下文中获取到Person类对象!下面就分析下整个过程的原理。
进入AnnotationConfigApplicationContext构造方法,可以看到有三个方法,this()是调用无参构造函数,初始化读取Bean定义信息的reader以及Bean定义包扫描对象,可以扫描一些@Componet,@Service等注解标注的组件,register方法就是注册配置类,关键是下面refresh()函数
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// 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();
}
}
}
下面逐一分析下refresh函数里面做的事情
- prepareRefresh()函数是刷新前的预处理,里面做的工作主要是初始化一些属性设置;子类自定义个性化的属性设置方法;检验属性的合法等等
- obtainFreshBeanFactory()的作用是获取BeanFactory,Spring创建Bean可以直接Bean相关参数创建,也可以通过BeanFactory的getObject方法获取Bean
- prepareBeanFactory(beanFactory);这里是BeanFactory的预准备工作(BeanFactory进行一些设置),如:
1)设置BeanFactory的类加载器、支持表达式解析器
2)添加部分BeanPostProcessor。BeanPostProcessor的作用是很强大的,它能在Bean初始化的前后做一些工作,例如ApplicationContextAwareProcessor的工作就是在其方法postProcessBeforeInitialization()中对继承自ApplicationContextAware的bean进行处理,调用其setApplicationContext将Spring上下文注入。因此我们可以简单写一个实现ApplicationContextAware接口类重写setApplicationContext方法就可以得到Spring上下文来做一些事情了。
4. postProcessBeanFactory(beanFactory)是BeanFactory准备工作完成之后进行的设置处理工作。子类可以通过重写这个方法来在BeanFactory创建并预准备完成以后做进一步的设置操作,如下面的MyBeanFactoryPostProcessor
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("MyBeanFactoryPostProcessor...postProcessBeanFactory...");
int count = beanFactory.getBeanDefinitionCount();
String[] names = beanFactory.getBeanDefinitionNames();
System.out.println("当前BeanFactory中有"+count+" 个Bean");
System.out.println(Arrays.asList(names));
}
}
5. invokeBeanFactoryPostProcessor(beanFactory)为执行BeanFactoryPostProcessor的方法。BeanFactoryPostProcessor为BeanFactory的后置处理器,是在BeanFactory初始化之后执行的。
6. registerBeanPostProcessors(beanFactory)这步是注册BeanPostProcessor,注意这是Bean的后置处理器,区别是BeanFactoryPostProcessor。两者针对的对象不一样,前者是针对Bean创建对象的方式,后者则是BeanFactory创建Bean的方式(Spring通过BeanFactory的getObject的方法获取Bean对象).不同接口类型的BeanPostProcessor;在Bean创建前后的执行时机是不一样的
1)、获取所有的 BeanPostProcessor;后置处理器都默认可以通过PriorityOrdered、Ordered接口来执行优先级
2)、先注册PriorityOrdered优先级接口的BeanPostProcessor;把每一个BeanPostProcessor;添加到BeanFactory中
beanFactory.addBeanPostProcessor(postProcessor);
3)、再注册Ordered接口的
4)、最后注册没有实现任何优先级接口的
5)、最终注册MergedBeanDefinitionPostProcessor;
6)、注册一个ApplicationListenerDetector;来在Bean创建完成后检查是否是ApplicationListener,如果是
applicationContext.addApplicationListener((ApplicationListener<?>) bean)
7. initMessageSource()主要是初始化MessageSource组件,来做国际化功能、消息绑定、消息解析
8. onRefresh()方法是空的,设计的目的主要是给子类重写,在容器刷新的时候可以自定义逻辑
9. finishBeanFactoryInitialization(beanFactory):初始化所有剩下的单实例Bean 。
具体过程如下:
1、beanFactory.preInstantiateSingletons();初始化后剩下的单实例bean
1)、获取容器中的所有Bean,依次进行初始化和创建对象
2)、获取Bean的定义信息;RootBeanDefinition
3)、Bean不是抽象的,是单实例的,是懒加载;
1)、判断是否是FactoryBean;是否是实现FactoryBean接口的Bean;
2)、不是工厂Bean。利用getBean(beanName);创建对象
0、getBean(beanName); ioc.getBean();
1、doGetBean(name, null, null, false);
2、先获取缓存中保存的单实例Bean。如果能获取到说明这个Bean之前被创建过(所有创建过的单实例Bean都会被缓存起来)
从private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);获取的
3、缓存中获取不到,开始Bean的创建对象流程;
4、标记当前bean已经被创建
5、获取Bean的定义信息;
6、【获取当前Bean依赖的其他Bean;如果有按照getBean()把依赖的Bean先创建出来;】
7、启动单实例Bean的创建流程;
1)、createBean(beanName, mbd, args);
2)、Object bean = resolveBeforeInstantiation(beanName, mbdToUse);让BeanPostProcessor先拦截返回代理对象;
【InstantiationAwareBeanPostProcessor】:提前执行;
先触发:postProcessBeforeInstantiation();
如果有返回值:触发postProcessAfterInitialization();
3)、如果前面的InstantiationAwareBeanPostProcessor没有返回代理对象;调用4)
4)、Object beanInstance = doCreateBean(beanName, mbdToUse, args);创建Bean
1)、【创建Bean实例】;createBeanInstance(beanName, mbd, args);
利用工厂方法或者对象的构造器创建出Bean实例;
2)、applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
调用MergedBeanDefinitionPostProcessor的postProcessMergedBeanDefinition(mbd, beanType, beanName);
3)、【Bean属性赋值】populateBean(beanName, mbd, instanceWrapper);
赋值之前:
1)、拿到InstantiationAwareBeanPostProcessor后置处理器;
postProcessAfterInstantiation();
2)、拿到InstantiationAwareBeanPostProcessor后置处理器;
postProcessPropertyValues();
=====赋值之前:===
3)、应用Bean属性的值;为属性利用setter方法等进行赋值;
applyPropertyValues(beanName, mbd, bw, pvs);
4)、【Bean初始化】initializeBean(beanName, exposedObject, mbd);
1)、【执行Aware接口方法】invokeAwareMethods(beanName, bean);执行xxxAware接口的方法
BeanNameAware\BeanClassLoaderAware\BeanFactoryAware
2)、【执行后置处理器初始化之前】applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
BeanPostProcessor.postProcessBeforeInitialization();
3)、【执行初始化方法】invokeInitMethods(beanName, wrappedBean, mbd);
1)、是否是InitializingBean接口的实现;执行接口规定的初始化;
2)、是否自定义初始化方法;
4)、【执行后置处理器初始化之后】applyBeanPostProcessorsAfterInitialization
BeanPostProcessor.postProcessAfterInitialization();
5)、注册Bean的销毁方法;
5)、将创建的Bean添加到缓存中singletonObjects;
ioc容器就是这些Map;很多的Map里面保存了单实例Bean,环境信息。。。。;
所有Bean都利用getBean创建完成以后;
检查所有的Bean是否是SmartInitializingSingleton接口的;如果是;就执行afterSingletonsInstantiated();
10. finishRefresh()这一步就是完成BeanFactory的初始化创建工作,IOC容器到这里就创建完成了。
总结:
1. Spring容器在启动的时候,先会保存所有注册进来的Bean定义信息,Bean定义信息有两大来源,一个就是xml配置了,就是本文刚开始提到的Bean配置方式,另一种就是注解注册Bean!就是平常我们开发常用到的@Service、@Componet、@Bean等等注解
2.Spring容器会在合适的时机创建这些Bean,创建好就保存在容器中,如果是单例的Bean会缓存下来。最后到了统一创建剩下的Bean的时候,就是前面所提到的方法:finishBeanFactoryInitialization()
3.后置处理器:BeanProcessor非常重要和强大,每一个Bean创建完成,都会使用各种后置处理器进行处理,从而达到增强Bean的功能,Spring另一个强大的模块AOP面向切面编程也依靠到了BeanProcessor来实现
4.上面其实还有某一两个函数没有提到,比如initApplicationEventMulticaster(),这个函数涉及到Spring事件驱动模型,来进行事件的监听,派发。