您当前的位置:首页 > 电脑百科 > 程序开发 > 容器

Spring启动原理和可扩展设计分析

时间:2020-06-24 14:03:22  来源:  作者:

Spring启动原理和可扩展设计分析

简述

spring核心是一个容器,但是却能在它身上像插件一样集成很多功能,在设计上要做到封闭修改、扩展开放,这一点spring做的很优秀,对开发框架有很好的借鉴和指导意义。

本文通过分析spring的启动过程来分析spring扩展开放的设计实现,下面主要集中在两个点来分析:Aware和BeanPostProcessor。spring自身很多扩展功能也都是通过这两个机制来实现。

原则

spring在启动过程中会注册很多回调来实现各种扩展功能,回调的形式最重要的是Aware和BeanPostProcessor。

spring各种不同业务都是一个思路:

  1. 创建不同的ApplicationContext
  2. 不同的ApplicationContext写死一个Aware类型的BeanPostProcessor
  3. 由写死的Aware类型BeanPostProcessor来加载特殊业务的各种逻辑

Aware

每当spring容器完成某件事情(如ApplicationContext初始化完成)时都会通知Aware,Aware通常都具有一些setXXX()的方法,如BeanFactoryAware:

public interface BeanFactoryAware extends Aware {
 void setBeanFactory(BeanFactory beanFactory) throws BeansException;
}

BeanPostProcessor

可以对spring扫描到的bean做手脚,初始化前和后

public interface BeanPostProcessor {
 Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
 Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

Spring 启动过程

spring容器启动的模板编排在org.springframework.context.support.AbstractApplicationContext#refresh

public void refresh() throws BeansException, IllegalStateException {
 prepareRefresh();
 // Tell the subclass to refresh the internal bean factory.
 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
 // Prepare the bean factory for use in this context.
 prepareBeanFactory(beanFactory);
 try {
 // Allows post-processing of the bean factory in context subclasses.
 //子类通常在这里添加自己需要的BeanPostProcessor
 postProcessBeanFactory(beanFactory);
 // Invoke factory processors registered as beans in the context.
 invokeBeanFactoryPostProcessors(beanFactory);
 // Register bean processors that intercept bean creation.
 //查找所有BeanPostProcessor并注册到容器中,bean初始化时会来调用bpp
 registerBeanPostProcessors(beanFactory);
 // Initialize message source for this context.
 initMessageSource();
 // Initialize event multicaster for this context.
 initApplicationEventMulticaster();
 // Initialize other special beans in specific context subclasses.
 onRefresh();
 // Check for listener beans and register them.
 registerListeners();
 // Instantiate all remaining (non-lazy-init) singletons.
 finishBeanFactoryInitialization(beanFactory);
 // Last step: publish corresponding event.
 finishRefresh();
 }
}

其中AbstractApplicationContext#prepareBeanFactory里注册ApplicationContext的Aware处理器:

 beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this))

ApplicationContextAwareProcessor里会触发各种aware

  1. ApplicationContextAware
  2. ApplicationEventPublisherAware
  3. ResourceLoaderAware
  4. EmbeddedValueResolverAware
  5. EnvironmentAware

实现Aware的各种bean接收到回调后就能获取各自想要的东西(ApplicationContext、ResourceLoader等),有了这些东西他们就可以实现自己的个性化逻辑

spring web启动

下面以spring web为例看看Spring web是如何在spring的基础上实现扩展的。

spring web的ApplicationContext大多集成自AbstractRefreshableWebApplicationContext

首先,还是那个套路,创建特殊的ApplicationContext,然后写死一个BeanPostProcessor

AbstractRefreshableWebApplicationContext#postProcessBeanFactory

@Override
 protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
 beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig)); 
 }

ServletContextAwareProcessor处理两种类型的Aware

  1. ServletContextAware
  2. ServletConfigAware

这是上面说的典型的套路

实现了ServletContextAware的bean就这样获取到了web上下文,可以做自己的事情了

spring web初始化方式

web.xml + ContextLoaderListener

< listener >
 < listener-class >
 org.springframework.web.context.ContextLoaderListener
 </ listener-class >
</ listener >
<context-param>
 <param-name>contextConfigLocation</param-name>
 <param-value>classpath:conf/spring/applicationContext.xml</param-value>
</context-param>

ContextLoaderListener 初始化WebApplicationContext 判断启动哪种WebApplicationContext

  1. web.xml 里的context-param找contextClass
  2. 没有的话就加载默认:spring jar里ContextLoader.properties写的XmlWebApplicationContext

web.mxl + DispatcherServlet

<servlet>
 <servlet-name>springMvc</servlet-name>
 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>

DispatcherServlet基于Servlet生命周期会在JAVAx.servlet.GenericServlet.init()初始化spring容器

springboot

DispatcherServletAutoConfiguration

