spring4,2024Java进阶者的新篇章

  • @see #initBeanDefinitionReader

  • @see #loadBeanDefinitions

*/

@Override

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {

// Create a new XmlBeanDefinitionReader for the given BeanFactory.

XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

// Configure the bean definition reader with this context’s

// resource loading environment.

beanDefinitionReader.setEnvironment(this.getEnvironment());

beanDefinitionReader.setResourceLoader(this);

beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

// Allow a subclass to provide custom initialization of the reader,

// then proceed with actually loading the bean definitions.

initBeanDefinitionReader(beanDefinitionReader);

loadBeanDefinitions(beanDefinitionReader);

}

以上代码可见,加载bean的定义是通过XmlBeanDefinitionReader 来完成的,重点关注loadBeanDefinitions方法:

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {

Resource[] configResources = getConfigResources();

if (configResources != null) {

reader.loadBeanDefinitions(configResources);

}

String[] configLocations = getConfigLocations();

if (configLocations != null) {

reader.loadBeanDefinitions(configLocations);

}

}

上述代码中的getConfigResources()和getConfigLocations(),究竟哪个会返回值有效数据呢?这就要去看ClassPathXmlApplicationContext的构造方法了:

//这个方法设置的是configLocations

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)

throws BeansException {

super(parent);

setConfigLocations(configLocations);

if (refresh) {

refresh();

}

}

//这个方法设置的是这个方法设置的是configResources

public ClassPathXmlApplicationContext(String[] paths, Class<?> clazz, ApplicationContext parent)

throws BeansException {

super(parent);

Assert.notNull(paths, “Path array must not be null”);

Assert.notNull(clazz, “Class argument must not be null”);

this.configResources = new Resource[paths.length];

for (int i = 0; i < paths.length; i++) {

this.configResources[i] = new ClassPathResource(paths[i], clazz);

}

refresh();

}

因此,到底是configLocations 还是configResources ,和我们使用哪个构造方法来实例化applicationContext对象有关;

  1. 如果我们实例化applicationContext对象的方式是new ClassPathXmlApplicationContext(“applicationContext.xml”),那么setConfigLocations方法就会被调用,因此loadBeanDefinitions方法内部,实际执行的代码如下:

String[] configLocations = getConfigLocations();

if (configLocations != null) {

reader.loadBeanDefinitions(configLocations);

}

  1. 现在可以来看AbstractBeanDefinitionReader类的loadBeanDefinitions(String… locations)方法了:

public int loadBeanDefinitions(String… locations) throws BeanDefinitionStoreException {

Assert.notNull(locations, “Location array must not be null”);

int counter = 0;

for (String location : locations) {

counter += loadBeanDefinitions(location);

}

return counter;

}

展开上面for循环中调用的方法:

public int loadBeanDefinitions(String location, Set actualResources) throws BeanDefinitionStoreException {

ResourceLoader resourceLoader = getResourceLoader();

if (resourceLoader == null) {

throw new BeanDefinitionStoreException(

“Cannot import bean definitions from location [” + location + “]: no ResourceLoader available”);

}

if (resourceLoader instanceof ResourcePatternResolver) {

// Resource pattern matching available.

try {

Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);

int loadCount = loadBeanDefinitions(resources);

if (actualResources != null) {

for (Resource resource : resources) {

actualResources.add(resource);

}

}

if (logger.isDebugEnabled()) {

logger.debug(“Loaded " + loadCount + " bean definitions from location pattern [” + location + “]”);

}

return loadCount;

}

catch (IOException ex) {

throw new BeanDefinitionStoreException(

“Could not resolve bean definition resource pattern [” + location + “]”, ex);

}

}

else {

// Can only load single resources by absolute URL.

Resource resource = resourceLoader.getResource(location);

int loadCount = loadBeanDefinitions(resource);

if (actualResources != null) {

actualResources.add(resource);

}

if (logger.isDebugEnabled()) {

logger.debug(“Loaded " + loadCount + " bean definitions from location [” + location + “]”);

}

return loadCount;

}

}

