Java教程

Spring源码分析

本文主要是介绍Spring源码分析,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

关键类介绍

ApplicationContext

万能的 applicationContext, 但实际上各种能力都是依赖于其他的类, 比如 getBean 是 beanFactory 的, publishEvent 是事件广播器的, 等等. 其本身是一个综合体, 整合这些能力, 便于开发者调用和理解.

# 下面列一下相关的接口, 抽象类, 和具体类
ApplicationContext
	是一个只读的 bean 容器
	可以加载解析配置文件(如xml)
	可以发布事件和注册监听
	具有国际化消息处理能力
ConfigurableApplicationContext
	是一个具有可配置能力的 容器(可设置各个参数, 如id, 父容器)
	具有容器生命周期概念, 如启动,停止,关闭.
AbstractApplicationContext
	模板方法模式的抽象类, 定义了容器的模板(refresh方法), 但由具体的子类实现部分方法
	管理Bean和BeanFactory的PostProcessor
	管理事件的监听和处理
AbstractRefreshableApplicationContext
	为可重复刷新的容器提供基类
	加入了BeanFactory的管理(创建/关闭等)
AbstractRefreshableConfigApplicationContext
	加入了configLocation字段, 用于某些容器初始化BeanFactory和Bean
AbstractXmlApplicationContext
	定义了读取xml配置文件来加载BeanFactory的代码, 使得子类只需提供配置文件地址或Resource
ClassPathXmlApplicationContext
	继承基类, 提供配置文件地址的构造方法, 调用refresh加载BeanFactory
		

BeanFactory

1.核心中的核心, 加载和管理 beanDefinitions(Bean配置信息), 创建和管理 bean 对象实例, 注册和管理 BeanPostProcessor(Bean扩展)

# 下面列一下相关的接口, 抽象类, 和具体类
BeanFactory
  定义了 Bean 的基础操作接口, 如 getBean, getType, isSingleton 等

SingletonBeanRegistry
  定义了单例对象的操作接口 (注册/获取/是否已存在) 

HierarchicalBeanFactory
  定义了父 BeanFactory 的相关操作接口(获取)

ConfigurableBeanFactory
  定义了对 BeanFactory 做各种配置的操作接口, 包括 BeanPostProcessor, setParentBeanFactory, destroyBean, registerAlias, resolveAliases 等

DefaultSingletonBeanRegistry
  实现了 SingletonBeanRegistry 接口, 即实现了单例对象的缓存管理, 包括一级/二级/三级(二级三级只依赖循环用上的两个缓存)
  
FactoryBeanRegistrySupport
  继承了 DefaultSingletonBeanRegistry
	实现对使用 FactoryBean 存储和获取 bean 对象实例方式的支持
	
AbstractBeanFactory
  继承了 FactoryBeanRegistrySupport
  实现了 BeanFactory/HierarchicalBeanFactory/ConfigurableBeanFactory 定义的接口
  实现了具体 getBean, 包括缓存管理等
  
AutowireCapableBeanFactory
  定义了根据 class 类型获取 BeanDefinition 信息以及 Bean 对象的接口

AbstractAutowireCapableBeanFactory
  继承自 AbstractBeanFactory 
  实现了 AutowireCapableBeanFactory 中定义的方法(就是实现了根据 class 获取 bean 或 BeanDefinition)
  实现了 createBean, 也就是真正的实例化一个对象的过程, 包括实例化, 为需要赋值的字段注入相应的值
  同时触发了 BeanPostProcessor 的方法调用
  
BeanDefinitionRegistry
  定义了 BeanDefinition 的注册/获取/移除
  
ListableBeanFactory
	定义了 BeanDefinition 的可遍历性
  
ConfigurableListableBeanFactory
  结合 ListableBeanFactory 和 ConfigurableBeanFactory 并补充完善了几个相关接口 (如 getBeanNamesIterator 接口 )

DefaultListableBeanFactory
  继承了 AbstractAutowireCapableBeanFactory
  实现了 BeanDefinitionRegistry/ConfigurableListableBeanFactory 的接口
 
# 总结:
定义处:
BeanFactory(getBean)
SingletonBeanRegistry(addSingleton)
HierarchicalBeanFactory(getParentBeanFactory)
ConfigurableBeanFactory(addBeanPostProcessor)
AutowireCapableBeanFactory(autowireBean)
BeanDefinitionRegistry(registerBeanDefinition)
ListableBeanFactory(getBeanDefinitionNames)
ConfigurableListableBeanFactory(getBeanNamesIterator)