@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
 public DispatcherServlet dispatcherServlet() {
 DispatcherServlet dispatcherServlet = new DispatcherServlet();
 dispatcherServlet.setDispatchOptionsRequest(
 this.webMvcProperties.isDispatchOptionsRequest());
 dispatcherServlet.setDispatchTraceRequest(
 this.webMvcProperties.isDispatchTraceRequest());
 dispatcherServlet.setThrowExceptionIfNoHandlerFound(
 this.webMvcProperties.isThrowExceptionIfNoHandlerFound());
 return dispatcherServlet;
 }

Spring MVC原理

接着上面的web原理

Dispatcher

Dispatcher是一个Servlet,是spring web的入口,来看下spring的dispatcher如何处理请求

Spring启动原理和可扩展设计分析

 

spring mvc

Spring MVC的入口是Controller,那么解析Controller的东西自然就是SpringMVC的入口了。

这个入口就是:

RequestMappingHandlerMapping

这个东西继承了3个Aware

  1. ApplicationAware(Spring web)
  2. ServletContextAware (Spring web)
  3. EmbeddedValueResolverAware (Spring context)

是不是很熟悉!

通过Aware,Spring mvc就这么起来了!并且能够自定义解析各种注解

RequestMappingHandlerMapping

内部维护一个Map<T, HandlerMethod> handlerMethods,T就是Controller的类

public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping
 implements MatchableHandlerMapping, EmbeddedValueResolverAware {
 /** 1. 初始化 */
 public void afterPropertiesSet() {
 initHandlerMethods();
 }
 /** 2. 扫描所有Object的bean,扫描Controller、RequestMapping
 3. 扫描每个controller的web请求方法,写入到handlerMethods里,以后处理请求时用来对应查找
 */ 
 protected void initHandlerMethods() { 
 String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
 BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
 getApplicationContext().getBeanNamesForType(Object.class));
 for (String beanName : beanNames) {
 if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX) &&
 isHandler(getApplicationContext().getType(beanName))){
 //查找web请求方法
 detectHandlerMethods(beanName);
 }
 }
 handlerMethodsInitialized(getHandlerMethods());
 }
 @Override
 protected boolean isHandler(Class<?> beanType) {
 return ((AnnotationUtils.findAnnotation(beanType, Controller.class) != null) ||
 (AnnotationUtils.findAnnotation(beanType, RequestMapping.class) != null));
 }
 /** 4. 处理web请求时负责找到对应的处理方法 */
 @Override
 public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
 Object handler = getHandlerInternal(request);
 if (handler == null) {
 handler = getDefaultHandler();
 }
 if (handler == null) {
 return null;
 }
 // Bean name or resolved handler?
 if (handler instanceof String) {
 String handlerName = (String) handler;
 handler = getApplicationContext().getBean(handlerName);
 }
 /** 组装HandlerExecutionChain,里面主要包括处理列表:
 List<HandlerInterceptor> interceptorList; */
 return getHandlerExecutionChain(handler, request);
 }
}


