spring分析

spring加载

启动tomcat服务器时,会读取项目中的web.xml文件来启动具体的服务;在servelet3.0后,web.xml文件消失,通过读取包目录中META-INF/services文件夹中描述文件加载启动指定的服务;这种机制称为spi机制;

  • 基于web.xml文件

  • 基于描述文件加载

描述文件名为服务接口类名称该接口由servelet提供,并需要实现onStartup方法;描述文件内容为具体服务启动对象类名称实现刚才的接口,由spring实现

image-20210419155730218

在spring中如下

image-20210419160027602

启动Spring

  1. Spring实现Servelet3.0的SPI规范,实现了接口极其方法onStartup()
  2. Tomcat依据规范调用这个接口的onStartup()方法
  3. Spring依据HandlesTypes注解描述的接口,将所有实现类注入到onStartup()方法的Set集合参数中
    • 下述接口是Spring提供的接口,也是HandlesTypes注解描述中的接口
  4. 根据Set集合中的类,创建对象
  5. 执行这些对象的onStartup方法
1
2
3
4
5
6
7
8
9
10
11
12
13
public interface WebApplicationInitializer {

/**
* Configure the given {@link ServletContext} with any servlets, filters, listeners
* context-params and attributes necessary for initializing this web application. See
* examples {@linkplain WebApplicationInitializer above}.
* @param servletContext the {@code ServletContext} to initialize
* @throws ServletException if any call against the given {@code ServletContext}
* throws a {@code ServletException}
*/
void onStartup(ServletContext servletContext) throws ServletException;

}

启动配置类

由上分析可见spring的启动类为org.springframework.web.SpringServletContainerInitializer,该类负责加载spring所需的组件;

其中@HandlesTypes注解修饰的接口为具体要加载的配置类接口(WebApplicationInitializer),我们可以实现它完成spring框架的整合以及spring相关组件的配置

  • 如下所示MyWebApplicationInitializer也是WebApplicationInitializer接口的子类实现
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
/***
* 该类配置来源于spring官网
* tomcat 启动时会加载此类,然后执行相关方法
* 完成初始化动作(此类中要完成原web.xml中要
* 执行的一些操作)
*/
public class MyWebApplicationInitializer implements WebApplicationInitializer {

@Override
public void onStartup(ServletContext servletContext) {

// 生成IOC容器
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
// 注册配置类,配置类由我们实现
context.register(AppConfig.class);

// Create and register the DispatcherServlet
// 创建DispatcherServlet
DispatcherServlet servlet = new DispatcherServlet(context);
// 向servlet容器对象注册创建DispatchdespacerServlet
// DispatcherServlet有对应的doGet,doPost方法(存在继承父类中),注册后Tomcat就能把请求分发给DispatcherServlet了
ServletRegistration.Dynamic registration = servletContext.addServlet("app", servlet);
registration.setLoadOnStartup(1);
registration.addMapping("/app/*");
}
}
  • 我们继承AbstractAnnotationConfigDispatcherServletInitializer并实现它的抽象方法以达到自定义配置的实现
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package com.db.common.config;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;

import org.springframework.web.filter.DelegatingFilterProxy;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
/***
* tomcat 启动时会加载此类,然后执行相关方法
* 完成初始化动作(此类中要完成原web.xml中要
* 执行的一些操作)
* @author ta
*/
public class AppWebInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
//此类对象在执行时首先会执行onStartup方法完成一些初始化操作
//并且会注册spring mvc前端控制器
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
System.out.println("onStartup()");
//super.onStartup(servletContext);
registerContextLoaderListener(servletContext);
registerFilter(servletContext);
registerDispatcherServlet(servletContext);
}
//注册shiro中的核心过滤器
private void registerFilter(ServletContext servletContext) {
//注册Filter对象
//什么时候需要采用此方式进行注册?
//项目没有web.xml并且此filter不是自己写的
FilterRegistration.Dynamic dy=
servletContext.addFilter("filterProxy",
DelegatingFilterProxy.class);
dy.setInitParameter("targetBeanName","shiroFilterFactory");
dy.addMappingForUrlPatterns(
null,//EnumSet<DispatcherType>
false,"/*");//url-pattern
}

