项目中的流程

1. SpringMVC执行流程

浅探SpringMVC中HandlerExecutionChain之handler、interceptor
在这里插入图片描述

2. IOC启动流程

参考
在这里插入图片描述
spring的启动是建筑在servlet容器之上的,所有web工程的初始位置就是web.xml,它配置了servlet的上下文(context)和监听器(Listener)。 web.xml中定义了 上下文监听器 ContextLoaderListener和前端控制器DispatcherServlet。

  1. 在启动项目时会触发ContextLoaderListener监听器的contextInitialized()上下文初始化方法。
  2. 然后ContextLoaderListener会调用父类 ContextLoader 的initWebApplicationContext()方法。 这是对ApplicationContext的初始化方法,也就是到这里正是进入了springIOC的初始化。
  3. initWebApplicationContext()方法的主要任务有三个:
    • 执行 createWebApplicationContext(servletContext)方法即是完成创建WebApplicationContext工作
    • configureAndRefreshWebApplicationContext方法用来 创建spring容器并初始化spring bean实例, 这个方法于封装ApplicationContext数据并且初始化所有相关Bean对象。 在这个方法中会调用refresh()方法来实例化bean。
    • 最后完成ApplicationContext创建之后就是将其放入ServletContext中。
      在这里插入图片描述

总结1

  1. 首先,对于一个web应用,其部署在web容器中,web容器提供其一个全局的上下文环境,这个上下文就是ServletContext,其为后面的spring IoC容器提供宿主环境;

  2. 其 次,在web.xml中会提供有contextLoaderListener。在web容器启动时,会触发容器初始化事件,此时 contextLoaderListener会监听到这个事件,其contextInitialized()方法会被调用,执行上下文初始化方法。

  3. contextInitialized()方法会调用父类 ContextLoader 的initWebApplicationContext()方法。在这个方法中,spring会初始 化一个启动上下文,这个上下文被称为根上下文,即WebApplicationContext,这是一个接口类,确切的说,其实际的实现类是 XmlWebApplicationContext。这个就是spring的IoC容器,其对应的Bean定义的配置由web.xml中的 context-param标签指定。

  4. initWebApplicationContext()方法的主要任务有三个:

    • 执行 createWebApplicationContext(servletContext)方法即是完成创建WebApplicationContext工作
    • configureAndRefreshWebApplicationContext()方法用来加载spring配置文件中的Bean实例。 这个方法于封装ApplicationContext数据并且初始化所有相关Bean对象。 configureAndRefreshWebApplicationContext()方法中调用最终初始化Bean的==refresh()==方法
    • 最后完成ApplicationContext创建之后,spring以WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE为属性Key,将其存储到ServletContext中,便于获取。

refresh()方法

public void refresh() throws BeansException, IllegalStateException {
    synchronized(this.startupShutdownMonitor) {
        this.prepareRefresh();
        ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
        this.prepareBeanFactory(beanFactory);

        try {
            this.postProcessBeanFactory(beanFactory);
            this.invokeBeanFactoryPostProcessors(beanFactory);
            this.registerBeanPostProcessors(beanFactory);
            this.initMessageSource();
            this.initApplicationEventMulticaster();
            this.onRefresh();
            this.registerListeners();
            this.finishBeanFactoryInitialization(beanFactory);
            this.finishRefresh();
        } catch (BeansException var9) {
            if (this.logger.isWarnEnabled()) {
                this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
            }

            this.destroyBeans();
            this.cancelRefresh(var9);
            throw var9;
        } finally {
            this.resetCommonCaches();
        }

    }
}
  1. prepareRefresh();刷新前的预处理
  2. obtainFreshBeanFactory();创建了一个BeanFactory
  3. prepareBeanFactory();BeanFactory的预准备工作
  4. invokeBeanFactoryPostProcessors();执行BeanFactory的后置处理器方法
  5. registerBeanPostProcessors();注册BeanPostProcessor(Bean的后置处理器)
  6. initMessageSource(); 初始化MessageSource组件
  7. initApplicationEventMulticaster();初始化事件派发器
  8. onRefresh(); 子类重写AbstractApplicationContext.onRefresh()这个方法,在容器刷新的时候可以自定义逻辑;
  9. registerListeners(); 将所有项目里面的ApplicationListener注册到容器中
  10. finishBeanFactoryInitialization(beanFactory);初始化所有剩下的单实例bean,这个方法里有初始化bean操作,即bean的生命周期
  11. finishRefresh();完成