Tags:Spring   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
我是一名程序员关注我们吧,我们会多多分享技术和资源。进来的朋友,可以多了解下青锋的产品,已开源多个产品的架构版本。Thymeleaf版(开源)1、采用技术: springboot、layui、Thymel...【详细内容】
2021-12-14  Tags: Spring  点击:(21)  评论:(0)  加入收藏
今天来梳理下 Spring 的整体脉络啦,为后面的文章做个铺垫~后面几篇文章应该会讲讲这些内容啦 Spring AOP 插件 (了好久都忘了 ) 分享下 4ye 在项目中利用 AOP + MybatisPlus 对...【详细内容】
2021-12-07  Tags: Spring  点击:(14)  评论:(0)  加入收藏
&emsp;前面通过入门案例介绍,我们发现在SpringSecurity中如果我们没有使用自定义的登录界面,那么SpringSecurity会给我们提供一个系统登录界面。但真实项目中我们一般都会使用...【详细内容】
2021-12-06  Tags: Spring  点击:(18)  评论:(0)  加入收藏
前言项目中的配置文件会有密码的存在,例如数据库的密码、邮箱的密码、FTP的密码等。配置的密码以明文的方式暴露,并不是一种安全的方式,特别是大型项目的生产环境中,因为配置文...【详细内容】
2021-11-17  Tags: Spring  点击:(25)  评论:(0)  加入收藏
SpringBoot开发的物联网通信平台系统项目功能模块 功能 说明 MQTT 1.SSL支持 2.集群化部署时暂不支持retain&will类型消 UDP ...【详细内容】
2021-11-05  Tags: Spring  点击:(56)  评论:(0)  加入收藏
1. 介绍1.1 介绍今天开始我们来学习Java操作MySQL数据库的技巧,Java操作MySQL是借助JdbcTemplate这个对象来实现的。JdbcTemplate是一个多数据库集中解决方案,而我们今天只讲...【详细内容】
2021-11-05  Tags: Spring  点击:(30)  评论:(0)  加入收藏
SpringBoot中的Controller注册本篇将会以Servlet为切入点,通过源码来看web容器中的Controller是如何注册到HandlerMapping中。请求来了之后,web容器是如何根据请求路径找到对...【详细内容】
2021-11-04  Tags: Spring  点击:(53)  评论:(0)  加入收藏
环境:Spring5.3.10通常,应用程序开发人员不需要对ApplicationContext实现类进行子类化。相反,SpringIOC容器可以通过插入特殊集成接口的实现来扩展。使用BeanPostProcessor自定...【详细内容】
2021-10-26  Tags: Spring  点击:(34)  评论:(0)  加入收藏
环境:Springboot2.4.11环境配置接下来的演示都是基于如下接口进行。@RestController@RequestMapping("/exceptions")public class ExceptionsController { @GetMapping(...【详细内容】
2021-10-11  Tags: Spring  点击:(41)  评论:(0)  加入收藏
SpringBoot项目默认使用logback, 已经内置了 logback 的相关jar包,会从resource包下查找logback.xml, logback 文件格式范本 可直接复制使用,有控制台 info.log error.log三个...【详细内容】
2021-10-09  Tags: Spring  点击:(50)  评论:(0)  加入收藏
▌简易百科推荐
一、前因闲来没事,想着升级下树莓派中的应用,没曾想,全是最新的,害我以为被黑客眷顾,帮我升级了。多方查证,才知道,是上次搭建的photoprism搞的鬼,不过也不全是它的锅,只是它的yml文...【详细内容】
2021-12-28  闲余悟道    Tags:Docker   点击:(2)  评论:(0)  加入收藏
一、为什么要搭建主从架构呢1.数据安全,可以进行数据的备份。2.读写分离,大部分的业务系统来说都是读数据多,写数据少,当访问压力过大时,可以把读请求给到从服务器。从而缓解数据...【详细内容】
2021-12-15  实战Java    Tags:Docker   点击:(12)  评论:(0)  加入收藏
在网页中渲染公式一直是泛学术工具绕不开的一个功能,最近更新产品功能,正巧遇到了这个需求,于是使用容器方式简单实现了一个相对靠谱的公式渲染服务。分享出来,希望能够帮到有类...【详细内容】
2021-12-01  编程菌zfn    Tags:Docker   点击:(11)  评论:(0)  加入收藏
1.1 docker命令直接部署1.1.1 拉取镜像docker pull wurstmeister/zookeeperdocker pull wurstmeister/kafka1.1.2 启动zookeeper容器docker run -d --name myzookeeper -p 2...【详细内容】
2021-11-15  无    Tags:docker   点击:(48)  评论:(0)  加入收藏
01 前言 顺着docker的发展,很多测试的同学也已经在测试工作上使用docker作为环境基础去进行一些自动化测试,这篇文章主要讲述我们在docker中使用浏览器进行自动化测试如果可以...【详细内容】
2021-10-29  小码哥聊软件测试    Tags:Docker   点击:(42)  评论:(0)  加入收藏
因为你懂得的原因,下载docker镜像速度非常喜感,故收集几个国内常用的docker镜像。Docker中国区官方镜像地址:https://registry.docker-cn.com网易163的镜像http://hub-mirror.c...【详细内容】
2021-10-28  抓蛙程序猿    Tags:docker   点击:(48)  评论:(0)  加入收藏
环境:Spring5.3.10通常,应用程序开发人员不需要对ApplicationContext实现类进行子类化。相反,SpringIOC容器可以通过插入特殊集成接口的实现来扩展。使用BeanPostProcessor自定...【详细内容】
2021-10-26  Java网络研发架构师    Tags:Spring   点击:(34)  评论:(0)  加入收藏
我们在很多场景下都需要做笔记,来对抗遗忘,一份好的笔记不仅能在需要的时候供我们查阅,也能帮助我们归纳整理知识提高做事效率。 目前市面上有很多云笔记软件,体验上各有不同,但...【详细内容】
2021-10-11  运维贼船    Tags:docker   点击:(62)  评论:(0)  加入收藏
1. Nacos官网Nacos Docker 快速开始2. Clone 项目git clone https://github.com/nacos-group/nacos-docker.git3. cd 到nacos-docker 路径下 直接启动即可cd nacos-dockerdo...【详细内容】
2021-09-16  程序狗爱化妆    Tags:Nacos   点击:(109)  评论:(0)  加入收藏
今天不做保姆级教程,分享奶爸常用、好用的Docker应用。有了这些Docker,Nas的可玩性会大幅提高,有时候奶爸也在想,刨去官方套件不考虑的话,Nas真的是差不多。如果小伙伴们有需要,后...【详细内容】
2021-09-03  晋升奶爸的垃圾佬    Tags:Docker   点击:(168)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条