//官方建议在此方法中加载model(service,respository)
@Override
protected Class<?>[] getRootConfigClasses() {
System.out.println("getRootConfigClasses()");
//return new Class[]{AppDataSourceConfig.class,AppMyBatisConfig.class};
return new Class[]{AppRootConfig.class};
}
//官方建议在此方法中加载View,Controller,...
@Override
protected Class<?>[] getServletConfigClasses() {
System.out.println("getServletConfigClasses()");
return new Class[]{AppMvcConfig.class};
}
//官方建议在此方法中定义请求映射
@Override
protected String[] getServletMappings() {
System.out.println("getServletMappings()");
//由前端控制器处理所有以.do结尾的请求
return new String[]{"*.do"};
}
}

SpringIOC

ioc容器核心来源于两个map,分别以Map<String beanName,BeanDefinition definition>,Map<String beanName,Object object>的方式存储数据;

他们都属于BeanFactory接口下的对象

IOC加载流程

核心控制类

AbstractApplicationContext类的refresh()方法控制了IOC容器的加载流程,其中比较关键的几步如下:

  1. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();,创建BeanFactory,注册BeanDefinition
  2. prepareBeanFactory(beanFactory);,准备类加载器,用于创建对象
  3. finishBeanFactoryInitialization(beanFactory);,初始化singleton的Bean对象
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
@Override
public void refresh() throws BeansException, IllegalStateException {
// 来个锁,不然 refresh() 还没结束,你又来个启动或销毁容器的操作,那不就乱套了嘛
synchronized (this.startupShutdownMonitor) {

// 准备工作,记录下容器的启动时间、标记“已启动”状态、处理配置文件中的占位符
prepareRefresh();

// 这步比较关键,这步完成后,配置文件就会解析成一个个 Bean 定义,注册到 BeanFactory 中,
// 当然,这里说的 Bean 还没有初始化,只是配置信息都提取出来了,
// 注册也只是将这些信息都保存到了注册中心(说到底核心是一个 beanName-> beanDefinition 的 map)
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// 设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean
// 这块待会会展开说
prepareBeanFactory(beanFactory);

try {
// 【这里需要知道 BeanFactoryPostProcessor 这个知识点,Bean 如果实现了此接口,
// 那么在容器初始化以后,Spring 会负责调用里面的 postProcessBeanFactory 方法。】

// 这里是提供给子类的扩展点,到这里的时候,所有的 Bean 都加载、注册完成了,但是都还没有初始化
// 具体的子类可以在这步的时候添加一些特殊的 BeanFactoryPostProcessor 的实现类或做点什么事
postProcessBeanFactory(beanFactory);
// 调用 BeanFactoryPostProcessor 各个实现类的 postProcessBeanFactory(factory) 方法
invokeBeanFactoryPostProcessors(beanFactory);

// 注册 BeanPostProcessor 的实现类,注意看和 BeanFactoryPostProcessor 的区别
// 此接口两个方法: postProcessBeforeInitialization 和 postProcessAfterInitialization
// 两个方法分别在 Bean 初始化之前和初始化之后得到执行。注意,到这里 Bean 还没初始化
registerBeanPostProcessors(beanFactory);

// 初始化当前 ApplicationContext 的 MessageSource,国际化这里就不展开说了,不然没完没了了
initMessageSource();

// 初始化当前 ApplicationContext 的事件广播器,这里也不展开了
initApplicationEventMulticaster();

// 从方法名就可以知道,典型的模板方法(钩子方法),
// 具体的子类可以在这里初始化一些特殊的 Bean(在初始化 singleton beans 之前)
onRefresh();

// 注册事件监听器,监听器需要实现 ApplicationListener 接口。这也不是我们的重点,过
registerListeners();

// 重点,重点,重点
// 初始化所有的 singleton beans
//(lazy-init 的除外)
finishBeanFactoryInitialization(beanFactory);

// 最后,广播事件,ApplicationContext 初始化完成
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.
// 销毁已经初始化的 singleton 的 Beans,以免有些 bean 会一直占用资源
destroyBeans();

// Reset 'active' flag.
cancelRefresh(ex);

// 把异常往外抛
throw ex;
}

finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
//代码注释解析来自博客https://blog.csdn.net/nuomizhende45/article/details/81158383/

创建BeanFactory,注册BeanDefinition

需要注意以下几点

  1. 初始三各类继承关系如下,AbstractApplicationContext→AbstractRefreshableApplicationContext→AbstractXmlApplicationContext
  2. AbstractRefreshableApplicationContext类会创建Bean工厂“DefaultListableBeanFactory”该工厂内涵几个核心Map,后续流程中会被注入到BeanDefinitionReader对象中用于BeanDefinition的注入
  3. DefaultBeanDefinitionDocumentReader通过委派BeanDefinitionParserDelegate来实现BeanDefinition的封装,核心流程均由这个被委派这完成
  4. 后续会通过BeanDefinitionReaderUtils的静态方法registerBeanDefinition()注册BeanDefition,实际上Spring框架在多个地方都调用该方法手动注册一些Spring核心类
BeamDefinition

准备类加载器

该方法主要职责在第一行,设置类加载器;

需要注意,目前该方法始终是在AbstractApplicationContext类中的,而AbstractApplicationContext继承自DefaultResourceLoader,在DefaultResourceLoader的无参构造函数中就通过this.classLoader = ClassUtils.getDefaultClassLoader();来创建获取类加载器

ClassUtils是Spring框架的类对象操作工具类,可提取出来学习利用

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71

/**
* Configure the factory's standard context characteristics,
* such as the context's ClassLoader and post-processors.
* @param beanFactory the BeanFactory to configure
*/
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 设置 BeanFactory 的类加载器,我们知道 BeanFactory 需要加载类,也就需要类加载器,
// 这里设置为当前 ApplicationContext 的类加载器
beanFactory.setBeanClassLoader(getClassLoader());
// 设置 BeanExpressionResolver
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
//
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

// 添加一个 BeanPostProcessor,这个 processor 比较简单,
// 实现了 Aware 接口的几个特殊的 beans 在初始化的时候,这个 processor 负责回调
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

// 下面几行的意思就是,如果某个 bean 依赖于以下几个接口的实现类,在自动装配的时候忽略它们,
// Spring 会通过其他方式来处理这些依赖。
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

/**
* 下面几行就是为特殊的几个 bean 赋值,如果有 bean 依赖了以下几个,会注入这边相应的值,
* 之前我们说过,"当前 ApplicationContext 持有一个 BeanFactory",这里解释了第一行
* ApplicationContext 继承了 ResourceLoader、ApplicationEventPublisher、MessageSource
* 所以对于这几个,可以赋值为 this,注意 this 是一个 ApplicationContext
* 那这里怎么没看到为 MessageSource 赋值呢?那是因为 MessageSource 被注册成为了一个普通的 bean
*/
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);

// 这个 BeanPostProcessor 也很简单,在 bean 实例化后,如果是 ApplicationListener 的子类,
// 那么将其添加到 listener 列表中,可以理解成:注册事件监听器
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

// Detect a LoadTimeWeaver and prepare for weaving, if found.
// 这里涉及到特殊的 bean,名为:loadTimeWeaver,这不是我们的重点,忽略它
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}

