概述
1. Spring 容器介绍:
1.1 BeanFactory
首先要提到BeanFactory,它是Spring容器的顶层接口,BeanFactory表示Bean工厂,所以很明显,BeanFactory负责创建Bean,并且提供获取Bean的API。 但我们使用更多的是它的子接口:ApplicationContext,在Spring源码中,是这么定义的:
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory,
HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
...
}
1.2 ApplicationContext
ApplicationContext是个接口,实际上也是一个BeanFactory,不过比BeanFactory
更加强大,比如:
- HierarchicalBeanFactory:拥有获取父BeanFactory的功能
- ListableBeanFactory:拥有获取beanNames的功能
- ResourcePatternResolver:资源加载器,可以一次性获取多个资源(文件资源等等)
- EnvironmentCapable:可以获取运行时环境(没有设置运行时环境功能)
- ApplicationEventPublisher:拥有广播事件的功能(没有添加事件监听器的功能)
- MessageSource:拥有国际化功能
我们先来看ApplicationContext两个比较重要的实现类:
- AnnotationConfigApplicationContext
- ClassPathXmlApplicationContext
AnnotationConfigApplicationContext
通过扫描包的形式加载:
@Test
public void testAnnotationContext() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ScanBean.class);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String beanName : beanDefinitionNames) {
System.out.println("beanName: " + beanName);
}
}
类的继承关系图:
现在看不懂没关系,源码熟悉一点后回来再来就容易多了。
- ConfigurableApplicationContext:继承了ApplicationContext接口,增加了,添加事件监听器、添加BeanFactoryPostProcessor、设置Environment,获取ConfigurableListableBeanFactory等功能;
- AbstractApplicationContext:实现了ConfigurableApplicationContext接口;
- GenericApplicationContext:继承了AbstractApplicationContext,实现了BeanDefinitionRegistry接口,拥有了所有ApplicationContext的功能,并且可以注册BeanDefinition,注意这个类中有一个属性(DefaultListableBeanFactory beanFactory)
- AnnotationConfigRegistry:可以单独注册某个类为BeanDefinition(可以处理该类上的@Configuration、@Bean注解),同时可以扫描;
- AnnotationConfigApplicationContext:继承了GenericApplicationContext,实现了AnnotationConfigRegistry接口,拥有了以上所有的功能。
ClassPathXmlApplicationContext
通过配置文件加载:
@Test
public void testXml() {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
Kieasar kieasar = applicationContext.getBean(Kieasar.class);
System.out.println(kieasar.getUsername());
}
类的继承关系图:
ClassPathXmlApplicationContext 继承了AbstractApplicationContext,但是相对于AnnotationConfigApplicationContext而言,功能没有AnnotationConfigApplicationContext强大,不能注册BeanDefinition。
另外,还有两个实现类:
- FileSystemXmlApplicationContext:通过配置文件的绝对路径加载:
ApplicationContext applicationContext = new FileSystemXmlApplicationContext("E:\idea\springdemo\spring.xml");
- EmbeddedWebApplicationContext:Springboot 加载容器
ApplicationContext applicationContext = new EmbeddedWebApplicationContext();
2. Spring 容器加载核心方法refresh()概览
AbstractApplicationContext.refresh()方法是Spring 容器启动过程中的核心方法,Spring 容器要加载必须执行该方法,该方法中包括以下方法:
① prepareRefresh():准备此上下文用于刷新,设置启动时间和active标志,初始化属性
② obtainFreshBeanFactory():创建 BeanFactory
③ prepareBeanFactory():设置 BeanFactory 的基本属性
④ postProcessBeanFactory():子类处理自定义的BeanFactoryPostProcess
⑤ invokeBeanFactoryPostProcessors():调用所有的BeanFactoryPostProcessor
⑥ registerBeanPostProcessors():注册,把实现了BeanPostProcessor接口的类实例化,加到BeanFactory
⑦ initMessageSource():初始化上下文中的资源文件,如国际化文件的处理等
⑧ initApplicationEventMulticaster():初始化上下文的事件传播器
⑨ onRefresh():给子类扩展初始化其他Bean,springboot 中用来做内嵌 tomcat 启动
⑩ registerListeners():在所有bean中查找监听 bean,然后注册到广播器中
⑪ finishBeanFactoryInitialization():Bean实例化过程、IOC、AOP入口、各种注解的解析
⑫ finishRefresh():完成刷新过程,发布相应事件
/*
*TODO 该方法是spring容器初始化的核心方法。是spring容器初始化的核心流程,是一个典型的父类模板设计模式的运用
* 根据不同的上下文对象,会调到不同的上下文对象子类方法中
* 核心上下文子类有:
* ClassPathXmlApplicationContext
* FileSystemXmlApplicationContext
* AnnotationConfigApplicationContext
* EmbeddedWebApplicationContext(springboot)
*/
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
//TODO 为容器初始化做准备,重要程度:0
// Prepare this context for refreshing.
prepareRefresh();
/*
* 重要程度:5
* TODO
* 1、创建BeanFactory对象
* 2、xml解析
* 传统标签解析:bean、import等
* 自定义标签解析 如:<context:component-scan base-package="com.xiangxue.jack"/>
* 自定义标签解析流程:
* a、根据当前解析标签的头信息找到对应的namespaceUri
* b、加载spring所有jar中的spring.handlers文件。并建立映射关系
* c、根据namespaceUri从映射关系中找到对应的实现了NamespaceHandler接口的类
* d、调用类的init方法,init方法是注册了各种自定义标签的解析类
* e、根据namespaceUri找到对应的解析类,然后调用paser方法完成标签解析
* 3、把解析出来的xml标签封装成BeanDefinition对象
*/
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
/*
* TODO 给beanFactory设置一些属性值
*/
prepareBeanFactory(beanFactory);
try {
postProcessBeanFactory(beanFactory);
/*
* TODO 完成对这两个接口的调用:
* BeanDefinitionRegistryPostProcessor
* BeanFactoryPostProcessor
*/
invokeBeanFactoryPostProcessors(beanFactory);
/*
* TODO 把实现了BeanPostProcessor接口的类实例化,并且加入到BeanFactory中
*/
registerBeanPostProcessors(beanFactory);
/*
* TODO 国际化,重要程度2
*/
initMessageSource();
// TODO 初始化事件管理类
initApplicationEventMulticaster();
// TODO 这个方法着重理解模板设计模式,因为在springboot中,这个方法是用来做内嵌tomcat启动的
onRefresh();
/*
* TODO 往事件管理类中注册事件类
*/
registerListeners();
/*
* TODO 这个方法是spring中最重要的方法,没有之一
* 所以这个方法一定要理解要具体看
* 1、bean实例化过程
* 2、ioc
* 3、注解支持
* 4、BeanPostProcesApplicationListenersor的执行
* 5、Aop的入口
*/
finishBeanFactoryInitialization(beanFactory);
// 完成刷新过程,通知生命周期处理器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
destroyBeans();
// Reset 'active' flag.
// 重置容器激活标签
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...
// 当我们可能再也不需要单例 bean的元数据时候,重置 Spring 核心的普通内存缓存
resetCommonCaches();
}
}
}
3.模板设计模式
在 spring 中大量使用了模板设计模式,可以说是用得最多的设计模式。
// 父类
public abstract class 爸爸 {
public void 生活() {
学习();
工作();
爱情();
}
public void 学习() {
System.out.println("====要认认真真学习====");
}
public void 工作() {
System.out.println("====主动承担责任====");
}
// 该方法就是一个钩子方法,通过子类的实现干预父类的方法的业务流程钩子方法挂载到父类方法中执行
// 这里爸爸不强迫孩子的爱情,孩子自己实现自己的爱情
public abstract void 爱情();
}
// 子类张三
public class 张三 extends 爸爸 {
@Override
public void 爱情() {
System.out.println("======找肤白貌美大长腿========");
}
}
// 子类李四
public class 张四 extends 爸爸 {
@Override
public void 爱情() {
System.out.println("======找有钱的=========");
}
}
// 测试类
public class Test {
public static void main(String[] args) {
爸爸 bb = new 张三();
bb.生活();
}
}
打印结果:
====要认认真真学习====
====主动承担责任====
======找肤白貌美大长腿========
4.BeanDefinition
BeanDefinition 在 Spring 中贯穿始终,Spring 要根据 BeanDefinition 对象来实 例化 Bean,把解析的标签、扫描的注解类封装成 BeanDefinition 对象,Spring 才能实例化。BeanDefinition 实现类有: ChildBeanDefinition、RootBeanDefinition、GenericBeanDefinition
4.1 ChildBeanDefinition
ChildBeanDefinition 继承自它父类的设置,即 ChildBeanDefinition 对 RootBeanDefinition 有一定的依赖关系。 ChildBeanDefinition 从父类继承构造参数值,属性值并可以重写父类的方法,同 时也可以增加新的属性或者方法。
4.2 RootBeanDefinition
是一个汇总的BeanDefiniiton,一个 RootBeanDefinition 定义表明它是一个可合并的 BeanDefinition,即在 Spring beanFactory 运行期间,可以返回一个特定的 bean。RootBeanDefinition 可 以作为一个重要的通用的 BeanDefinition 视图, RootBeanDefinition 用来在配置阶段进行注册BeanDefinition。
4.3 GenericBeanDefinition(重点)
GenericBeanDefinition继承于抽象的AbstractBeanDefinition,是一个泛化的beanDefinition,一个简易版本,它是为了方便使用,较为简单、通用。
它是一站式的标准BeanDefinition,除了具有指定类、可选的构造参数值和属性参数这些其它BeanDefinition一样的特性外,它还具有通过 parenetName 属性来灵活设置 parentBeaDefinition。另外,它支持动态定义父依赖,方法是:
GenericBeanDefinition.setParentName(java.lang.String),同时,GenericBeanDefinition 可以有效的替代 ChildBeanDefinition 的绝大分部使用场合。
4.4 ScannedGenericBeanDefinition
ScannedGenericBeanDefinition继承于GenericBeanDefinition,通过Compoent-scan扫描得到 ScannedGenericBeanDefinition(MetadataReader),MetadataReader包装了类的基本信息,通过MetadataReaderFactory()获取MetadataReader。
4.4 AnnotatedGenericBeanDefinition
它继承于GenericBeanDefinition,实现AnnotatedBeanDefinition接口,通过@Import注解导入进来、以及内部类解析得到 AnnotatedGenericBeanDefinition(AnnotationMetadata ); 通过AnnotationMetadata拿到相应的className(matadata.getClassName()),并设置到AnnotatedGenericBeanDefinition对象中,通过AnnotationMetadata获取类的基本属性。
4.6 ConfigurationClassBeanDefinition
ConfigurationClassBeanDefinition通过@Bean注解解析得到,它是内部使用的,我们无法创建,是私有的。
举例:用GenericBeanDefinition 创建实例:
@Data
public class BeanDefinitionBean {
private String name;
}
public class JamesImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) {
// 自己创建BeanDefinition对象,然后注册到BeanDefinitionRegistry中
GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
genericBeanDefinition.setBeanClass(BeanDefinitionBean.class);
MutablePropertyValues propertyValues = genericBeanDefinition.getPropertyValues();
propertyValues.add("name","Jack");
registry.registerBeanDefinition("beanDefinitionBean",genericBeanDefinition);
}
}
4.4 BeanDefinition中的属性
- id:Bean 的唯一标识名,它必须是合法的 XMLID,在整个 XML 文档中唯一;
- name:用来为 id 创建一个或多个别名,它可以是任意的字母符合,多个别名之间用逗号或空格分开;
- class:用来定义类的全限定名(包名+类名)。只有子类 Bean 不用定义该属性;
- parent:子类 Bean 定义它所引用它的父类 Bean,这时前面的 class 属性失效。子类 Bean 会继承父类 Bean 的所有属性,子类 Bean 也可以覆盖父类 Bean 的属性,注意:子类 Bean 和父类 Bean 是同一 个 Java 类。
- abstract(默认为”false”):用来定义 Bean 是否为抽象 Bean,它表示这个 Bean 将不会被实 例化,一般用于父类 Bean,因为父类 Bean 主要是供子类 Bean 继承使用;
- lazy-init(默认为“default”):用来定义这个 Bean 是否实现懒初始化,如果为“true”,它将 在 BeanFactory 启动时初始化所有的 SingletonBean。反之,如果为“false”,它只在 Bean 请求时才开 始创建 SingletonBean;
- autowire(自动装配,默认为“default”):它定义了 Bean 的自动装载方式,另外还有:
- “no”:不使用自动装配功能;
- “byName”:通过 Bean 的属性名实现自动装配;
- “byType”:通过 Bean 的类型实现自动装配;
- “constructor”:类似于 byType,但它是用于构造函数的参数的自动组装;
- “autodetect”:通过 Bean 类的反省机制(introspection)决定是使用“constructor” 还是使用“byType”。
8. depends-on(依赖对象):这个 Bean 在初始化时依赖的对象,这个对象会在这个 Bean 初始 化之前创建;
9. init-method:用来定义 Bean 的初始化方法,它会在 Bean 组装之后调用。它必须是一个无参数 的方法;
10. destroy-method:用来定义 Bean 的销毁方法,它在 BeanFactory 关闭时调用。同样,它也必 须是一个无参数的方法。它只能应用于 singletonBean;
11. factory-method:定义创建该 Bean 对象的工厂方法,它用于下面的“factory-bean”,表示 这个 Bean 是通过工厂方法创建,此时,“class”属性失效;
12. factory-bean:定义创建该 Bean 对象的工厂类,如果使用了“factory-bean”则“class”属性 失效;
13. autowire-candidate:采用 xml 格式配置 bean 时,将元素的 autowire-candidate 属性设置为 false,这样容器在查找自动装配对象时,将不考虑该 bean,即它不会被考虑作为其它 bean 自动装配的候选者,但是该 bean 本身还是可以使用自动装配来注入其它 bean 的;
14. MutablePropertyValues:用于封装标签的信息,其实类里面就是有一个 list,list 里面是 PropertyValue 对象,PropertyValue 就是一个 name 和 value 属性,用于封装标签 的名称和值信息;
15. ConstructorArgumentValues:用于封装标签的信息,其实类里面就是有 一个 map,map 中用构造函数的参数顺序作为 key,值作为 value 存储到 map 中;
16. MethodOverrides:用于封装 lookup-method 和 replaced-method 标签的信息,同样的类里 面有一个 Set 对象添加 LookupOverride 对象和 ReplaceOverride 对象。
最后
以上就是幽默枕头为你收集整理的Spring源码前置知识1. Spring 容器介绍:2. Spring 容器加载核心方法refresh()概览的全部内容,希望文章能够帮你解决Spring源码前置知识1. Spring 容器介绍:2. Spring 容器加载核心方法refresh()概览所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复