0%

前言

SpringBoot 的入口方法如下,入口方法有2个特征

  1. 声明注解@SpringBootApplication
  2. main方法中调用方法org.springframework.boot.SpringApplication#run(java.lang.Class<?>, java.lang.String...)
1
2
3
4
5
6
7
8
// 如下是简洁版本。
// 通常用户会根据业务需求额外声明一些注解,例如`@PropertySource`,`@ComponentScan`等,参见其它篇章。
@SpringBootApplication
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}

SpringApplication 构造方法

源码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// org.springframework.boot.SpringApplication#SpringApplication(org.springframework.core.io.ResourceLoader, java.lang.Class<?>...)
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    this.resourceLoader = resourceLoader;
    Assert.notNull(primarySources, "PrimarySources must not be null");
    // primarySources 默认为声明注解`@SpringBootApplication`(通常也是调用`SpringApplication#run`的`main`方法)的所在类。
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    // 从 classpath 探测 web application type,通常为`org.springframework.boot.WebApplicationType#SERVLET`。
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    // 从"META-INF/ spring.factories"探测`BootstrapRegistryInitializer.class`的实现类。
    this.bootstrapRegistryInitializers = new ArrayList<>(
            getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
    // 从"META-INF/ spring.factories"探测`ApplicationContextInitializer.class`的实现类。
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    // 从"META-INF/ spring.factories"探测`ApplicationListener.class`的实现类。
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    // 探测 main 方法所在的类,具体方式是获取堆栈信息后过滤 main 方法。
    this.mainApplicationClass = deduceMainApplicationClass();
}

自动配置类 ApplicationContextInitializer 和 ApplicationListener 介绍

SpringBoot 自动配置ApplicationContextInitializer实现,详情如下

前言

SpringBoot 采用“约定大于配置”的思想。

SpringBoot 支持自动配置。

约定大于配置

“约定大于配置”(Convention Over Configuration)是一种软件设计范式,其核心思想是:框架为开发者提供一套默认的、符合大多数人习惯的约定(标准、规范),开发者只需要在不遵守这些约定时,才需要显式地编写配置来指定自己的行为。

基本配置信息

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
-- 切换数据库
USE test;

-- 查询数据库版本
SELECT VERSION();

-- 查询当前数据库
SELECT DATABASE();

-- 查询当前用户
SELECT USER();

-- 查询对象名称大小写敏感性
-- 0 Linux 敏感
-- 1 Windows 不敏感
-- 2 Mac
SHOW VARIABLES LIKE '%lower_case_table_names%';
SELECT @@SESSION.lower_case_table_names;

-- 查询字符集与排序规则
SHOW VARIABLES LIKE '%character%';
SHOW VARIABLES LIKE '%collation%';

-- 查询严格模式
SHOW VARIABLES LIKE '%innodb_strict_mode%';

-- 查询 SQL 模式
SHOW VARIABLES LIKE '%sql_mode%';
SHOW VARIABLES LIKE '%mode%';
SELECT @@SESSION.sql_mode;

-- 默认存储引擎
SHOW VARIABLES LIKE 'default_storage_engine';
-- InnoDB 状态
SHOW ENGINE INNODB STATUS;

-- 系统时区
SHOW VARIABLES LIKE 'system_time_zone';
-- 当前时区
SHOW VARIABLES LIKE 'time_zone';

事务与锁相关

事务

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
-- 查询自动提交模式
SHOW VARIABLES LIKE '%autocommit%';
SELECT @@SESSION.autocommit;

-- 查询事务 ID
SELECT trx_id FROM information_schema.innodb_trx WHERE trx_mysql_thread_id = CONNECTION_ID();

-- 查看全局和会话隔离级别
SELECT @@GLOBAL.transaction_isolation, @@SESSION.transaction_isolation;

-- 查看所有支持的隔离级别
SHOW VARIABLES LIKE 'transaction_isolation';

-- 查看隔离级别相关统计
SELECT * FROM performance_schema.events_transactions_summary_global_by_event_name;

-- InnoDB 重做日志(Redo Log)刷新控制
-- 0: 每秒写入并刷新日志到磁盘(性能最好,安全性最低)
-- 1: 每次事务提交都写入并刷新日志(默认值,最安全,性能较差)
-- 2: 每次事务提交写入日志,但每秒刷新一次到磁盘(折中方案)
SHOW VARIABLES LIKE 'innodb_flush_log_at_trx_commit%';

-- 二进制日志(Binlog)刷新控制
-- 0: 依赖操作系统刷新(性能最好,安全性最低)
-- 1: 每次事务提交都同步(默认值,最安全)
-- N: 每N次事务提交同步一次
SHOW VARIABLES LIKE 'sync_binlog%';

锁检测与死锁

锁超时

参数校验异常

request 请求参数解析可能抛出 3 种常见异常

  1. MethodArgumentNotValidException
    1. 场景:@RequestBody修饰的入参校验
    2. 处理器:RequestResponseBodyMethodProcessor
  2. BindException
    1. 场景:未使用 @RequestBody@RequestParam等注解修饰的入参校验,且入参对象被@Valid@Validated相关注解修饰。
    2. 处理器:ServletModelAttributeMethodProcessor/ModelAttributeMethodProcessor
  3. ConstraintViolationException
    1. 场景:类被@Validated注解修饰,且未使用 @RequestBody修饰入参对象,且入参对象被@Constraint相关注解修饰。
    2. 处理器:org.springframework.validation.beanvalidation.MethodValidationInterceptor