以上方法中,首先要记得resourceLoader是ClassPathXmlApplicationContext(beanDefinitionReader.setResourceLoader(this)这行代码),所有resourceLoader.getResource(location)这行代码最终会调用PathMatchingResourcePatternResolver类的getResources(String locationPattern)方法得到bean有关的Resource对象;得到Resource对象后,接着会调用loadBeanDefinitions(Resource… resources)方法来加载bean的定义了,最终是调用XmlBeanDefinitionReader.loadBeanDefinitions(EncodedResource encodedResource)方法:

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {

Assert.notNull(encodedResource, “EncodedResource must not be null”);

if (logger.isInfoEnabled()) {

logger.info("Loading XML bean definitions from " + encodedResource.getResource());

}

Set currentResources = this.resourcesCurrentlyBeingLoaded.get();

if (currentResources == null) {

currentResources = new HashSet(4);

this.resourcesCurrentlyBeingLoaded.set(currentResources);

}

if (!currentResources.add(encodedResource)) {

throw new BeanDefinitionStoreException(

“Detected cyclic loading of " + encodedResource + " - check your import definitions!”);

}

try {

InputStream inputStream = encodedResource.getResource().getInputStream();

try {

InputSource inputSource = new InputSource(inputStream);

if (encodedResource.getEncoding() != null) {

inputSource.setEncoding(encodedResource.getEncoding());

}

return doLoadBeanDefinitions(inputSource, encodedResource.getResource());

}

finally {

inputStream.close();

}

}

catch (IOException ex) {

throw new BeanDefinitionStoreException(

"IOException parsing XML document from " + encodedResource.getResource(), ex);

}

finally {

currentResources.remove(encodedResource);

if (currentResources.isEmpty()) {

this.resourcesCurrentlyBeingLoaded.remove();

}

}

}

上述代码可见,重要的是通过Resource对象得到InputStream,再调用doLoadBeanDefinitions方法:

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)

throws BeanDefinitionStoreException {

try {

Document doc = doLoadDocument(inputSource, resource);

return registerBeanDefinitions(doc, resource);

}

上面是加载bean定义的关键代码:先制作Document对象,再调用registerBeanDefinitions方法,最终会将每个bean的定义放入DefaultListableBeanFactory的beanDefinitionMap中,详细的堆栈如下图:

完成了bean定义的注册,可以回到AbstractRefreshableApplicationContext.refreshBeanFactory方法了,看看loadBeanDefinitions(beanFactory)之后的代码:

synchronized (this.beanFactoryMonitor) {

this.beanFactory = beanFactory;

}

至此,refreshBeanFactory方法分析完毕,该方法所做的事情:把xml文件中的bean定义被解析后,存放在DefaultListableBeanFactory的beanDefinitionMap中;

现在回到主线的AbstractApplicationContext.refresh()方法内,obtainFreshBeanFactory()我们已经分析完毕,所有bean定义都被存放在beanFactory这个临时变量对应的实例中;

prepareBeanFactory

接下来是prepareBeanFactory(beanFactory),看一下此方法的源码:

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {

//设置类加载器

beanFactory.setBeanClassLoader(getClassLoader());

//设置解析器,用于解析bean的定义中出现的Spel表达式表达式

beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));

//设置一个注册接口,该接口只有一个方法registerCustomEditors,用来设置自定义的转换器

beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

// 部署一个bean的后置处理器ApplicationContextAwareProcessor,用于将spring的环境信息注入到实例化的bean之中

beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

//bean在初始化的时候,如果有属性的类型为ResourceLoaderAware,则该属性不会被依赖注入

beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);

beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);

beanFactory.ignoreDependencyInterface(MessageSourceAware.class);

beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

beanFactory.ignoreDependencyInterface(EnvironmentAware.class);

// BeanFactory interface not registered as resolvable type in a plain factory.

// MessageSource registered (and found for autowiring) as a bean.

//bean如果有个属性的类型为BeanFactory.class,那么该属性会被设置为beanFactory

beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);

beanFactory.registerResolvableDependency(ResourceLoader.class, this);

beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);

beanFactory.registerResolvableDependency(ApplicationContext.class, this);

// Detect a LoadTimeWeaver and prepare for weaving, if found.

if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {

// 部署一个bean的后置处理器ApplicationContextAwareProcessor,用于AOP静态代理相关的处理

beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));

// Set a temporary ClassLoader for type matching.

beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));

}

// Register default environment beans.

if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {

//注册一个bean

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());

}

}

上述代码中有以下几点需要注意:

  1. beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())),此方法要配合AbstractBeanFactory.registerCustomEditors方法一起看更好理解:addPropertyEditorRegistrar方法向propertyEditorRegistrars属性中放入了一个registrar,之后调用registerCustomEditors方法的时候,会用到propertyEditorRegistrars中的registrar,调用这些registrar的registerCustomEditors方法,完成自定义的转换器的设置;

  2. beanFactory.addBeanPostProcessor方法用来注入后置处理器,在bean实例被创建后,初始化方法被执行的前后,后置处理器的postProcessBeforeInitialization、postProcessAfterInitialization这两个方法会分别被调用;

  3. beanFactory.ignoreDependencyInterface设置了依赖注入时要忽略的接口,例如bean有个属性类型是ResourceLoaderAware,那么该属性不会被注入ResourceLoaderAware类型的实例;

  4. beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory)是特殊设置,如果一个bean有个属性的类型是BeanFactory,那么该属性会被设置为beanFactory这个实例;

总的来说prepareBeanFactory方法就是为beanFactory做一些设置工作,传入一些后面会用到的参数和工具类,再在spring容器中创建一些bean;

postProcessBeanFactory

postProcessBeanFactory方法是留给子类扩展的,可以在bean实 需要zi料+ 绿色徽【vip1024b】

例初始化之前注册后置处理器(类似prepareBeanFactory方法中的beanFactory.addBeanPostProcessor),以子类AbstractRefreshableWebApplicationContext为例,其postProcessBeanFactory方法如下:

protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {

beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));

beanFactory.ignoreDependencyInterface(ServletContextAware.class);

beanFactory.ignoreDependencyInterface(ServletConfigAware.class);

WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);

WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);

}

可见除了WebApplicationContextUtils类的工作之外,其余的都是和prepareBeanFactory方法中类似的处理;

invokeBeanFactoryPostProcessors

invokeBeanFactoryPostProcessors方法用来执行BeanFactory实例的后置处理器BeanFactoryPostProcessor的postProcessBeanFactory方法,这个后置处理器除了原生的,我们也可以自己扩展,用来对Bean的定义做一些修改,由于此时bean还没有实例化,所以不要在自己扩展的BeanFactoryPostProcessor中调用那些会触发bean实例化的方法(例如BeanFactory的getBeanNamesForType方法),源码的文档中有相关说明,如下图红框所示,不要触发bean的实例化,如果要处理bean实例请在BeanPostProcessor中进行;:

registerBeanPostProcessors

registerBeanPostProcessors方法的代码略多,就不在此贴出来了,简单的说,就是找出所有的bean的后置处理器(注意,是bean的后置处理器,不是beanFactory的后置处理器,bean后置处理器处理的是bean实例,beanfactory后置处理器处理的是bean的定义),然后将这些bean的后置处理器分为三类:

  1. 实现了顺序接口Ordered.class的,先放入orderedPostProcessors集合,排序后顺序加入beanFactory的bean后处理集合中;

  2. 既没有实现Ordered.class,也没有实现PriorityOrdered.class的后置处理器,也加入到beanFactory的bean后处理集合中;

  3. 最后是实现了优先级接口PriorityOrdered.class的,排序后顺序加入beanFactory的bean后处理集合中;

registerBeanPostProcessors方法执行完毕后,beanFactory中已经保存了有序的bean后置处理器,在bean实例化之后,会依次使用这些后置处理器对bean实例来做对应的处理;

initMessageSource

initMessageSource方法用来准备国际化资源相关的,将实现了MessageSource接口的bean存放在ApplicationContext的成员变量中,先看是否有配置,如果有就实例化,否则就创建一个DelegatingMessageSource实例的bean;

initApplicationEventMulticaster

spring中有事件、事件广播器、事件监听器等组成事件体系,在initApplicationEventMulticaster方法中对事件广播器做初始化,如果找不到此bean的配置,就创建一个SimpleApplicationEventMulticaster实例作为事件广播器的bean,并且保存为applicationContext的成员变量applicationEventMulticaster;

onRefresh

onRefresh是个空方法,留给子类自己实现的,在实例化bean之前做一些ApplicationContext相关的操作,以子类AbstractRefreshableWebApplicationContext为例,看看它的onRefresh方法:

@Override

protected void onRefresh() {

this.themeSource = UiApplicationContextUtils.initThemeSource(this);

}

可见是做了主题相关的初始化,并保存在ApplicationContext的成员变量中;

registerListeners

方法名为registerListeners,看名字像是将监听器注册在事件广播器中,但实际情况并非如此,只有一些特殊的监听器被注册了,那些在bean配置文件中实现了ApplicationListener接口的类还没有实例化,所以此处只是将其name保存在广播器中,将这些监听器注册在广播器的操作是在bean的后置处理器中完成的,那时候bean已经实例化完成了,我们看代码:

protected void registerListeners() {

// 注册的都是特殊的事件监听器,而并非配置中的bean

for (ApplicationListener<?> listener : getApplicationListeners()) {

getApplicationEventMulticaster().addApplicationListener(listener);

}

// Do not initialize FactoryBeans here: We need to leave all regular beans

// uninitialized to let post-processors apply to them!

// 根据接口类型找出所有监听器的名称

String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);

for (String listenerBeanName : listenerBeanNames) {

// 这里只是把监听器的名称保存在广播器中,并没有将这些监听器实例化!!!

getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);

}

}

finishBeanFactoryInitialization

finishBeanFactoryInitialization方法做了两件事:

  1. beanFactory对象的初始化;

  2. 我们在bean配置文件中配置的那些单例的bean,都是在finishBeanFactoryInitialization方法中实例化的;

看代码:

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {

// Initialize conversion service for this context.

// 实例化类型转换的bean,并保存在ApplicationContext中

if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&

beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {

beanFactory.setConversionService(

beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));

}

// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.

// 实例化LoadTimeWeaverAware接口的bean,用于ApsectJ的类加载期织入的处理

String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);

for (String weaverAwareName : weaverAwareNames) {

getBean(weaverAwareName);

}

// Stop using the temporary ClassLoader for type matching.

// 确保临时的classLoader为空,临时classLoader一般被用来做类型匹配的

beanFactory.setTempClassLoader(null);

// Allow for caching all bean definition metadata, not expecting further changes.

// 将一个标志设置为true,表示applicationContext已经缓存了所有bean的定义,这些bean的name都被保存在applicationContext的frozenBeanDefinitionNames成员变量中,相当于一个快照,记录了当前那些bean的定义已经拿到了

beanFactory.freezeConfiguration();

// 实例化所有还未实例化的单例bean

beanFactory.preInstantiateSingletons();

}

上述代码中,beanFactory.preInstantiateSingletons()需要展开仔细看:

public void preInstantiateSingletons() throws BeansException {

if (this.logger.isDebugEnabled()) {

this.logger.debug("Pre-instantiating singletons in " + this);

}

// Iterate over a copy to allow for init methods which in turn register new bean definitions.

// While this may not be part of the regular factory bootstrap, it does otherwise work fine.

List beanNames = new ArrayList(this.beanDefinitionNames);

// Trigger initialization of all non-lazy singleton beans…

for (String beanName : beanNames) {

// 获取bean的定义,该定义已经和父类定义做了合并

RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);

// 非抽象类、是单例、非懒加载

if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {

//FactoryBean的处理

if (isFactoryBean(beanName)) {

final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);

boolean isEagerInit;

if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {

isEagerInit = AccessController.doPrivileged(new PrivilegedAction() {

@Override

public Boolean run() {

return ((SmartFactoryBean<?>) factory).isEagerInit();

}

}, getAccessControlContext());

}

else {

isEagerInit = (factory instanceof SmartFactoryBean &&

((SmartFactoryBean<?>) factory).isEagerInit());

}

if (isEagerInit) {

getBean(beanName);

}

}

else {

//非FactoryBean的实例化、初始化

getBean(beanName);

}

}

}

// Trigger post-initialization callback for all applicable beans…

// 单例实例化完成后,如果实现了SmartInitializingSingleton接口,afterSingletonsInstantiated就会被调用,此处用到了特权控制逻辑AccessController.doPrivileged

for (String beanName : beanNames) {

Object singletonInstance = getSingleton(beanName);

if (singletonInstance instanceof SmartInitializingSingleton) {

final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;

if (System.getSecurityManager() != null) {

AccessController.doPrivileged(new PrivilegedAction() {

写在最后

很多人感叹“学习无用”,实际上之所以产生无用论,是因为自己想要的与自己所学的匹配不上,这也就意味着自己学得远远不够。无论是学习还是工作,都应该有主动性,所以如果拥有大厂梦,那么就要自己努力去实现它。

最后祝愿各位身体健康,顺利拿到心仪的offer!

由于文章的篇幅有限,所以这次的蚂蚁金服和京东面试题答案整理在了PDF文档里

蚂蚁、京东Java岗4面:原理+索引+底层+分布式+优化等,已拿offer

蚂蚁、京东Java岗4面:原理+索引+底层+分布式+优化等,已拿offer

蚂蚁、京东Java岗4面:原理+索引+底层+分布式+优化等,已拿offer

else {

//非FactoryBean的实例化、初始化

getBean(beanName);

}

}

}

// Trigger post-initialization callback for all applicable beans…

// 单例实例化完成后,如果实现了SmartInitializingSingleton接口,afterSingletonsInstantiated就会被调用,此处用到了特权控制逻辑AccessController.doPrivileged

for (String beanName : beanNames) {

Object singletonInstance = getSingleton(beanName);

if (singletonInstance instanceof SmartInitializingSingleton) {

final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;

if (System.getSecurityManager() != null) {

AccessController.doPrivileged(new PrivilegedAction() {

写在最后

很多人感叹“学习无用”,实际上之所以产生无用论,是因为自己想要的与自己所学的匹配不上,这也就意味着自己学得远远不够。无论是学习还是工作,都应该有主动性,所以如果拥有大厂梦,那么就要自己努力去实现它。

最后祝愿各位身体健康,顺利拿到心仪的offer!

由于文章的篇幅有限,所以这次的蚂蚁金服和京东面试题答案整理在了PDF文档里

[外链图片转存中…(img-e4ozdoII-1710368577076)]

[外链图片转存中…(img-mIVHFgaG-1710368577077)]

[外链图片转存中…(img-Y8ZYYpcR-1710368577077)]

  • 16
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值