/**
* 从下面几行代码我们可以知道,Spring 往往很 "智能" 就是因为它会帮我们默认注册一些有用的 bean,
* 我们也可以选择覆盖
*/

// 如果没有定义 "environment" 这个 bean,那么 Spring 会 "手动" 注册一个
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
// 如果没有定义 "systemProperties" 这个 bean,那么 Spring 会 "手动" 注册一个
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
// 如果没有定义 "systemEnvironment" 这个 bean,那么 Spring 会 "手动" 注册一个
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
//代码注释解析来自博客https://blog.csdn.net/nuomizhende45/article/details/81158383/

后置处理器

后置处理器有两种,BeanFactoryPostProcessor和BeanPostProcessor

  • BeanFactoryPostProcessor:用于拓展Spring框架,内部可得到Bean容器,操作BeanDefinition
  • BeanPostProcessor:用于增加Bean生命周期操作

此时还没有创建Bean对象,这里只讲BeanFactoryPostProcessor,Spring主要的后置处理较多,这里距离三个常用到的

  • PropertySourcesPlaceholderConfigurer:处理配置类占位符${..}
  • ConfigurationClassParser:识别注解标签,创建对应的BeanDefiniton

初始化Bean对象

Bean对象的初始化利用到了反射技术,核心操作类如图可见为AbstractAutowireCapableBeanFactory.java,它负责了bean对象的创建,属性注入,init方法和后置处理器的调度使用

可将getBean()方法看作bean的初始化开启方法,我们经常通过applictionContext.getBean()方法获取bean,两者是同一个方法

Bean初始化

SpringMVC

SpringMVC核心是DispatcherServlet对象,核心方法是doDispatch()

1
DispatcherServlet

由于DispatcherServlet是个Servlet对象,虽然没有doGet,doPost方法(实际已被父类实现),但请求最终会进入该类的doService()->doDispatch()

Controller对象中的方法和映射如何匹配?