初始化Servlet

  1. 初始化Spring Web MVC使用的Web上下文,并且指定父容器为WebApplicationContext 。contextLoaderListener监听器初始化完毕后,开始初始化web.xml中配置的Servlet,这里是DispatcherServlet。DispatcherServlet上下文在初始化的时候会建立自己的IoC上下文,用以持有spring mvc相关的bean。在建立DispatcherServlet自己的IoC上下文时,会利用WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE先从ServletContext中获取之前的根上下文(即WebApplicationContext)作为自己上下文的parent上下文。

  2. 初始化DispatcherServlet使用的策略,如HandlerMapping、HandlerAdapter等。

    protected void initStrategies(ApplicationContext context) {
        initMultipartResolver(context);
        initLocaleResolver(context);
        initThemeResolver(context);
        initHandlerMappings(context);
        initHandlerAdapters(context);
        initHandlerExceptionResolvers(context);
        initRequestToViewNameTranslator(context);
        initViewResolvers(context);
        initFlashMapManager(context);
    }
  1. 这样每个servlet 就持有自己的上下文,即拥有自己独立的bean空间,同时各个servlet共享相同的bean,即根上下文(第2步中初始化的上下文)定义的那些 bean。

3. Spring中Bean的创建过程

在这里插入图片描述
如下面的代码,doCreateBean()方法实现了Bean生命周期的前三个阶段

// 忽略了无关代码
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
      throws BeanCreationException {

   // Instantiate the bean.
   BeanWrapper instanceWrapper = null;
   if (instanceWrapper == null) {
       // 实例化阶段!
      instanceWrapper = createBeanInstance(beanName, mbd, args);
   }

   // Initialize the bean instance.
   Object exposedObject = bean;
   try {
       // 属性赋值阶段!
      populateBean(beanName, mbd, instanceWrapper);
       // 初始化阶段!
      exposedObject = initializeBean(beanName, exposedObject, mbd);
   }

   }
1. 实例化 createBeanInstance()

容器根据相应bean定义的BeanDefintion取得实例化信息,结合不同的实例化策略以及不同的bean定义类型,获得实例化完成的对象实例,以BeanWrapper对构造完成的对象实例进行包裹,返回相应的BeanWrapper实例。

容器在内部实现的时候,采用“策略模式(Strategy Pattern)”来决定采用何种方式初始化bean实例。

容器根据相应bean定义的BeanDefintion取得实例化信息,结合CglibSubclassingInstantiationStrategy以及不同的bean定义类型,就可以返回实例化完成的对象实例。
但是,返回方式上有些“点缀”。不是直接返回构造完成的对象实例,而是以BeanWrapper对构造完成的对象实例
进行包裹,返回相应的BeanWrapper实例。

使用BeanWrapper对bean实例操作很方便,可以免去直接使用Java反射API操作对象实例的烦琐。

2. 属性赋值 populateBean()

为什么实例化返回相应的BeanWrapper实例,而不是原对象实例?
在这里插入图片描述

  1. BeanWrapper定义继承了org.springframework.beans.PropertyAccessor接口,可以以统一的
    方式对对象属性进行访问
  2. BeanWrapper定义同时又直接或者间接继承了PropertyEditorRegistry和TypeConverter接口 ,便于设置对象属性值、 转换类型
3. 设置相关依赖
  • 使用BeanFactory容器,采用Aware接口设置相关依赖

    当对象实例化完成并且相关属性以及依赖设置完成之后, Spring容器会检查当前对象实例是否实现了一系列的以Aware命名结尾的接口定义。如果是,则将这些Aware接口定义中规定的依赖注入给当前对象实例。

    主要是 org.springframework.beans.factory.包下的接口:BeanNameAwareBeanClassLoaderAwareBeanFactoryAware

  • 使用ApplicationContext,则采用BeanPostProcesser方式设置相关依赖

    主要是org.springframework.context.包下的接口,如:ResourceLoaderAwareApplicationEventPublisherAwareMessageSourceAwareApplicationContextAware

    BeanPostProcesser:

    public interface BeanPostProcessor
    {
        //初始化之前执行
    	Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
        //初始化之后执行
    	Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
    }
    

    BeanPostProcessor的两个方法中都传入了原来的对象实例的引用,这为我们扩展容器的对象实例化过程中的行为提供了极大的便利 。也可以自定义BeanPostProcessor 。

4. 初始化 initializeBean()

指定自定义的对象初始化操作,有两种方式:

  1. 实现InitializingBean接口 :在对象实例化过程调用过“BeanPostProcessor的前置处理”之后,会接着检测当前对象是否实现了InitializingBean接口,如果是,则会调用其afterPropertiesSet()方法进一步调整对象实例的状态。
  2. 使用< bean>的init-method属性: 通过init-method,系统中业务对象的自定义初始化操作可以以任何方式命名,而不再受制于InitializingBean的afterPropertiesSet()。
