Spring源码分析(12)——Spring常用调试断点和方法

在分析Spring相关源码时,或者优化Spring启动过程时,可能能够用到的一些调试的断点的位置。

容器的创建

  • Spring

ApplicationContext容器类型为:XmlWebApplicationContext,来自web.xml文件中配置的ContextLoaderListener,默认类型配置在ContextLoader.properties中

BeanFactory容器类型为:DefaultListableBeanFactory

断点位置:

ContextLoader.java
1
protected WebApplicationContext createWebApplicationContext(ServletContext sc) {}
  • SpringMVC

ApplicationContext容器类型为:XmlWebApplicationContext,来自web.xml文件中配置的DispatcherServlet

BeanFactory容器类型为:DefaultListableBeanFactory

断点位置:

FrameworkServlet.java
1
protected WebApplicationContext initWebApplicationContext() {}
  • SpringBoot

ApplicationContext容器类型为:

SpringBoot 1.x : AnnotationConfigEmbeddedWebApplicationContext

SpringBoot 2.x : AnnotationConfigServletWebServerApplicationContext

BeanFactory容器类型为:DefaultListableBeanFactory

断点位置:

SpringApplication.java
1
protected ConfigurableApplicationContext createApplicationContext() {}

看容器中所有的Bean

由于在AbstractApplicationContext的finishBeanFactoryInitialization()方法中会初始化剩余的bean,因此在这一步的下一行finishRefresh()打断点就能看到所有的bean了。

AbstractApplicationContext.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
prepareRefresh();
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
prepareBeanFactory(beanFactory);
try {
postProcessBeanFactory(beanFactory);
invokeBeanFactoryPostProcessors(beanFactory);
registerBeanPostProcessors(beanFactory);
initMessageSource();
initApplicationEventMulticaster();
onRefresh();
registerListeners();
// 初始化剩余的bean
finishBeanFactoryInitialization(beanFactory);
// 在这一步打断点,查看beanFactory变量中的值
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
destroyBeans();
cancelRefresh(ex);
throw ex;
}
finally {
resetCommonCaches();
}
}
}

在beanFactory变量中,最重要的两个变量是“singletonObjects”和“beanDefinitionMap”。

singletonObjects保存的是整个Spring容器中 id -> 实例 的键值对,是最终的全体单例保存的地方。

beanDefinitionMap保存的是 id -> bean定义 的键值对,保存了Spring扫描到的所有Bean定义。

重复Bean和Bean的覆盖

同一个xml文件中定义了id相同的bean时,Spring会启动失败,并抛异常。这是在xml文件读取时完成的,同一个空间中不允许相同的id。

BeanDefinitionParserDelegate.java
1
protected void checkNameUniqueness(String beanName, List<String> aliases, Element beanElement){}

不同的xml文件中定义了名字一样的bean的时候,后被扫描到的bean会将先扫描到的bean覆盖掉,并输出以下日志:

2019-04-12 16:50:32.784 main [INFO] o.s.b.f.s.DefaultListableBeanFactory (DefaultListableBeanFactory.java:828 Overriding bean definition for bean ‘ExceptionDeclaration’ with a different definition: replacing [Genericbean: class []; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0;autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null;destroyMethodName=null; defined in URL []] with [Root bean: class [null]; scope=; abstract=false;lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false;factoryBeanName=enableThriftServerPublish.ThriftServerPublishConfiguration;factoryMethodName=ExceptionDeclaration; initMethodName=null; destroyMethodName=(inferred); defined in classpath resource []]

覆盖的操作是在bean注册时完成的,断点位置:

DefaultListableBeanFactory.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
if (oldBeanDefinition != null) {
// 不允许覆盖直接抛异常
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionStoreException();
}
else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
if (this.logger.isWarnEnabled()) {
this.logger.warn();
}
}
// 如果两个类不相等,就会覆盖
else if (!beanDefinition.equals(oldBeanDefinition)) {
if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
// 相同的bean也会覆盖
if (this.logger.isDebugEnabled()) {
this.logger.debug("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
this.beanDefinitionMap.put(beanName, beanDefinition);
}
}
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×