- 基本概念
- 自动配置
- 1:从0开始
- 2: new SpringApplication
- 2.1 deduceFromClasspath 猜一下环境类型? 默认的就是 SERVLET
- 3: getSpringFactoriesInstances
- 4:重点看 SpringFactoriesLoader.loadFactoryNames
- 5:loadSpringFactories 干活的,根据类加载器读取配置文件
- 6:run方法
- _7:_createApplicationContext 创建容器
- 8:这个类关系挺乱。。先上图
- ">
- 9: 接下来是重点refreshContext
- _10.先搞清楚一个重要概念 _beanFactory ,后面会不断的出现
- 12:invokeBeanFactoryPostProcessors
- 13:对上面两个参数分类,放到列表中,并调用他们的 postProcessBeanDefinitionRegistry 方法
基本概念
启动原理
参考 https://www.cnblogs.com/theRhyme/p/11057233.html#_label1
https://www.jianshu.com/p/87f101d8ec41
1:ioc/DI
参考:https://blog.csdn.net/ivan820819/article/details/79744797
一种编程思想,引入容器管理对象,使得对象之间解耦
实现原理参考 https://blog.csdn.net/vannesspeng/article/details/79486922
2:aop
参考:https://www.cnblogs.com/joy99/p/10941543.html
面向切面编程,一种编程思想。(类似python的装饰器)可以自定义作用范围
基本使用demo
导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
@Aspect
@Component
public class AcceptUtil {
@Pointcut("execution(public * com.example..*.*(..))") //定义切入点
public void acceptUtil(){}
@After("acceptUtil()")
public void after(JoinPoint joinPoint){
System.out.println("执行 after");
}
@Before("acceptUtil()")
public void before(JoinPoint joinPoint){
System.out.println("执行 before");
}
@Around("acceptUtil()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("=====前");
Object proceed = joinPoint.proceed();
System.out.println("=====后");
return proceed;
}
}
自定义注解
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface CusomAop { }
//注解实现
@Aspect
@Component
public class CusomAopImpl {
@Around("@annotation(CusomAop)")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("执行开始时间"+new Date());
Object proceed = joinPoint.proceed();
System.out.println("执行结束时间"+new Date());
return proceed;
}
}
自动配置
1:从0开始
2: new SpringApplication
3
2.1 deduceFromClasspath 猜一下环境类型? 默认的就是 SERVLET
3: getSpringFactoriesInstances
4:重点看 SpringFactoriesLoader.loadFactoryNames
这个方法是从 spring.factories 中读取配置信息,然后获取指定的 _factoryType 内容
_spring.factories 长这样,,key:value形式,_factoryType 就是key
5:loadSpringFactories 干活的,根据类加载器读取配置文件
=====第一部分结束。此时已经拿到了 spring.factories 中所有的配置信息
_cache 结构 { classLoad :{factories : [ ……] ,….} }
6:run方法
7:环境 prepareEnvironment
返回一个 SERVLET 环境 ==直译就是标准的SERVLET 环境 。。。
_7:_createApplicationContext 创建容器
所以这里返回的就是 AnnotationConfigServletWebServerApplicationContext
8:这个类关系挺乱。。先上图
9: 接下来是重点refreshContext
一直委托到 父类 ,在 AbstractApplicationContext 上面的图中能找到
_10.先搞清楚一个重要概念 _beanFactory ,后面会不断的出现
obtainFreshBeanFactory 看这个方法
顾名思义,这是一个bean工厂
他是哪来的?
还得从 _7:_createApplicationContext 创建容器 说起 根据 7.1 的图,AnnotationConfigServletWebServerApplicationContext 实例化时
调用父类
ServletWebServerApplicationContext 无参
再调用 父类 GenericWebApplicationContext 无参
最终到
这是默认的beanFactory DefaultListableBeanFactory
10.1 DefaultListableBeanFactory 关系图
10.2:prepareBeanFactory 对beanFactory 一顿设置,不知道干啥,有空看?
12:invokeBeanFactoryPostProcessors
12.1 里面的 参数 getBeanFactoryPostProcessors()
两个参数是在 2 中初始化的 都实现了 ApplicationContextInitializer接口
13:对上面两个参数分类,放到列表中,并调用他们的 postProcessBeanDefinitionRegistry 方法
13.1 分别看一下两个的 postProcessBeanDefinitionRegistry 方法
13.1.1:CachingMetadataReaderFactoryPostProcessor
两个操作
1:注册bean,
生成bean 并放到 beanDefinitionMap和 beanDefinitionNames 中
beanDefinitionMap 名称更实例的map
beanDefinitionNames 这里放置bean名称
13.1.2 configureConfigurationClassPostProcessor 方法
没看明白这个,好像是拿bean的回调方法,如果没有,给他配置一个默认的
14 :拿到实现 BeanDefinitionRegistryPostProcessor 接口的bean列表
这两块代码重复了?都是拿到以后调用 postProcessBeanDefinitionRegistry 方法
15: ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry
这个用于扫描所有注解,比如contorller comport
类图
16:委托到 processConfigBeanDefinitions方法
看 checkConfigurationClassCandidate
拿到包含 Configuration 注解的方法
中间一顿操作。。。。
这里定义了一个配置解析器,用于解析注解
17:parse 方法
委托到 processConfigurationClass方法
18:doProcessConfigurationClass 真正干活的
一顿操作拿到当前解析类下所有 注解
拿到后 调用parse方法调用 processConfigurationClass 放到 configurationClasses 中
处理其他注解,这里就跟上面重复了
如果没有指定读取器,给一个默认的
拿到所有bean名称,
====第二部分结束,当前所有默认配置及自定义配置bean都已经扫描
并且处理好了接口方法
开始扫描根目录