一、spring源码前置知识补充
1、为什么要阅读Spring源码?
阅读spring源码首要任务是为了更好的利用spring开发日常需求,然后是学习spring当中的设计思想转为自有,能够更好的使用这些设计思想,让自身的业务代码更优美。
2、如何阅读Spring源码?
a方式、从官网下载spring的源码 然后构建,因为是基于gradle的 所以构建会比较麻烦,但是可以在源码里新增备注,调整代码。
b方式、直接在idea里新建一个maven项目,引入spring对应的依赖就行,然后直接打断点调试。这种缺点就是不能加自己的注释。
3、Spring整体结构
Spring Core:框架的最基础部分,提供 IoC 容器,对 bean 进行管理。
Spring Context:继承BeanFactory,提供上下文信息,扩展出JNDI、EJB、电子邮件、国际化等功能。
Spring DAO:提供了JDBC的抽象层,还提供了声明性事务管理方法。
Spring ORM:提供了JPA、JDO、Hibernate、MyBatis 等ORM映射层.
Spring AOP:集成了所有AOP功能
Spring Web:提供了基础的 Web 开发的上下文信息,现有的Web框架,如JSF、Tapestry、Structs等,提供了集成
Spring Web MVC:提供了 Web 应用的 Model-View-Controller 全功能实现。
4、Spring源码流程概览
5、Spring中的常见接口
- BeanFactory接口
- BeanFactory是Spring容器的顶层接口,定义了IOC容器的基本规范
- 三个子接口(二级接口)
- ListableBeanFactory
- HierarchicalBeanFactory
- AutowireCapableBeanFactory
- 经常使用的一些BeanFactory的实现类
DefaultListableBeanFactory:重要,几乎所有BeanFactory都会内置该实现类来完成各种功能
AnnotationConfigApplicationContext:注解形式配置上下文(这里也是入口)
ClassPathXmlApplicationContext:在classPath中的xml配置文件(这里也是入口)
FileSystemXmlApplicationContext:自定义配置文件路径
WebApplicationContext:主要用于web应用,内置了web上下文环境
- Resource接口
- ByteArrayResource
ClassPathResource(常用):通过 ClassPathResource 以类路径的方式进行访问
DescriptiveResource
FileSystemResource(常用)
InputStreamResource
PortletContextResource
ServletContextResource(常用):通过 ServletContextResource 以相对于Web应用根目录的方式进行访问
UrlResource(常用)
- ByteArrayResource
- ResourceLoader接口
- ResourceLoader接口用来加载Resource资源
- 所有的ApplicationContext类都实现了ResourceLoader接口,所以我们可以使用context来加载resource
- 不同类型的ApplicationContext会返回不同的Resource
- Aware接口
- 在Spring中有很多Aware接口,实现了这些接口后,我们可以在自己写的bean中感知(获取)到对应的Spring组件
比如实现了ApplicationContextAware接口的类,能够获取到ApplicationContext
比如实现了BeanFactoryAware接口的类,能够获取到BeanFactory对象 - BeanNameAware
作用:让Bean获取自己在BeanFactory配置中的名字(根据情况是id或者name)。
Spring自动调用。并且会在Spring自身完成Bean配置之后,且在调用任何Bean生命周期回调(初始化或者销毁)方法之前就调用这个方法。换言之,在程序中使用BeanFactory.getBean(String beanName)之前,Bean的名字就已经设定好了。
- 在Spring中有很多Aware接口,实现了这些接口后,我们可以在自己写的bean中感知(获取)到对应的Spring组件
- BeanDefinition接口
- BeanDefinition中存放了Spring bean的描述信息(注册信息)
- spring会加载所有符合要求的class(从xml或者注解中)
- 解析这些类的相关信息
- 把解析完的信息存放在BeanDefinition中
- 根据bean的scope属性进行实例化
- 执行该bean实现的一些接口,比如Aware等
- BeanDefinitionReader接口
- 用来读取Bean的类转变成BeanDefinition的接口
- XML读取的对应实现类是XmlBeanDefinitionReader
- InitializingBean接口
- 该接口为bean提供了初始化方法的方式,需要重写afterPropertiesSet方法:凡是继承该接口的类,在初始化bean时都会执行该方法
- InitializingBean和init-method和@PostConstruct功能类似,执行顺序、原理存在区别
- 执行顺序
- 实例化bean
- @Autowired等 bean的依赖注入
- @PostConstruct 执行
- InitializingBean 的 afterPropertiesSet 执行
- init-method 执行
- DisposableBean接口
- 与InitializingBean接口的方法类似
- 执行顺序
- @PreDestroy 执行
- DisposableBean的 destory()方法
- destroy-method 执行
- ImportBeanDefinitionRegistrar接口
- ImportSelector接口
- AliasRegistry接口
- 主要是对spring Bean的别名进行管理的顶级接口,主要对别名进行增删功能
- 它有几个比较重要的子接口或者实现类
- BeanDefinitionRegistry接口:继承AliasRegistry接口,扩展了对BeanDefinition注册操作的功能
- FactoryBean接口
- BeanFactoryPostProcessor接口
- BeanFactoryPostProcessor是bean工厂的beanDefinition处理容器:说通俗一点就是可以管理我们的bean工厂内所有beanDefinition(未实例化)数据,可以随心所欲的修改属性
- BeanPostProcessor接口
- bean的后置处理器接口,在依赖注入的初始化方法前后进行调用
- 对所有bean进行前置和后置处理
6、Spring中Bean的作用域
singleton、prototype、request、session和global session。
1、singleton作用域是默认的作用域,它表示在整个应用程序中只有一个实例
2、prototype作用域表示每次请求都会创建一个新的实例。
3、request作用域,它表示每个HTTP请求都会创建一个新的实例,该实例仅在当前请求的范围内可见。这种作用域通常用于Web应用程序中,用于将数据在不同的请求之间进行共享。
4、session作用域表示每个HTTP会话都会创建一个实例,该实例在整个会话期间可见。
5、global session作用域与session作用域类似,但适用于Portlet环境。
7、Spring程序如何启动?入口在哪里?
思考:
- spring本质是一个容器,来存储各种Bean,根节点接口是BeanFactory。
- 如何将代码所写的类读取并装载到容器中并且实例化然后初始化给用户使用的?
- 需要通过什么方式扫描将代码中写的类扫描到
- 然后通过BeanDefinitionReader将类转换为BeanDefinition,再生成具体的Bean对象。
- 最后进行创建存储
从常用的类和接口中可以看到BeanFactory是根节点,在具体的实现中有两种配置上下文
1、AnnotationConfigApplicationContext:注解形式配置上下文(这里也是入口)
2、ClassPathXmlApplicationContext:在classPath中的xml配置文件(这里也是入口)
所以,入口肯定在以上两个Context中,这里选则AnnotationConfigApplicationContext,下面就开始分析了。
ApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.test");
public AnnotationConfigApplicationContext(String... basePackages) {
this();
scan(basePackages);
refresh();
}
public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
/**
* 前戏,做容器刷新前的准备工作
* 1、设置容器的启动时间
* 2、设置活跃状态为true
* 3、设置关闭状态为false
* 4、获取Environment对象,并加载当前系统的属性值到Environment对象中
* 5、准备监听器和事件的集合对象,默认为空的集合
*/
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
// 创建容器对象:DefaultListableBeanFactory
// 加载xml配置文件的属性值到当前工厂中,最重要的就是BeanDefinition
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
// beanFactory的准备工作,对各种属性进行填充
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
// 子类覆盖方法做额外的处理,此处我们自己一般不做任何扩展工作,但是可以查看web中的代码,是有具体实现的
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
// 调用各种beanFactory处理器
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
// 注册bean处理器,这里只是注册功能,真正调用的是getBean方法
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
// 为上下文初始化message源,即不同语言的消息体,国际化处理,在springmvc的时候通过国际化的代码重点讲
initMessageSource();
// Initialize event multicaster for this context.
// 初始化事件监听多路广播器
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
// 留给子类来初始化其他的bean
onRefresh();
// Check for listener beans and register them.
// 在所有注册的bean中查找listener bean,注册到消息广播器中
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
// 初始化剩下的单实例(非懒加载的)
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
// 完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
// 为防止bean资源占用,在异常处理中,销毁已经在前面过程中生成的单件bean
destroyBeans();
// Reset 'active' flag.
// 重置active标志
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}