1
2
3
4
5
6
7
@Controller
public class MyController{//类加载(将类读到内存)-->Class
@RequestMapping("doIndexUI")
public String doIndexUI(){
return "starter";//WEB-INF/pages/starter.html
}
}

SpringMvc找Controller流程

  1. 扫描项目所有包,注册所有注解和配置描述的bean,由ioc容器预先完成
  2. @拿到所有Controller类
  3. 遍历类中的所有方法对象Method.class
  4. 判断方法是否添加了@RequestMapping注解
  5. 将RequestMapping注解中的描述如:”doIndexUI”作为key,步骤4的方法对象作为value存入map集合中
  6. 容器启动完成
  7. 根据用户发送的请求,拦截获取URI 注:URL=http://localhost:80/test.do URI=/test.do
  8. 根据URI(/test.do)查找Map集合获取Method方法对象
  9. 通过反射调用Method方法

DispatcherSerblet主流程

注意,此时容器已启动完成,用户请求发送通过servlet传递进入doDispatch()方法

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;

WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

try {
ModelAndView mv = null;
Exception dispatchException = null;

try {
// 处理确认所有的带有二进制文件的请求,遵循http协议,判断请求中的描述符确认
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);

// Determine handler for the current request.
// 根据请求获取mapperHandler,即Controller对象或映射指定的Method对象
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}

// Determine handler adapter for the current request.
// 获取Handler适配器,原理同getHandler,根据情况获取不同种类的Handler适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}

if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}

// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

if (asyncManager.isConcurrentHandlingStarted()) {
return;
}

applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}

获取MethodHandler

  • 通过getHandler(processedRequest);开启

MethodHandler可能是Controller控制器的封装类,也可能是对应Method对象的封装类

DispacherServlet对象有一个HandelrMapping对象集合,HandlerMapping对象里的Map集合用来存储之前描述的Method对象;之所以有不同的HandlerMapping是由于Spring有多种Controller的实现,需要不同的Handler处理

image-20210501184910811

  • 最终HandlerMapping们会通过自身集合中的Map集合获取到对应的Method或对象
  • 上述代码最终返回HandlerMethod,它实际上是uri和对应Method对象的包装类,也可以理解为Controller

获取Handler

由图可见,不同的HandlerMapping有不同的Map集合,分情况进入

Controller案例1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* 类型1Controller,通过注解@Controller实现
*/
@Controller
@RequestMapping("/ControllerType1/")
public class ControllerType1 {
@RequestMapping("getPathValue")
@ResponseBody
public String testController(@PathVariable String name){
System.out.println("Controller2执行");
System.out.println("hello,"+name);
return "hello,"+name;
}
}

Controller案例2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* 基于实现Controller接口实现Controller
*/
@Component("/ControllerType2")
public class ControllerType2 implements Controller {

@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 通过paramMap读取请求参数手动操作数据
// Map<String, String[]> parameterMap = request.getParameterMap();
System.out.println("Controller2执行");
return new ModelAndView("Controller2,say hello");
}
}

请求分发

handlerAdapter.handle()

根据情况调用适当的适配器后,通过适配器调用实际要进入的方法,这里分上述两个Controller案例分析

案例一,基于实现Controller接口

原理很简单,直接调用Controller对象的的对应方法即可

1
2
3
4
5
6
7
8
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
//参数4的handler就是先前被封装的Controller对象
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {

return ((Controller) handler).handleRequest(request, response);
}
}

案例二,基于注解RequestMapping

部分源码跳过

获取参数处理器

参数处理器中的参数指的时Controller中映射方法的参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
//先从缓存中获取
HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
if (result == null) {
for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
//基于不同参数处理器的supportsParameter方法判定
if (resolver.supportsParameter(parameter)) {
result = resolver;
this.argumentResolverCache.put(parameter, result);
break;
}
}
}
return result;
}

举例几个参数处理器案例

  • 当请求方法中有@RequestBody注解时,直接通过参数中的注解判断
1
2
3
4
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(RequestBody.class);
}
  • 当请求方法参数中有@RequestParam时,通过是否含注解判断
1
2
3
4
5
6
@Override
public boolean supportsParameter(MethodParameter parameter) {
RequestParam requestParam = parameter.getParameterAnnotation(RequestParam.class);
return (requestParam != null && Map.class.isAssignableFrom(parameter.getParameterType()) &&
!StringUtils.hasText(requestParam.name()));
}
  • 当请求方法参数中有@PathVariable也同理