实现处:
DefaultSingletonBeanRegistry(registerSingleton)
FactoryBeanRegistrySupport(getObjectFromFactoryBean)
AbstractBeanFactory(doGetBean)
AbstractAutowireCapableBeanFactory(createBean)
DefaultListableBeanFactory(registerBeanDefinition)

容器初始化过程

1.setParent(): 处理父容器 
2.setConfigLocations(): 解析并设置xml配置文件路径
3.refresh(): 创建 beanFactory 对象并初始化, 读取 xml 配置文件得到 beanDefinitions, 接着处理两种 PostProcessor, 然后添加国际化处理器和事件广播器以及相应的初始化和一些处理, 最后实例化单例的 bean 等等.

#外圈结束, 再看 refresh() 里面的每个方法
1.prepareRefresh(): 准备工作, 一些字段值的设置和处理.
2.obtainFreshBeanFactory(): 创建一个 beanFactory 对象并注册到 applicationContext (即赋值到字段上), 然后解析 xml 配置文件(或注解配置)的信息, 解析得到 beanDefinitions 并注册到容器中.
3.然后是一些对 beanFactory 对象的完善配置的代码
4.扫描并执行 BeanFactoryPostProcessor(其作用是为beanFactory对象添加东西提供扩展性), 其中我认识的就只有 ConfigurationClassPostProcessor(这个类作用就是解析 @Configuration/@Component/@Import/@ImportSource/@ComponentScan等基础注解).
5.扫描实现了 BeanPostProcessor 接口的 bean 并注册到 beanFactory 中存起来, 等 createBean 创建对象时会在对应的时机执行一些对应的方法(钩子). 常见的各种 XxxAware 就是靠这个实现的咯.
6.接着, 初始化国际化资源处理器, 事件广播器, 并注册一些需要注册的事件(也注册容器内实现对应接口的 bean)
7.处理一些 beanFactory 的配置, 接着为所有单例且非懒加载的(不就是默认策略嘛) bean 创建实例, 缓存起来.
8.广播容器加载完成了的事件. 以及处理生命周期.

最后总结下, 先创建容器, 再将根据配置文件解析得到 BeanDefinition 注册到容器中, 然后处理两大扩展(BeanFactoryPostProcessor/BeanPostProcessor), 接着是Spring的国际化, 以及相当有用的事件广播器, 最后实例化 bean. 整体感觉其实很简单, 但其实有大量的工作交给了 BeanPostProcessor.

超长源码分析过程

// 先随便写个 main 方法, 如我写的, 可测试依赖循环问题和事件监听:
// 包名: cn.gudqs7.spring.tests, 改动则需同步修改xml哦
// 进入对应类代码: 快捷键 Cmd+Option+鼠标点击 (或 Ctrl+Alt+鼠标左键 ); 如果是接口松开 Option(或Alt)键

Test.java
public class Test {

	public static void main(String[] args) {
		ApplicationContext xmlContext = new ClassPathXmlApplicationContext("application-wq.xml");
		UserServiceImpl userService = xmlContext.getBean(UserServiceImpl.class);
		userService.sayHi();
	}

}


application-wq.xml
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" default-autowire="byName">

	<bean name="userService" class="cn.gudqs7.spring.tests.UserServiceImpl">
		<property name="starter"><ref bean="serverStarter"/></property>
	</bean>
	<bean name="serverStarter" class="cn.gudqs7.spring.tests.ServerStarter">
		<property name="userService"><ref bean="userService"/></property>
	</bean>

</beans>

    
UserServiceImpl.java
@Service
public class UserServiceImpl {

	@Resource
	private ServerStarter starter;

	public void sayHi() {
		System.out.println(starter);
		System.out.println("Hello Spring!");
	}

	public void setStarter(ServerStarter starter) {
		this.starter = starter;
	}
}


ServerStarter.java
@Service
public class ServerStarter implements ApplicationListener<ContextRefreshedEvent> {

	@Inject
	private UserServiceImpl userService;

	@Override
	public void onApplicationEvent(ContextRefreshedEvent event) {
		String applicationName = event.getApplicationContext().getApplicationName();
		System.out.println(applicationName);
		System.out.println(userService);
		System.out.println("========== started by gudqs7 ==============");
		System.out.println("========== started by gudqs7 ==============");
		System.out.println("========== started by gudqs7 ==============");
	}

	public void setUserService(UserServiceImpl userService) {
		this.userService = userService;
	}
}

这篇关于Spring源码分析的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!