5. 销毁

与InitializingBean和init-method用于对象的自定义初始化相对应, DisposableBean和destroy-method为对象提供了执行自定义销毁逻辑的机会。

https://www.jianshu.com/p/1dec08d290c1

4. SpringBoot启动流程

参考:

Spring Boot启动流程简单解释

SpringBoot启动流程总结

1. 启动

Spring Boot程序有一个入口,就是main方法。main里面调用SpringApplication.run()启动整个Spring Boot程序

2. 构造SpringApplication实例

SpringBoot启动的时候,不论调用什么方法,都会构造一个SpringApplication的实例,然后调用这个实例的run方法,这样就表示启动SpringBoot。

在run方法调用之前,也就是构造SpringApplication的时候会进行初始化的工作,初始化的时候会做以下几件事:

  1. this.webApplicationType = WebApplicationType.deduceFromClasspath();

    判断 应用程序 类型: SpringBoot将应用程序分为三种类型: Reactive(响应式web类型) 、Servlet(web类型)、None(非web类型)。

  2. this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
    从spring.factories文件中找出所有的初始化器, 创建并初始化ApplicationContextInitializer列表

  3. this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
    从spring.factories文件中找出所有的应用程序监听器, 创建并初始化 ApplicationListener列表 列表

  4. this.mainApplicationClass = this.deduceMainApplicationClass();

    找出运行的主类(main class)

3. 执行run()方法

  1. 获取并启动 事件监听器 SpringApplicationRunListener
  SpringApplicationRunListeners listeners = this.getRunListeners(args);
  listeners.starting();
  1. 创建并配置当前Spring Boot应用将要使用的Environment
   ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
   this.configureIgnoreBeanInfo(environment);
  1. 构造Spring容器(ApplicationContext)

    • context = this.createApplicationContext();根据应用程序类型创建上下文

    • this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);准备上下文

    • this.refreshContext(context);刷新上下文, 这个是spring启动的代码

      该方法会调用 AbstractApplicationContext - >refresh()方法,该方法就是IOC容器启动的代码。和SSM项目中IOC容器启动不一样的地方是,refresh()方法中的 onRefresh() 方法会创建内置容器,如tomcat。

    • this.afterRefresh(context, applicationArguments);上下文刷新完毕

  2. listeners.started(context); 遍历执行SpringApplicationRunListener的finished()方法

5. SpringBoot自动配置原理

具体看这篇文章《Spring Boot自动配置原理、实战》。

注解 @EnableAutoConfiguration, @Configuration, @ConditionalOnClass 就是自动配置的核心,首先它得是一个配置文件,其次根据类路径下是否有这个类去自动配置。

1. 配置文件

Spring Boot有一个全局配置文件:application.properties或application.yml。 我们的各种属性都可以在这个文件中进行配置,最常配置的比如:server.port、logging.level.* 等等。

那么问题来了:这些配置是如何在Spring Boot项目中生效的呢?

2. 加载自动配置类到容器

Spring Boot关于自动配置的源码在spring-boot-autoconfigure-x.x.x.x.jar中:
在这里插入图片描述
Spring Boot的启动类上有一个@SpringBootApplication注解,这个注解是Spring Boot项目必不可少的注解。 @SpringBootApplication是一个复合注解或派生注解, 它包括@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan
在这里插入图片描述
@EnableAutoConfiguration注解也是一个派生注解,其中的关键功能由==@Import==提供,其导入的AutoConfigurationImportSelector的selectImports()方法通过SpringFactoriesLoader.loadFactoryNames()扫描所有具有META-INF/spring.factories的jar包。 扫描所有具有META-INF/spring.factories的jar包。spring-boot-autoconfigure-x.x.x.x.jar里就有一个这样的spring.factories文件。
在这里插入图片描述
AutoConfigurationImportSelector源码如下
在这里插入图片描述
这个spring.factories文件也是一组一组的key=value的形式,其中有一个KV对,key是EnableAutoConfiguration类的全类名,而它的value是一个以AutoConfiguration结尾的类名的列表,这些类名以逗号分隔,如下图所示:
在这里插入图片描述
这个@EnableAutoConfiguration注解通过@SpringBootApplication被间接的标记在了Spring Boot的启动类上。在SpringApplication.run(…)的内部就会执行selectImports()方法,找到所有JavaConfig自动配置类的全限定名对应的class,然后将所有自动配置类加载到Spring容器中。