1
2
3
4
5
6
@Override
public boolean supportsParameter(MethodParameter parameter) {
PathVariable ann = parameter.getParameterAnnotation(PathVariable.class);
return (ann != null && Map.class.isAssignableFrom(parameter.getParameterType()) &&
!StringUtils.hasText(ann.value()));
}

不同参数处理器有不同的操作,依据需要装配的类型而定,后续不一一例举了,可自行查看HandlerMethodArgumentResolver接口下的子类

SpringAOP

代理对象创建

代理对象创建在Bean生命周期init方法之后执行,由Spring内置的后置处理器BeanPostProcess实现

  • 该方法在AbstractAutowireCapableBeanFactory类中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {

Object result = existingBean;
//循环执行所有后置处理器
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
  • 代理对象创建主要逻辑
  • 具体实现通知类为AbstractAutoProxyCreator
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
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}

// 创建并获取所有的通知,通知会被加入通知缓存
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
//创建代理对象
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
// 代理对象加入缓存
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
  • 匹配可用通知
  • 创建代理对象工厂
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
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {

if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
//场景代理对象工厂为工厂注入属性
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) {
//此处逻辑判断依据需要被代理类是否有接口
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
//有接口则进入以下逻辑为工厂添加接口
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
//筛选通知,找到对应的通知
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
//设置通知
proxyFactory.addAdvisors(advisors);
//设置目标类,后续代理对象需要调用原方法时,通过该对象调用
proxyFactory.setTargetSource(targetSource);
//钩子方法,无具体实现
customizeProxyFactory(proxyFactory);

proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
//通过工厂创建代理对象
return proxyFactory.getProxy(getProxyClassLoader());
}
  • 接下来进入代理工厂

ProxyFactory

代理后置处理器会createAopProxy().getProxy(classLoader);方法依据条件调用后对应的代理创建方法;

工厂依据事先设置的属性判断创建何种代理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
//jdk动态代理
return new JdkDynamicAopProxy(config);
}
//CGLIB代理
return new ObjenesisCglibAopProxy(config);
}
else {
//jdk动态代理
return new JdkDynamicAopProxy(config);
}
}

通知的执行

无论切面是基于JDK还是CGLIB实现,均会调用特定方法获取到通知集合(adviceChain),通过这个集合SpringAOP基于责任链的模式实现了通知方法的切入

  • 通知集合总是以特定顺序排序

createMethodHandler

  • 通知通过传递MethodInvocation对象实现责任链模式
  • methodInvocation.proceed()能进入MethodInvocation对象中遍历数组找到下一个通知并进入对应invoke()方法,它们以类似递归的方式执行
  • invokeAdviceMethod()方法为调用通知,底层基于反射调用对应通知

adviceChain

通知具体分析

五种不同的通知实现的方式和承担的职责不同,以下对核心代码分析

arround环绕同通知

1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
if (!(mi instanceof ProxyMethodInvocation)) {
throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
}
ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
//为环绕通知创建ProceedingJoinPoint对象,将作为参数注入具体的通知方法以供用户使用
//通过这个JoinPoint能重新进入MethodHandler的proceed()方法继续通知责任链
ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
JoinPointMatch jpm = getJoinPointMatch(pmi);
//调用通知方法
return invokeAdviceMethod(pjp, jpm, null, null);
}

before前置通知

1
2
3
4
5
6
7
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
//没什么好讲的,先执行通知方法
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
//再重新进入MethodHandler继续责任链
return mi.proceed();
}

after后置通知

1
2
3
4
5
6
7
8
9
10
11
public Object invoke(MethodInvocation mi) throws Throwable {
try {
//先进入责任链
return mi.proceed();
}
finally {
//后执行通知
//可见后置通知执行代码是再finally块的,因此无论是否异常都会执行
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}

afterReturning返回通知

1
2
3
4
5
6
7
public Object invoke(MethodInvocation mi) throws Throwable {
Object retVal = mi.proceed();
//先进入责任链
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
//后执行通知
return retVal;
}

afterThrowing异常通知

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public Object invoke(MethodInvocation mi) throws Throwable {
try {
//先进入责任链
return mi.proceed();
}
//可见由于通知在异常代码块中,只有代码出现异常才会执行该通知
catch (Throwable ex) {
if (shouldInvokeOnThrowing(ex)) {
//出现异常后执行通知
invokeAdviceMethod(getJoinPointMatch(), null, ex);
}
throw ex;
}
}

spring分析
https://andrewjiao.github.io/2020/06/12/Spring/
作者
Andrew_Jiao
发布于
2020年6月12日
许可协议