手把手带你看spring的配置创建、注入以及获取bean。
看源码最好的方式就是定义一个最最基本的流程,从开始debug到你认为懂了为止。
bean的配置
最基本的spring配置是将bean配置在spring的配置文件中,该配置文件还可以配置spring的配置属性,虽然标签不是,但是spring会将其注入到指定的类中,因此不论标签如何,spring都会将配置文件中的属性转化成类属性,最终创建对应的对象。有的朋友可能已经注意到了:配置都是放在
标签中的。
bean的生成与注入
启动spring的入口之一就是创建 ClassPathXmlApplicationContext 对象:
//创建Spring容器的对象:ApplicationContext的实现类 ----> ClassPathXmlApplicationContext
//ApplicationContext就是表示Spring容器,我们可以通过容器获取对象
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
向下看之前不妨看一下该类的UML关系:
创建ClassPathXmlApplicationContext对象时就能看到整个spring创建对象的流程:
真正调用的是这里:
这里的setConfigLocations方法只是将传入的配置文件名注入到本类的configLocations字符串数组变量中。
真正的流程是在refresh方法中,该方法的实现其实是在父类AbstractApplicationContext中:
将一些与主流程相关较小的代码剔除后如下:
public void refresh() throws BeansException, IllegalStateException {
//在方法内对别的对象加锁,使得锁最小化。
synchronized (this.startupShutdownMonitor) {
//第一步就是创建bean的容器
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
prepareBeanFactory(beanFactory);
try {
postProcessBeanFactory(beanFactory);
invokeBeanFactoryPostProcessors(beanFactory);
registerBeanPostProcessors(beanFactory);
finishBeanFactoryInitialization(beanFactory);
} catch (BeansException ex) {...}
finally {
resetCommonCaches();
contextRefresh.end();
}
}
}
逐步解析:
obtainFreshBeanFactory():
其中:refreshBeanFactory() 才是创建beanFactory的关键:其在 AbstractApplicationContext 类中是抽象方法,需要子类实现,通常调用的是 AbstractRefreshableApplicationContext 类。
其中 loadBeanDefinitions(beanFactory) 是最主要的,在子类 AbstractXmlApplicationContext 中
loadBeanDefinitions(beanFactory) 创建了 XmlBeanDefinitionReader 对象。该类封装了读配置文件的逻辑。随后就是调用 XmlBeanDefinitionReader的方法 loadBeanDefinitions :
这个方法在其父类 AbstractBeanDefinitionReader 中实现:
AbstractBeanDefinitionReader 将字符串类型的配置文件名转化为 Resource 对象,Resource是个接口,继承了InputStreamSource,Spring中对于文件的读取类都需实现该接口。
而通过Resource加载类的方法是在子类 XmlBeanDefinitionReader 实现:
接着就是创建但是真正读配置文件的抽象类:BeanDefinitionDocumentReader。
registerBeanDefinitions 在子类 DefaultBeanDefinitionDocumentReader 中实现:
然后挨个解析每一个标签
这里的 BeanDefinitionHolder 要注意,这个就是解析bean
标签的生成对象,可以看出,bean
标签里设置的属性都在该对象中,没有配置的属性会采用默认值(这也解释了spring中创建的对象默认是懒加载的)。
随后将对象名和类定义放入【DefaultListableBeanFactory】
的 beanDefinitionMap 中。
而事实上,后续的流程都是针对 DefaultListableBeanFactory类的。
就此,spring中一个完整的配置文件中bean的解析、注册就结束了!!!
prepareBeanFactory(beanFactory)
该方法就只是为Spring的BeanFactory赋值。比如后置处理器,添加一些Spring内部对象等:
/**
* 配置BeanFactory的一些上下文属性,比如上下文类加载器和后置处理器
* @param 需要赋值的beanFactory
*/
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
//使用调用类的类加载器
beanFactory.setBeanClassLoader(getClassLoader());
if (!shouldIgnoreSpel) {
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
}
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// Configure the bean factory with context callbacks.
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
beanFactory.ignoreDependencyInterface(ApplicationStartupAware.class);
// BeanFactory interface not registered as resolvable type in a plain factory.
// MessageSource registered (and found for autowiring) as a bean.
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// Register early post-processor for detecting inner beans as ApplicationListeners.
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// Detect a LoadTimeWeaver and prepare for weaving, if found.
if (!NativeDetector.inNativeImage() && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
// 注册默认的环境类对象
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
if (!beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) {
beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup());
}
}
invokeBeanFactoryPostProcessors(beanFactory):
该方法主要是加载和实例化 BeanFactory 后置处理器(所有实现了 BeanFactoryPostProcessor
接口的类)。后置处理器可以在 Bean 实例化、属性填充、初始化和销毁等不同的阶段对 Bean 进行自定义的处理和增强。典型的后处理器就是org.mybatis.spring.mapper.MapperScannerConfigurer
,该类将指定的mapper接口注册到mybatis
的Configuration
类的MapperRegistry
属性中。
registerBeanPostProcessors(beanFactory):
主要是将上一步实例化的后置处理器对象添加到 beanFactory 的 beanPostProcessors 变量中。
finishBeanFactoryInitialization(beanFactory):
从方法名也能看出该方法是最终的一步:初始化所有的单例模式,所有的非懒加载的类。该方法内封装的其实就是之前构建的 ConfigurableListableBeanFactory 接口实现类的方法,spring中该接口的实现类用的是 DefaultListableBeanFactory
可以看出,初始化类的时候是会根据类是否是工厂类而作出额外的初始化,最重要的还是 getBean方法。
该方法是 ClassPathXmlApplication 的父类 AbstractApplicationContext 实现的:
而 doGetBean 也是 AbstractBeanFactory 实现的:
protected T doGetBean(
String name, @Nullable Class requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
String beanName = transformedBeanName(name);
Object beanInstance;
// 看看有无该类对象的缓存,有则直接返回
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}else {
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// 如果有父类的BeanFactory对象则调用父类BeanFactory独享的doGetBean方法。
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
.tag("beanName", name);
try {
if (requiredType != null) {
beanCreation.tag("beanType", requiredType::toString);
}
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// 先初始化要初始化对象依赖的对象,其实就是递归调用getBean。
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// 单例对象的初始化
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
//原型模式对象的创建
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
//Spring2.0之后又引入了另外三种scope类型:request、session、global session类型
//只能在只能在Web应用中使用,若只是后台进程的话则不会走该分支。
String scopeName = mbd.getScope();
if (!StringUtils.hasLength(scopeName)) {
throw new IllegalStateException("No scope name defined for bean '" + beanName + "'");
}
Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new ScopeNotActiveException(beanName, scopeName, ex);
}
}
}
catch (BeansException ex) {
beanCreation.tag("exception", ex.getClass().toString());
beanCreation.tag("message", String.valueOf(ex.getMessage()));
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
finally {
beanCreation.end();
}
}
return adaptBeanInstance(name, beanInstance, requiredType);
}
doGetBean 方法是先看看该对象是否已经初始化,如果没有在创建并初始化,值得注意的是,其是先创建并初始化当前要创建的对象的依赖(还是调用doGetbean),最后再根据对象类型分开创建,但是核心是调用 父类 AbstractAutowireCapableBeanFactory 的 createBean 方法。
createBeanInstance则很有意思,其是先判断是否由指定工厂创建,再有无注册的构造方法,最后才会通过反射获取该类的构造方法构造对象。
instantiate方法在 SimpleInstantiationStrategy类中。
而 BeanUtil.instantiateClass方法则是封装的的通过构造器获取对象。
由此,一个对象就被创建结束,而后虽然会对该对象进行一系列封装,但是归根结底,spring的bean创建还是上述这些过程。
bean的获取
其实通过 ClassPathXmlApplicationContext 对象获取指定类的对象的 getBean 方法其实就是第5步中的方法,对于非懒加载类对象就可以直接获取,而懒加载类的对象则在此刻构建。
最后再附上一张用到的UML图: