Java开发框架之Spring源码解析

本文探讨了Spring框架的发展历程,从Webwork、Struts到Spring Boot,强调Spring的简化编程和多元化拓展特性。文章重点介绍了Spring的核心——ApplicationContext,包括Environment、PropertyResolver、MessageSource、ApplicationEventPublisher和ResourcePatternResolver等接口的功能。此外,还讨论了BeanFactory及其扩展,如ListableBeanFactory和HierarchicalBeanFactory在bean管理中的作用。Spring的这些设计使得开发者能够更高效地管理和扩展应用程序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言:

作为一个后台java开发,我们接触过很多开源框架。

从最初的webwork,struts到现在最流行的spring,我们会发现这些框架发展都是朝着简化编程,多元化拓展的方向发展的。

spring作为其中的翘楚者,依赖注入,控​​java培训​​制反转,支持配置文件,注解开发,第三方模块轻量接入,比如JDBC,Log,Cache等等。

慢慢的经过发展又出现了更加简便的SpringBoot-约定优于配置的最佳实践者。

给春天穿上靴子,极大的提高开发效率,借助maven工具,把以前搭建spring框架繁琐的配置文件过程变成了几个maven依赖,几乎实现了0配置。

随着互联网技术的发展以及各种成熟的解决方案的接入,随之出现了功能更加强大且不失简便的springcloud框架。

作为这些框架的核心,spring的源码完全值得我们研究,借助这个过程,我们不但可以学习spring中的代码风格实现逻辑,而且可以熟悉spring给我们提供的所有功能,方便于我们日后能够把自己的插件集成入spring中以及排查spring项目的问题。

spring给我们提供的最重要的一个功能就是上下文管理,通过这个上下文,我们能管理整个应用的bean,环境变量,资源文件信息等等。

这是spring里面的ApplicationContext接口定义。真实的实现类内部是相当复杂的,但是我们可以通过接口入手,去研究上下文给我们提供了一些什么功能。

EnvironmentCapable

接口定义实际上就一个方法返回当前的环境变量。

Environment:上下文中一系列的环境资源文件管理器,继承于PropertyResolver。

PropertyResolver:资源解析器,它提供一系列关于资源文件的读取方法,比如通过key去获取资源文件的value,通过一个key和Class信息,去获取一个对应的且已根据资源文件初始化好的bean,另一个重要的功能是去解析占位符“${...}”信息。

ConfigurableEnvironment:继承于Environment接口,可以修改环境内部profile属性,达到区分线上环境功能。

Environment可以理解为一个能区分配置文件的资源管理器,我们平时可能会用到application-dev.properties,application-pro.properties,dev,pro作为两个环境,spring只会去加载与它环境相同的配置文件,Environment中通过profile配置环境。

Environment=profile(配置)+propertyResolver(资源解析器);

MessageSource

messageSource接口是用来做国际化。

ApplicationEventPublisher

此接口是用来推送信息的,spring内部就实现了应用内部的消息推送功能,如果只需要做一个简单的本机消息推送功能,可以考虑此方法,

步骤一:先继承ApplicationEvent

步骤二:注册监听方法

步骤三:发送事件

ResourcePatternResolver

资源搜索器,比如提供一个表达式:“classpath*:java.lang.*",表示要去类路径下的java.lang包下去加载资源。

该接口继承于ResourceLoader,ResourceLoader解决的是从一个具体的路径下加载资源,相当于扩展了该接口的方法,资源(Resource)可以是一个输入流,也可以是一个文件。

ListableBeanFactory与HierarchicalBeanFactory

两个接口有一个公共的接口BeanFactory,该接口为applicationContext提供了强大的bean管理能力,包括获取class信息,初始化bean,自动注入等等。

BeanFactory:定义了一些列获取bean的方法,是一个最基础的bean容器提供者。

ListableBeanFactory:扩展了BeanFactory功能,相比直接存入bean,该接口提供了一系列的BeanDefinetion存取功能,beanDefinetion包含类的描述,注解信息,是否是代理类,以及依赖bean等。这些功能在bean的初始化过程中相当有用。

HierarchicalBeanFactory:为BeanFactory提供了一个层级功能,能通过这个接口拿到父BeanFactory。

一个最基本的applictionContext接口都能定义的如此复杂,所以我们不得不佩服这些框架开发者的周全之处,有了这些基础,spring才能灵活扩展各种功能。

代码解析2,部分摘抄 简单的说,在web容器中,通过ServletContext为Spring的IOC容器提供宿主环境,对应的建立起一个IOC容器的体系。其中,首先需要建立的是根上下文,这个上下文持有的对象可以有业务对象,数据存取对象,资源,事物管理器等各种中间层对象。在这个上下文的基础上,和web MVC相关还会有一个上下文来保存控制器之类的MVC对象,这样就构成了一个层次化的上下文结构。在web容器中启动Spring应用程序就是一个建立这个上下文体系的过程。Spring为web应用提供了上下文的扩展接口 WebApplicationContext: 如转载请注明,转载自:关注Java[http://www.gbsou.com] 本文链接: http://www.gbsou.com/2009/08/11/214.html - - Java代码 public interface WebApplicationContext extends ApplicationContext { //这里定义的常量用于在ServletContext中存取根上下文 String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT"; …… //对WebApplicationContext来说,需要得到Web容器的ServletContext ServletContext getServletContext(); } public interface WebApplicationContext extends ApplicationContext { //这里定义的常量用于在ServletContext中存取根上下文 String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT"; ...... //对WebApplicationContext来说,需要得到Web容器的ServletContext ServletContext getServletContext(); } 而一般的启动过程,Spring会使用一个默认的实现,XmlWebApplicationContext – 这个上下文实现作为在web容器中的根上下文容器被建立起来,具体的建立过程在下面我们会详细分析。 Java代码 public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext { /** 这是和web部署相关的位置信息,用来作为默认的根上下文bean定义信息的存放位置*/ public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml"; public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/"; public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml"; //我们又看到了熟悉的loadBeanDefinition,就像我们前面对IOC容器的分析中一样,这个加载工程在容器的refresh()的时候启动。 protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException { //对于XmlWebApplicationContext,当然使用的是XmlBeanDefinitionReader来对bean定义信息来进行解析 XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader); } protected void initBeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader) { } //使用XmlBeanDefinitionReader来读入bean定义信息 protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { String[] configLocations = getConfigLocations(); if (configLocations != null) { for (int i = 0; i < configLocations.length; i++) { reader.loadBeanDefinitions(configLocations[i]); } } } //这里取得bean定义信息位置,默认的地方是/WEB-INF/applicationContext.xml protected String[] getDefaultConfigLocations() { if (getNamespace() != null) { return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX}; } else { return new String[] {DEFAULT_CONFIG_LOCATION}; } } } public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext { /** 这是和web部署相关的位置信息,用来作为默认的根上下文bean定义信息的存放位置*/ public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml"; public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/"; public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml"; //我们又看到了熟悉的loadBeanDefinition,就像我们前面对IOC容器的分析中一样,这个加载工程在容器的refresh()的时候启动。 protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException { //对于XmlWebApplicationContext,当然使用的是XmlBeanDefinitionReader来对bean定义信息来进行解析 XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader); } protected void initBeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader) { } //使用XmlBeanDefinitionReader来读入bean定义信息 protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { String[] configLocations = getConfigLocations(); if (configLocations != null) { for (int i = 0; i < configLocations.length; i++) { reader.loadBeanDefinitions(configLocations[i]); } } } //这里取得bean定义信息位置,默认的地方是/WEB-INF/applicationContext.xml protected String[] getDefaultConfigLocations() { if (getNamespace() != null) { return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX}; } else { return new String[] {DEFAULT_CONFIG_LOCATION}; } } } 对于一个Spring激活的web应用程序,可以通过使用Spring代码声明式的指定在web应用程序启动时载入应用程序上下文(WebApplicationContext),Spring的ContextLoader是提供这样性能的类,我们可以使用 ContextLoaderServlet或者ContextLoaderListener的启动时载入的Servlet来实例化Spring IOC容器 – 为什么会有两个不同的类来装载它呢,这是因为它们的使用需要区别不同的Servlet容器支持的Serlvet版本。但不管是 ContextLoaderSevlet还是 ContextLoaderListener都使用ContextLoader来完成实际的WebApplicationContext的初始化工作。这个ContextLoder就像是Spring Web应用程序在Web容器中的加载器booter。当然这些Servlet的具体使用我们都要借助web容器中的部署描述符来进行相关的定义。 下面我们使用ContextLoaderListener作为载入器作一个详细的分析,这个Servlet的监听器是根上下文被载入的地方,也是整个 Spring web应用加载上下文的第一个地方;从加载过程我们可以看到,首先从Servlet事件中得到ServletContext,然后可以读到配置好的在web.xml的中的各个属性值,然后ContextLoder实例化WebApplicationContext并完成其载入和初始化作为根上下文。当这个根上下文被载入后,它被绑定到web应用程序的ServletContext上。任何需要访问该ApplicationContext的应用程序代码都可以从WebApplicationContextUtils类的静态方法来得到:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值