@Validated注解修饰的类的方法均会由 MethodValidationInterceptor 拦截器校验参数,优先级低于请求参数处理器(例如 RequestResponseBodyMethodProcessor)。

请求入口

1
2
3
4
5
6
7
-> Tomcat 网络连接
-> StandardEngineValve
-> StandardHostValve
-> StandardContextValve
-> StandardContextValve
-> ApplicationFilterChain
-> HttpServlet

Servlet 入口

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// 请求流程
// javax.servlet.http.HttpServlet#service(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
-> org.springframework.web.servlet.FrameworkServlet#service
    -> 如果是 PATCH 方法或空方法if (httpMethod == HttpMethod.PATCH || httpMethod == null) 
        -> 详情参加 POST 方法org.springframework.web.servlet.FrameworkServlet#processRequest
    -> javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
        -> 根据方法类型路由到不同的方法
            -> GETlastModified 参数相关适配
            -> POSTorg.springframework.web.servlet.FrameworkServlet#doPost
                -> org.springframework.web.servlet.FrameworkServlet#processRequest
                    -> LocaleContextRequestAttributes 等处理
                    -> org.springframework.web.servlet.DispatcherServlet#doService
                        -> 详情参加分支 DispatcherServlet#doDispatchorg.springframework.web.servlet.DispatcherServlet#doDispatch
            -> PUT
            -> OPTION
            -> 其它方法略

请求分发

分支 DispatcherServlet#doDispatch

  1. Aspect 使用场景
  2. 接口定义 Advice/Pointcut/Advisor
  3. Aspect 执行顺序
  4. Aspect-Bean解析流程
    1. SmartInstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation
    2. SmartInstantiationAwareBeanPostProcessor#postProcessAfterInitialization
  5. Aspect-Interceptor执行流程
    1. JdkDynamicAopProxy#invoke
    2. DynamicAdvisedInterceptor#intercept
    3. ReflectiveMethodInvocation#proceed

  1. PointcutAdvisor = Advice + Pointcut
  2. Advice: AspectJAroundAdvice/AspectJMethodBeforeAdvice/AspectJAfterAdvice/AspectJAfterReturningAdvice/AspectJAfterThrowingAdvice
  3. Pointcut: AspectJExpressionPointcut
  4. PointcutAdvisor: InstantiationModelAwarePointcutAdvisorImpl instanceof PointcutAdvisor
  5. Advisor refers to PointcutAdvisor
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// 声明式
org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator
-> org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator
-> org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator
-> org.springframework.aop.framework.autoproxy.InfrastructureAdvisorAutoProxyCreator
org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator


// 编程式
org.springframework.aop.framework.ProxyFactory
org.springframework.aop.aspectj.annotation.AspectJProxyFactory
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator
 bean name 过滤期望被 AOP 代理的普通 bean
-> org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator#getAdvicesAndAdvisorsForBean
    -> org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator#isSupportedBeanName
        -> org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator#isMatch
配置 advisor/advice/interceptor参见 org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#resolveInterceptorNames
-> org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#setInterceptorNames


org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator
 advisor bean name 过滤 advisor
-> org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator#isEligibleAdvisorBean
    -> org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator#getAdvisorBeanNamePrefix


org.springframework.aop.framework.ProxyFactoryBean
工厂模式创建代理
过滤 advisor/advice/interceptor相关注释 The referenced beans should be of type Interceptor, Advisor or Advice.
-> org.springframework.aop.framework.ProxyFactoryBean#setInterceptorNames

END

HandlerAdapter 介绍

简介

在 Spring MVC 中,HandlerAdapter 是核心组件之一,负责协调控制器(Handler)的执行流程。它的主要作用是适配不同类型的处理器(Handler),使它们能够统一处理请求。

Aspect 动态代理方式

在Spring AOP中,如果目标类实现了至少一个接口,Spring默认会使用JDK动态代理。

JDK动态代理只能代理接口中定义的方法。普通类自身定义的方法(未在接口中声明)不会被代理,代理对象无法“看到”这个方法。

ExposeInvocationInterceptor

将 MethodInvocation 存储到 ThreadLocal 变量中。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
public final class ExposeInvocationInterceptor implements MethodInterceptor, PriorityOrdered, Serializable {
	private static final ThreadLocal<MethodInvocation> invocation =
			new NamedThreadLocal<>("Current AOP method invocation");
	public static MethodInvocation currentInvocation() throws IllegalStateException {
		MethodInvocation mi = invocation.get();
        //...
    }
	@Override
	@Nullable
	public Object invoke(MethodInvocation mi) throws Throwable {
		MethodInvocation oldInvocation = invocation.get();
		invocation.set(mi);
		try {
			return mi.proceed();
		}
		finally {
			invocation.set(oldInvocation);
		}
	}
}

END