前言

最近我在读Spring源码,还是有不少收获,打算近期把阅读的心得体会总结一下分享给大家,让大家也能够快速入手,希望对你会有所帮助。

我尽量用一些自己认为更好理解的方式,带大家一起感受一下Spring的魅力。

我们先从最最最基础的Spring IOC开始。

需要注意的是,Spring系列文章源码的版本是:5.3.23。

1. 什么是Spring IOC?

IOC是InversionofControl的缩写,即控制反转。

我们之前是怎么创建对象的,大概是这样的吧:

Useruser=newUser();
user.setName("苏三");


Rolerole=newRole();
role.setId(123);
role.setName("角色");
user.setRole(role);

在我们的业务代码中,通过new关键字主动创建对象,然后就可以调用该对象的方法了。

这种创建对象的方式,是开发者控制的。

如果user和role都是单例对象,创建和初始化对象,在整个生命周期中只有一次。

既然如此,对象的创建和初始化,有没有办法让框架代码自动实现呢?

将创建对象的方式,反转给框架控制,不由开发者控制,这样更智能化一些。

这其实是Spring IOC的控制反转。

其实Spring IOC不只是包含控制反转的功能,它的功能更强大,还能帮大家完成各个对象依赖关系的字段注入。

这就是大家经常说的DI(Dependency Injection),即依赖注入。

上面的那个例子中user对象的初始化,需要依赖于role对象,需要它先初始化。

这里用的:

user.setRole(role);

手动设置的依赖,其实Spring可以帮我们自动完成依赖的注入。

问题来了,Spring是如何管理对象的呢?

2. BeanFactory

如果你经常使用Spring,肯定听过BeanFactory,它是一个顶层的接口,用来创建Spring容器的。

在Spring中的对象,有个非常特别的名字,叫做:Bean。

在Java中万事万物皆是对象,而在Spring中万事万物皆是Bean。

BeanFactory见名之意,是Bean的工厂,用来创建和管理Bean对象的。

publicinterfaceBeanFactory{


StringFACTORY_BEAN_PREFIX="&";
ObjectgetBean(Stringname)throwsBeansException;


<T>TgetBean(Stringname,Class<T>requiredType)throwsBeansException;

ObjectgetBean(Stringname,Object...args)throwsBeansException;


<T>TgetBean(Class<T>requiredType)throwsBeansException;


<T>TgetBean(Class<T>requiredType,Object...args)throwsBeansException;


<T>ObjectProvider<T>getBeanProvider(Class<T>requiredType);


<T>ObjectProvider<T>getBeanProvider(ResolvableTyperequiredType);


booleancontainsBean(Stringname);


booleanisSingleton(Stringname)throwsNoSuchBeanDefinitionException;


booleanisPrototype(Stringname)throwsNoSuchBeanDefinitionException;


booleanisTypeMatch(Stringname,ResolvableTypetypeToMatch)throwsNoSuchBeanDefinitionException;


booleanisTypeMatch(Stringname,Class<?>typeToMatch)throwsNoSuchBeanDefinitionException;


@Nullable
Class<?>getType(Stringname)throwsNoSuchBeanDefinitionException;


@Nullable
Class<?>getType(Stringname,booleanallowFactoryBeanInit)throwsNoSuchBeanDefinitionException;


String[]getAliases(Stringname);
}

BeanFactory接口中定义了我们耳熟能详的方法,这些想法我们经常会用到。

但这些只是Spring IOC最基础的功能,ApplicationContext接口的出现极大的丰富了BeanFactory接口的功能。

image

ApplicationContext接口继承了BeanFactory接口功能,并且增加了:资源文件的处理、事件处理、国际化等功能。

目前Spring容器,更多的是通过ApplicationContext接口的实现类取创建和初始化的。image

我们见得比较多的实现类有:

  1. FileSystemXmlApplicationContext
  2. ClassPathXmlApplicationContext
  3. AnnotationConfigWebApplicationContext

其实这些类都殊途同归,最终都会调用refresh方法,我们以ClassPathXmlApplicationContext类为例:

publicClassPathXmlApplicationContext(
String[]configLocations,booleanrefresh,@NullableApplicationContextparent)
throwsBeansException{


super(parent);
setConfigLocations(configLocations);
if(refresh){
refresh();
}
}

它的构造方法最终会调用refresh方法,该方法是Spring容器的关键方法。

顺便说一下,上面的setConfigLocations方法主要是解析配置文件的路径的。

3. refresh方法

refresh方法会去解析配置文件中的各种标签,已经解析各种Spring的注解,创建Spring容器,创建和初始化各种bean。

refresh方法是Spring IOC的入口方法,后面大家想阅读Spring的源码,可以直接从该方法开始。

该方法是AbstractApplicationContext类的方法。

主要代码如下:

publicvoidrefresh()throwsBeansException,IllegalStateException{
synchronized(this.startupShutdownMonitor){
StartupStepcontextRefresh=this.applicationStartup.start("spring.context.refresh");


//准备环境,初始化placeholder
prepareRefresh();


//解析xml,生成并注册BeanDefinition
ConfigurableListableBeanFactorybeanFactory=obtainFreshBeanFactory();


//准备BeanFactory容器参数
prepareBeanFactory(beanFactory);


try{
//钩子方法,添加BeanFactoryPostProcessor
postProcessBeanFactory(beanFactory);


StartupStepbeanPostProcess=this.applicationStartup.start("spring.context.beans.post-process");
//调用BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(beanFactory);


//注册BeanPostProcessor
registerBeanPostProcessors(beanFactory);
beanPostProcess.end();


//支持国际化
initMessageSource();


//初始化广播事件
initApplicationEventMulticaster();


//钩子方法,启动web容器
onRefresh();


//注册事件监听器
registerListeners();


//初始化单例bean
finishBeanFactoryInitialization(beanFactory);


//广播消息
finishRefresh();
}


catch(BeansExceptionex){
//销毁Spring容器
destroyBeans();


//重置状态
cancelRefresh(ex);
throwex;
}


finally{
//重置常用缓存
resetCommonCaches();
contextRefresh.end();
}
}
}

下面用一张图,以便于大家更好的理解。

image

好了,今天就聊到这里,后面会将refresh方法中的关键代码都跟大家分享一下,我们下期再见。

最后修改:2026 年 06 月 05 日
如果觉得我的文章对你有用,请随意赞赏