3. 自动配置生效

每一个AutoConfiguration结尾自动配置类都是在某些条件之下才会生效的,这些条件的限制在Spring Boot中以注解的形式体现,常见的条件注解有如下几项:

@ConditionalOnBean:当容器里有指定的bean的条件下。

@ConditionalOnMissingBean:当容器里不存在指定bean的条件下。

@ConditionalOnClass:当类路径下有指定类的条件下。

@ConditionalOnMissingClass:当类路径下不存在指定类的条件下。

@ConditionalOnProperty:指定的属性是否有指定的值,比如@ConditionalOnProperties(prefix=”xxx.xxx”, value=”enable”, matchIfMissing=true),代表当xxx.xxx为enable时条件的布尔值为true,如果没有设置的情况下也为true

ServletWebServerFactoryAutoConfiguration为例
在这里插入图片描述
在ServletWebServerFactoryAutoConfiguration类上,有一个@EnableConfigurationProperties注解:开启配置属性,而它后面的参数是一个ServerProperties类,这就是习惯优于配置的最终落地点。
在这里插入图片描述
在这个类上,我们看到了一个非常熟悉的注解:@ConfigurationProperties,它的作用就是从配置文件中绑定属性到对应的bean上,而@EnableConfigurationProperties负责导入这个已经绑定了属性的bean到spring容器中。那么所有其他的和这个类相关的属性都可以在全局配置文件中定义,也就是说,真正“限制”我们可以在全局配置文件中配置哪些属性的类就是这些XxxxProperties类,它与配置文件中定义的prefix关键字开头的一组属性是唯一对应的。

至此,我们大致可以了解。在全局配置的属性如:server.port等,通过@ConfigurationProperties注解,绑定到对应的XxxxProperties配置实体类上封装为一个bean,然后再通过@EnableConfigurationProperties注解导入到Spring容器中。

而诸多的XxxxAutoConfiguration自动配置类,就是Spring容器的JavaConfig形式,作用就是为Spring 容器导入bean,而所有导入的bean所需要的属性都通过xxxxProperties的bean来获得。

4.总结

  1. Spring Boot启动的时候会通过@EnableAutoConfiguration注解找到META-INF/spring.factories配置文件中的所有自动配置类,并对其进行加载
  2. 而这些自动配置类都是以AutoConfiguration结尾来命名的,它实际上就是一个JavaConfig形式的Spring容器配置类
  3. XxxxProperties类是通过@ConfigurationProperties注解与全局配置文件中对应的属性进行绑定的。
  4. 名字以AutoConfiguration结尾的自动配置类能通过Properties类获取到这些属性如:server.port

6. Mybatis执行流程

public static void addStudent(){
    Student stu = new Student(3,"lc",19,"1");
    //1
    InputStream stream = Student.class.getClassLoader().getResourceAsStream("conf.xml");
    //2
    SqlSessionFactory ssf=new SqlSessionFactoryBuilder().build(stream);
    //3
    SqlSession session=ssf.openSession();
    //4
    StudentMapper studentMapper = session.getMapper(StudentMapper.class);
    //5
    studentMapper.addStudent(stu);
    session.commit();
    session.close();
}

[执行流程] https://blog.csdn.net/qq_38270106/article/details/93398694 :

  1. 加载Mybatis配置文件(两种方式:使用类加载器加载, 或使用Resources类加载),将配置文件里的信息解析成一个IO流。

  2. 构建sqlSession的工厂:新建一个SqlSessionFactoryBuilder对象,并调用build()方法,将IO流传入其中,将解析到的信息包成一个Configuration对象,使用这个对象创建一个SqlSessionFactory并返回。

  3. 创建能执行映射文件中sql的sqlSession:使用SqlSessionFactory的operSession()方法创建sqlSession,其中openSession方法中,

    • 根据Configuration对象获取Environment信息, transactionFactory 使用该环境产生事务,
    • 根据Configuration对象调用 Executor 执行器,默认是Simple Executor 。

    在构建sqlSession过程中,需要创建 transaction和executor用于后续执行操作。

  4. jdk动态代理生成mapper接口的代理对象

  5. 通过第4步返回的代理对象,执行相应的方法。

    • 先判断sql语句的类型
    • 如果是查询语句,使用CachingExecutor的query方法去查二级缓存,没有二级缓存的话,去查一级缓存 localCache,一级缓存也没有, 走queryFromDatabase方法查数据库 ,查到后放入一级缓存。

7. Mybatis 中动态sql原理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值