三. SpringBoot原理

三. SpringBoot原理,第1张

三. SpringBoot原理 三. SpringBoot原理

对于springboot来说,还有两块是比较有意思的,第一就是发现他内置了tomcat,接下来一快就是他对springmvc进行了无缝整合

1. 内嵌tomcat

首先来看下最简单的tomcat集成。

pom


    4.0.0

    hgy
    embed-tomcat
    1.0-SNAPSHOT

    
        
        
            org.apache.tomcat.embed
            tomcat-embed-core
            8.5.11
        

        
        
            org.apache.tomcat
            tomcat-jasper
            8.5.11
        
    

新建立一个servlet
package len.hgy.servlet;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class IndexServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().print("this is index... tomcat");
    }
}
tomcat 整合
package len.hgy;

import len.hgy.servlet.IndexServlet;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.startup.Tomcat;

public class MyTomcat {
    private static final int PORT = 8080;
    private static final String CONTEX_PATH = "/hgy";
    private static final String SERVLET_NAME = "indexServlet";

    public static void main(String[] args) throws LifecycleException, InterruptedException {
        // 创建tomcat服务器
        Tomcat tomcatServer = new Tomcat();
        // 指定端口号
        tomcatServer.setPort(PORT);
        // 是否设置自动部署
        tomcatServer.getHost().setAutoDeploy(false);
        // 创建上下文
        StandardContext standardContext = new StandardContext();
        standardContext.setPath(CONTEX_PATH);
        // 监听上下文
        standardContext.addLifecycleListener(new Tomcat.FixContextListener());
        // tomcat容器添加standardContext
        tomcatServer.getHost().addChild(standardContext);

        // 创建Servlet
        tomcatServer.addServlet(CONTEX_PATH, SERVLET_NAME, new IndexServlet());
        // servleturl映射
        standardContext.addServletMappingDecoded("/index", SERVLET_NAME);
        tomcatServer.start();
        System.out.println("tomcat服务器启动成功..");
        // 异步进行接收请求
        tomcatServer.getServer().await();
    }
}

运行main方法,在浏览器输入:

http://localhost:8080/hgy/index

注意: 9.xx版本的并不能直接访问

2. SpringMVC 整合 新增spring依赖

    org.springframework
    spring-web
    5.0.4.RELEASE
    compile


    org.springframework
    spring-webmvc
    5.0.4.RELEASE
    compile

UserService
package len.hgy.service;

import org.springframework.stereotype.Service;

@Service
public class UserService {
    public String index() {
        return "springboot 2.0  我正在加载UserService";
    }
}
RestController
package len.hgy.controller;

import len.hgy.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class IndexController {
    @Autowired
    private UserService userService;

    @RequestMapping(value = "/index", produces = "text/html;charset=UTF-8")
    public String index() {
        return userService.index();
    }
}
DispatcherServlet配置类

虽然前面有了service,有了controller,但依然没有把这些组建交给spring,对于springmvc来说,有个DispatcherServlet,这是springmvc的前端控制器,以前是配置在web.xml中。只是现在用的是注解

package len.hgy.conf;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("len.hgy")
public class RootConfig {
}
package len.hgy.conf;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"len.hgy.controller"})
//public class WebConfig extends WebMvcConfigurerAdapter {
public class WebConfig implements WebMvcConfigurer {
}
package len.hgy.conf;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

@Configuration
public class SpringWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
    // 加载根配置信息 spring核心
    protected Class[] getRootConfigClasses() {
        return new Class[]{RootConfig.class};
    }

    // springmvc 加载 配置信息
    protected Class[] getServletConfigClasses() {
        return new Class[]{WebConfig.class};
    }

    // springmvc 拦截url映射 拦截所有请求
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}
Tomcat集成

TomcatApp

package len.hgy;

import java.io.File;
import javax.servlet.ServletException;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.WebResourceRoot;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.webresources.DirResourceSet;
import org.apache.catalina.webresources.StandardRoot;

public class TomcatApp {
    public static void main(String[] args) throws ServletException, LifecycleException {
        start();
    }

    public static void start() throws ServletException, LifecycleException {
        // 创建Tomcat容器
        Tomcat tomcatServer = new Tomcat();
        // 端口号设置
        tomcatServer.setPort(9090);
        // 读取项目路径 加载静态资源
        StandardContext ctx = (StandardContext) tomcatServer.addWebapp("/", new File("src/main").getAbsolutePath());
        // 禁止重新载入
        ctx.setReloadable(false);
        // class文件读取地址
        File additionWebInfClasses = new File("target/classes");
        // 创建WebRoot
        WebResourceRoot resources = new StandardRoot(ctx);
        // tomcat内部读取Class执行
        resources.addPreResources(
            new DirResourceSet(resources, "/WEB-INF/classes", additionWebInfClasses.getAbsolutePath(), "/"));
        tomcatServer.start();
        // 异步等待请求执行
        tomcatServer.getServer().await();
    }
}

启动,在地址栏输入:

http://localhost:9090/index

JSP支持

要支持JSP,回忆学习springmvc中的内容,需要用到一个试图解析器

修改WebConfig

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"len.hgy.controller"})
//public class WebConfig extends WebMvcConfigurerAdapter {
public class WebConfig implements WebMvcConfigurer {
    // 创建SpringMVC视图解析器
    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/WEB-INF/views/");
        viewResolver.setSuffix(".jsp");
        // 可以在JSP页面中通过${}访问beans
        viewResolver.setExposeContextBeansAsAttributes(true);

        registry.viewResolver(viewResolver);
    }
}

新增controller

@Controller
public class UserController {
    @RequestMapping("/pageIndex")
    public String pageIndex() {
        return "pageIndex";
    }
}

增加JSP

在resources里面新增WEB-INFviewspageIndex.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>



    
    jsp page


这是个jsp页面


重启tomcat ,访问 http://localhost:9090/pageIndex

3. SpringBootTomcat 加载流程 tomcat如何启动的?
org.springframework.boot.autoconfigure.EnableAutoConfiguration=
...
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,
...

ServletWebServerFactoryAutoConfiguration 这类里面有个TomcatServletWebServerFactoryCustomizer这个类实现了WebServerFactoryCustomizer

@Configuration
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
@import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
		ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
		ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
		ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {

EmbeddedTomcat->TomcatServletWebServerFactory->TomcatServletWebServerFactory.getWebServer()->getTomcatWebServer->TomcatWebServer->启动tomcat

// Start the server to trigger initialization listeners

this.tomcat.start();

在注入bean时候已经在构造器里面启动了tomcat

getWebServer谁调用的?

SpringApplication.run(App.class, args);

org.springframework.boot.SpringApplication#refreshContext

org.springframework.context.support.AbstractApplicationContext#refresh (Spring启动的核心方法)

org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#onRefresh

org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#createWebServer

org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory#getWebServer

大致分析:

​ 更具classpath中的class分析出当前的项目类型是REACTIVE, SERVELET, NONE, 如果是SERVLET类型创建ServletWebServerApplicationContext的Context, 在AbstractApplicationContext的onRefresh()的钩子方法调用ServletWebServerApplicationContext的onRefresh()方法调用createWebServer(),最终调用如下代码和Tomcat挂钩

if (webServer == null && servletContext == null) {
	ServletWebServerFactory factory = getWebServerFactory();
	this.webServer = factory.getWebServer(getSelfInitializer());
}

以上是SpringBoot在onRefresh()中启动Tomcat的逻辑, 其实还是在Spring的refresh()流程中

Tomcat如何初始化Spring呢?

只需要在refresh()方法打一个断点就知道了

其中有好几个异步追踪, 说明Tomcat初始化Spring使用的是异步线程方式

main线程

​ tomcatServer.start();

​ server.start();

​ startInternal(); 提交异步任务

异步任务线程1

异步任务线程2

​ listener.contextInitialized(tldEvent);

​ public void contextInitialized(ServletContextEvent event) {

​ this.initWebApplicationContext(event.getServletContext());

​ }

​ configureAndRefreshWebApplicationContext的实例是AnnotationConfigWebApplicationContext

而AnnotationConfigWebApplicationContext的继承结构是

所以在调用refresh()方法就会触发spring初始化的核心逻辑

而此时的onRefresh()钩子方法不会触发再次Tomcat启动, 所以不会出现Tomcat重复启动

@Override
protected void onRefresh() {
   this.themeSource = UiApplicationContextUtils.initThemeSource(this);
}
4. SpringBoot 启动流程分析 准备工作

ApplicationContextInitializer Context初始化后调用的类

SpringApplicationRunListener SpringBoot运行监听的类

ApplicationRunner/CommandLineRunner 两个几乎可以等价,用于启动后做客户自定义的 *** 作

MyApplicationRunner

@Component
public class MyApplicationRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("MyApplicationRunner.run()执行了");
    }
}

MyCommandLineRunner

@Component
public class MyCommandLineRunner implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("MyCommandLineRunner.run()执行了" + Arrays.asList(args));
    }
}

MyApplicationContextInitializer

public class MyApplicationContextInitializer
    implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        System.out.println("MyApplicationContextInitializer.initialize()执行了" + applicationContext);
    }
}

MySpringApplicationRunListener

public class MySpringApplicationRunListener implements SpringApplicationRunListener {
    //必须有的构造器
    public MySpringApplicationRunListener(SpringApplication application, String[] args) {
    }

    @Override
    public void starting() {
        System.out.println("MySpringApplicationRunListener.starting()执行了");
    }

    @Override
    public void environmentPrepared(ConfigurableEnvironment environment) {
        System.out.println("MySpringApplicationRunListener.environmentPrepared()执行了");
    }

    @Override
    public void contextPrepared(ConfigurableApplicationContext context) {
        System.out.println("MySpringApplicationRunListener.contextPrepared()执行了");
    }

    @Override
    public void contextLoaded(ConfigurableApplicationContext context) {
        System.out.println("MySpringApplicationRunListener.contextLoaded()执行了");
    }

    @Override
    public void started(ConfigurableApplicationContext context) {
        System.out.println("MySpringApplicationRunListener.started()执行了");
    }

    @Override
    public void running(ConfigurableApplicationContext context) {
        System.out.println("MySpringApplicationRunListener.running()执行了");
    }

    @Override
    public void failed(ConfigurableApplicationContext context, Throwable exception) {
        System.out.println("MySpringApplicationRunListener.failed()执行了");
    }
}

在resources/meta-INF/spring.factories增加

org.springframework.context.ApplicationContextInitializer=len.hgy.listener.MyApplicationContextInitializer
org.springframework.boot.SpringApplicationRunListener=len.hgy.listener.MySpringApplicationRunListener
创建SpringApplication

SpringApplication源码

public static ConfigurableApplicationContext run(Class primarySource,
      String... args) {
   return run(new Class[] { primarySource }, args);
}

其实SpringBoot启动就着两个步骤,先创建ConfigurableApplicationContext ,然后再调用Run方法。

ConfigurableApplicationContext 是其他方式接入Spring的入口上下文

SpringApplication构造方法源码

public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
	this.resourceLoader = resourceLoader;
    Assert.notNull(primarySources, "PrimarySources must not be null");
    //保存主类
    this.primarySources = new linkedHashSet<>(Arrays.asList(primarySources));
    //判断当前是什么类型项目, Tomcat启动Spring不需要判断,因为使用Tomcat就说明是SERVLET类型
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    //从类路径下找到meta-INF/spring.factories配置的所有 ApplicationContextInitializer
    setInitializers((Collection) getSpringFactoriesInstances(
        ApplicationContextInitializer.class));
    //从类路径下找到meta-INF/spring.factories配置的所有ApplicationListener
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    this.mainApplicationClass = deduceMainApplicationClass();
}
Run方法

核心方法

public ConfigurableApplicationContext run(String... args) {
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    ConfigurableApplicationContext context = null;
    Collection exceptionReporters = new ArrayList<>();
    configureHeadlessProperty();
    //从类路径下meta‐INF/spring.factories,取得 SpringApplicationRunListeners;
    SpringApplicationRunListeners listeners = getRunListeners(args);
    //回调所有的获取SpringApplicationRunListener.starting()方法
    listeners.starting();
    try {
        //封装命令行参数
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(
            args);
        //准备环境
        ConfigurableEnvironment environment = prepareEnvironment(listeners,
                                                                 applicationArguments);
        configureIgnoreBeanInfo(environment);
        //创回调SpringApplicationRunListener.environmentPrepared();
        //表示环境准备完成

        //打印 Banner 
        Banner printedBanner = printBanner(environment);
        //根据环境创建context
        context = createApplicationContext();
        //错误的异常报表
        exceptionReporters = getSpringFactoriesInstances(
            SpringBootExceptionReporter.class,
            new Class[] { ConfigurableApplicationContext.class }, context);
        //准备上下文环境;
        //将environment保存到ioc中;
        //applyInitializers()调用所有的ApplicationContextInitializer的initialize方法
        //调用所有的SpringApplicationRunListener的contextPrepared();
        prepareContext(context, environment, listeners, applicationArguments,
                       printedBanner);
        //SpringApplicationRunListener的contextLoaded
        //刷新容器
        //扫描,创建,加载所有组件;
        refreshContext(context);
        afterRefresh(context, applicationArguments);
        stopWatch.stop();
        if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass)
                .logStarted(getApplicationLog(), stopWatch);
        }
        //所有的SpringApplicationRunListener回调started方法
        listeners.started(context);
        //获取所有的ApplicationRunner和CommandLineRunner进行调用
        callRunners(context, applicationArguments);
    }
    catch (Throwable ex) {
        handleRunFailure(context, ex, exceptionReporters, listeners);
        throw new IllegalStateException(ex);
    }

    try {
        //所有的SpringApplicationRunListener的running();
        listeners.running(context);
    }
    catch (Throwable ex) {
        handleRunFailure(context, ex, exceptionReporters, null);
        throw new IllegalStateException(ex);
    }
    return context;
}

注意

ApplicationContextInitializer是在构造方法中从spring.factories中获取初始化的

SpringApplicationRunListener是在run中获取的

callRunners(context, applicationArguments); // 会调用所有的ApplicationRunner和CommandLineRunner

private void callRunners(ApplicationContext context, ApplicationArguments args) {
    List runners = new ArrayList<>();
    runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
    runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
    AnnotationAwareOrderComparator.sort(runners);
    for (Object runner : new linkedHashSet<>(runners)) {
        if (runner instanceof ApplicationRunner) {
            callRunner((ApplicationRunner) runner, args);
        }
        if (runner instanceof CommandLineRunner) {
            callRunner((CommandLineRunner) runner, args);
        }
    }
}
 

spi的bean不需要加注解就可以导入到Spring中, Runner需要加注解才能导入

总结:

springboot的启动核心步骤就是调用refresh()方法,启动spring核心流程, 调用onRefresh()方法, new Tomcat(),并设置tomcat项目路径,端口等(就是创建一个类似web.xml的对象)

另外springboot还有一个核心功能是自动配置, 接下来看自动配置

1、SPI

SPI 在 springboot 中是去读取 meta-INF/spring.factories 目录的配置文件内 容,把配置文件中的类加载到 spring 容器中。这样如果你想把一个类加载到 spring 容器中,也可以采用这种方式来做。把类配置到 spring.factories 配置 文件中即可。

如果你想把一个类加载到 spring 容器中管理有几种方式:

1、通过 xml 的 bean 标签

2、通过加@Component 注解被@ComponentScan 扫描

3、通过在 spring.factories 配置该类

前两者是加载本工程的 bean,扫描本工程的 bean,第三点可以加载第三方定义 的 jar 包中的 bean,毕竟第三方 jar 包的包名跟本工程包名可能不一样,所以 前两个方式扫描不到。

2、创建 springboot 的上下文对象

在这个上下文对象构造函数中把 ConfigurationClassPostProcessor 变成 beanDefinition 对象(核心的ConfigurationClassPostProcessor 是在这个地方编程了BeanDefinition的)

public class AnnotationConfigServletWebServerApplicationContext
		extends ServletWebServerApplicationContext implements AnnotationConfigRegistry {
...
	public AnnotationConfigServletWebServerApplicationContext() {
		this.reader = new AnnotatedBeanDefinitionReader(this);
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}
...
}

this.reader = new AnnotatedBeanDefinitionReader(this);
// 注册 ConfigurationClassPostProcessor的BeanDefinition
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
    RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
    def.setSource(source);
    beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}

3、容器的启动

其实很简单就是调用了上下文对象的 refresh 核心方法:

// 核心方法, 启动Spring容器
refreshContext(context);

// 进入AbstractApplicationContext
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // Prepare this context for refreshing.
        prepareRefresh();
        // 创建BeanFactory和xml的标签解析哦
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        // Prepare the bean factory for use in this context.
        prepareBeanFactory(beanFactory); // 设置一些属性, 不重要
        try {
            // 允许在上下文子类中对bean工厂进行后处理, 主要是注册WebApplication的Scopes和Environment的Beans到BeanFactory中, 所以是到beanFactory的后处理
//WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
//WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
            postProcessBeanFactory(beanFactory);
            
* 	private final List beanFactoryPostProcessors = new ArrayList<>();
            * SpringBoot中在applyInitializers(context);里面添加这个容器
	             * 这些bean不在核心容器里面, 是在一个单独的beanFactoryPostProcessors中
                 * 通过getBean实例化,让后调用后置处理器
                 * currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
				 * */
            invokeBeanFactoryPostProcessors(beanFactory); // 是BeanDefinitionRegistry和BeanFactory的后置处理器调用
				
            registerBeanPostProcessors(beanFactory); // 是Bean的后置处理器调用
            // Initialize message source for this context.
            initMessageSource();
            // Initialize event multicaster for this context.
            initApplicationEventMulticaster();
            // Initialize other special beans in specific context subclasses.
            onRefresh(); // new Tomcat(), 并启动
            // Check for listener beans and register them.
            registerListeners();
            // Instantiate all remaining (non-lazy-init) singletons.
            finishBeanFactoryInitialization(beanFactory);
            // Last step: publish corresponding event.
            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.
            destroyBeans();
            // Reset 'active' flag.
            cancelRefresh(ex);
            // Propagate exception to caller.
            throw ex;
        } finally {
            // Reset common introspection caches in Spring's core, since we
            // might not ever need metadata for singleton beans anymore...
            resetCommonCaches();
        }
    }
}

4、内置 tomcat 的启动和部署

Tomcat 的启动在 onRefresh()中:

// org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#onRefresh
@Override
public WebServer getWebServer(ServletContextInitializer... initializers) {
    Tomcat tomcat = new Tomcat(); // host
    File baseDir = (this.baseDirectory != null) ? this.baseDirectory
        : createTempDir("tomcat");
    tomcat.setbaseDir(baseDir.getAbsolutePath());
    Connector connector = new Connector(this.protocol); // connector
    tomcat.getService().addConnector(connector); // set service
    customizeConnector(connector);
    tomcat.setConnector(connector); // set connector
    tomcat.getHost().setAutoDeploy(false); // 设置非自动部署
    configureEngine(tomcat.getEngine());
    for (Connector additionalConnector : this.additionalTomcatConnectors) {
        tomcat.getService().addConnector(additionalConnector);
    }
    prepareContext(tomcat.getHost(), initializers);
    return getTomcatWebServer(tomcat);
}
SpringBoot启动核心就做了两件是

启动Spring的refresh()方法(refresh())

AbstractApplicationContext启动核心流程中回调ServletWebServerApplicationContext.onRefresh()的钩子方法(onRefresh())

5. SpringBoot的自动配置 为什么要有 springboot 自动配置功能?

在 springboot 项目中,我们可以在业务代码里面用事务注解,用缓存注解,用 mvn 相关的功能等等,但是我们并没有在 springboot 项目把这些功能开启添加 进来,那么为什么我们可以在业务代码中使用这些功能呢?也就是说这些功能如 何跑到 springboot 项目中来的呢?这就是 springboot 的自动配置功能

自动配置功能开启

@SpringBootConfiguration
@EnableAutoConfiguration // SpringBoot自动配置注解
@ComponentScan(excludeFilters = {
		@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
@AutoConfigurationPackage
@import(AutoConfigurationimportSelector.class) // 使用import导入
public @interface EnableAutoConfiguration {
那这个AutoConfigurationimportSelector如何被调用的?

在refresh()的核心流程中有两个非常重要的后置处理方法

invokeBeanFactoryPostProcessors(beanFactory); // BeanDefinitionRegistry和BeanFactory的后置处理器

// 这两个是对beanFactory的修改(当然, 主要是修改BeanDefinition)

// 继承关系 public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); // BeaDefinitionRegistry
// BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry(registry);
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory); // BeanFactory
// BeanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
// BeanDefinitionRegistryPostProcessor调用后将对象添加到BeanFactoryPostProcessor容器中
// 所以BeanDefinitionRegistryPostProcessor容器是BeanFactoryPostProcessor容器的一个自己
// 所有的BeanDefinitionRegistryPostProcessor对象会调用postProcessBeanDefinitionRegistry和postProcessBeanFactory两个方法

registerBeanPostProcessors(beanFactory); // BeanPostProcessor接口的调用, 即bean的后置处理器调用

public interface BeanPostProcessor { // 接口可以看出, bean的后置处理器是对Bean的修改
	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean; // 默认不修改返回原始bean
	}
	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean; // 默认不修改返回原始bean
	}
}

@Configuration,@import,@Bean,@importResource,@ComponentScan等注解是在ConfigurationClassPostProcessor中完成的

ConfigurationClassPostProcessor的类结构

public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
		PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {

理所当然Registry的postProcessBeanDefinitionRegistry后置处理器就是处理这些注解的入口

@Override // 不用忘记了, 这个是refresh核心流程调用过来的invokeBeanFactoryPostProcessor()
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
    int registryId = System.identityHashCode(registry);
    if (this.registriesPostProcessed.contains(registryId)) {
        throw new IllegalStateException(
            "postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
    }
    if (this.factoriesPostProcessed.contains(registryId)) {
        throw new IllegalStateException(
            "postProcessBeanFactory already called on this post-processor against " + registry);
    }
    this.registriesPostProcessed.add(registryId);

    processConfigBeanDefinitions(registry); // 处理配置beanDefinition, 处理注解的核心逻辑
}
this.deferredimportSelectorHandler.process(); // deferredimportSelector的处理器

// ConfigurationClassParser.DeferredimportSelectorHandler#process
public void process() {
    List deferredimports = this.deferredimportSelectors;
    this.deferredimportSelectors = null;
    try {
        if (deferredimports != null) {
            DeferredimportSelectorGroupingHandler handler = new DeferredimportSelectorGroupingHandler();
            deferredimports.sort(DEFERRED_import_COMPARATOR);
            deferredimports.forEach(handler::register);
            handler.processGroupimports(); // 处理 group imports逻辑
        }
    } finally {
        this.deferredimportSelectors = new ArrayList<>();
    }
}

// ConfigurationClassParser.DeferredimportSelectorGrouping#getimports
public Iterable getimports() {
    for (DeferredimportSelectorHolder deferredimport : this.deferredimports) {
        this.group.process(deferredimport.getConfigurationClass().getmetadata(),
                           deferredimport.getimportSelector()); // process调用importSelector的接口方法
    }
    return this.group.selectimports();
}

AutoConfigurationimportSelector的类继承结构如下

public class AutoConfigurationimportSelector // 是DeferredimportSelector的类
		implements DeferredimportSelector, BeanClassLoaderAware, ResourceLoaderAware,
		BeanFactoryAware, EnvironmentAware, Ordered {

getimports()->this.group.process()->AutoConfigurationimportSelector.AutoConfigurationGroup#process()

->AutoConfigurationimportSelector#getAutoConfigurationEntry()

->AutoConfigurationimportSelector#getCandidateConfigurations()

-> SpringFactoriesLoader.loadFactoryNames() // 此处就是SpringBoot通过SPI获取spring.Factories中bean实现,然后导入里面的类的

public static List loadFactoryNames(Class factoryClass, @Nullable ClassLoader classLoader) {
    String factoryClassName = factoryClass.getName();
    return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}

然后就是Spring的import注解的处理逻辑

AutoConfigurationimportSelector实现了 DeferredimportSelector 接口。 这个类的核心功能是通过 SPI 机制收集 EnableAutoConfiguration 为 key 的所有 类,然后通过 ConfigurationClassPostProcessor 这个类调用到该类中的方法, 把收集到的类变成 beanDefinition 对象最终实例化加入到 spring 容器。

# Auto Configure, 一个实现代表导入一个功能
org.springframework.boot.autoconfigure.EnableAutoConfiguration=
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,
...

AutoConfigurationimportSelector 类中两个方法会被 ConfigurationClassPostProcessor 调到:

org.springframework.boot.autoconfigure.AutoConfigurationimportSelector.AutoConfigurationGroup#process

org.springframework.boot.autoconfigure.AutoConfigurationimportSelector#selectimports

在这两个方法中完成了 SPI 类的收集。

ConfigurationClassPostProcessor 类只是把收集到的类变成 beanDefinition 并加入到 spring 容器。

ConfigurationClassPostProcessor 类调用的地方。

private void processimports(ConfigurationClass configClass, SourceClass currentSourceClass,
                            Collection importCandidates, boolean checkForCircularimports) {
...
    if (candidate.isAssignable(importSelector.class)) {
        // Candidate class is an importSelector -> delegate to it to determine imports
        Class candidateClass = candidate.loadClass();
        // 需要实例化这个候选的bean
        importSelector selector = BeanUtils.instantiateClass(candidateClass, importSelector.class);
        ParserStrategyUtils.invokeAwareMethods(
            selector, this.environment, this.resourceLoader, this.registry);
        if (selector instanceof DeferredimportSelector) { // 看看是不是一个Defer selector(延迟被导入的)
            this.deferredimportSelectorHandler.handle( // 处理加入
                configClass, (DeferredimportSelector) selector);
        } else {
            String[] importClassNames = selector.selectimports(currentSourceClass.getmetadata());
            Collection importSourceClasses = asSourceClasses(importClassNames);
            processimports(configClass, currentSourceClass, importSourceClasses, false);
        }
    }    
...
}

public void handle(ConfigurationClass configClass, DeferredimportSelector importSelector) {
    DeferredimportSelectorHolder holder = new DeferredimportSelectorHolder(
        configClass, importSelector);
    if (this.deferredimportSelectors == null) {
        DeferredimportSelectorGroupingHandler handler = new DeferredimportSelectorGroupingHandler();
        handler.register(holder);
        handler.processGroupimports(); // 调用处理
    }
    else {
        this.deferredimportSelectors.add(holder);
    }
}

public void processGroupimports() {
    for (DeferredimportSelectorGrouping grouping : this.groupings.values()) {
        grouping.getimports().forEach(entry -> { // here	
            ConfigurationClass configurationClass = this.configurationClasses.get(
                entry.getmetadata());
            try {
                processimports(configurationClass, asSourceClass(configurationClass),
                               asSourceClasses(entry.getimportClassName()), false);
            }
            catch (BeanDefinitionStoreException ex) {
                throw ex;
            }
            catch (Throwable ex) {
                throw new BeanDefinitionStoreException(
                    "Failed to process import candidates for configuration class [" +
                    configurationClass.getmetadata().getClassName() + "]", ex);
            }
        });
    }
}

public Iterable getimports() {
    for (DeferredimportSelectorHolder deferredimport : this.deferredimports) {
        // 调用 process
        this.group.process(deferredimport.getConfigurationClass().getmetadata(),
                           deferredimport.getimportSelector());
    }
    return this.group.selectimports(); // selectimports
}

这就是这两个方法的调用地方。

上述就是 EnableAutoConfiguration 为 key 自动配置类的收集过程。有自动配置类的收集并加入到 spring 容器,前面提到的 aop,事务,缓存,mvc 功能就已经导入到 springboot 工程了。

6. AOP 功能的自动配置类
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,

AopAutoConfiguration

这个就是 AOP 功能的自动配置类,如果我们要开启 aop 功能,必须要在 xml 里面加配置或者用注解的方式手动开启 aop 功能、注解方式开启 aop

功能如图:

手动开启 aop 功能的这个注解其实就是往 spring 容器里面加入了 一个支持 aop 功能的入口类。

@Configuration
@ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class,
		AnnotatedElement.class })
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {

	@Configuration
	@EnableAspectJAutoProxy(proxyTargetClass = false)
	@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = false)
	public static class JdkDynamicAutoProxyConfiguration {

	}

	@Configuration
	@EnableAspectJAutoProxy(proxyTargetClass = true)
	@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true)
	public static class CglibAutoProxyConfiguration {

	}
}

默认是开启 aop 自动配置功能的,默认是开启了 cglib 的动态代理功能的,并且也加上了EnableAspectJAutoProxy(proxyTargetClass = false) 注解了,加上这个注解就会开启 aop 功能。

EnableAspectJAutoProxy这个注解可以作用在内部类, 并且在SpringBoot的自动配置类中经常出现内部类, 并且这两个方法都是标记作用,没有任何实现逻辑

EnableAspectJAutoProxy说明

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@documented
@import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

	
	boolean proxyTargetClass() default false;

	
	boolean exposeProxy() default false;

}

Configuration说明

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@documented
@Component
public @interface Configuration {

	
	@AliasFor(annotation = Component.class)
	String value() default "";

    
	boolean proxyBeanMethods() default true; // 代理@Bean的方法, 默认代理且代理都是通过CGLIB代理实现, 这里没有使用JDK的选项, 这里和EnableAspectJAutoProxy#proxyTargetClass的相同,true表示使用cglib, 只不过这里的false不使用代理, 默认比是true不是false

}
7. Condition 功能的实现

Condition 功能的使用很简单 使用的需求是:有的时候我们需要当某一个条件满足的时候才把一些类实例化并 加入到 spring 容器中。

@ConditionalOnBean: 当 spring 容器中存在 jack 这个 bean 时,才调用该方法

@Bean
@ConditionalOnBean(name = "order")
public User CglibAutoProxyConfiguration {
    return new User();
}

其他注解类似

@ConditionalOnClass

@ConditionalOnMissingBean

@ConditionalOnMissingClass

@ConditionalOnexpression( " ${spring.datasource.max-idle} == 10")

@ConditionalOnProperty(perfix = “spring.redis”, name = “host”, havingValue = “192.168.10.10”)

自定义 condition
public class CustomCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypemetadata metadata) {
        System.out.println("=====CustomCondition.matches======");
        String property = context.getEnvironment().getProperty("spring.redis.jedis.pool.max-active");

        return !"8".equals(property);
    }
}

当自定义 CustomCondition 中的 matches 方法返回 true 时才会调用到该方法。 @Conditional 注解作用在类上面也是一样的使用方式

@Component
@Conditional(value = CustomCondition.class)
public class CustomConditionBean {
}

Condition 的原理和源码

从 condition 的使用需求我们知道,这个是单条件满足的时候才实例化 bean 和 加入到 spring 容器,而在 spring 中一个类的实例化必须要变成 beanDefinition 对象。而 ConfigurationClassPostProcessor 是所有 beanDefinition 对象的集散地,所有的 beanDefinition 都会在这个类里面处理。那么我们要完成 Condition 功能也必定在这个类里面。

ConfigurationClassParser类中的 shouldSkip 方法就是做 bean 过滤 的。

protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
    if (this.conditionevaluator.shouldSkip(configClass.getmetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
        return;
    }
    ...
}
for (Condition condition : conditions) {
    ConfigurationPhase requiredPhase = null;
    if (condition instanceof ConfigurationCondition) {
        requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
    }
    // matches方法,是核心方法
    if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
        return true;
    }
}

SpringBootCondition#matches(ConditionContext, AnnotatedTypemetadata)

public final boolean matches(ConditionContext context, AnnotatedTypemetadata metadata) {
    String classOrMethodName = getClassOrMethodName(metadata);
    try {
        // 模板方法,不同注解调用实现不一样
        ConditionOutcome outcome = getMatchOutcome(context, metadata);
        logOutcome(classOrMethodName, outcome);
        recordevaluation(context, classOrMethodName, outcome);
        return outcome.isMatch();
    }
    catch (NoClassDefFoundError ex) {
        throw new IllegalStateException("...", ex);
    }
    catch (RuntimeException ex) {
        throw new IllegalStateException("Error processing condition on " + getName(metadata), ex);
    }
}

这里看两个注解的实现

org.springframework.boot.autoconfigure.condition.ConditionalOnBean

对应的注解实现是: org.springframework.boot.autoconfigure.condition.OnBeanCondition

Bean 存在时才掉用方法,这个其实很好理解,判断 bean 是否存在其实就只要从 BeanFactory 中找就行了,源码里面就是从 BeanFactory 中找。

@Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypemetadata metadata) {
    ConditionMessage matchMessage = ConditionMessage.empty();
    MergedAnnotations annotations = metadata.getAnnotations();
    if (annotations.isPresent(ConditionalOnBean.class)) {
        Spec spec = new Spec<>(context, metadata, annotations, ConditionalOnBean.class);
        MatchResult matchResult = getMatchingBeans(context, spec); // 核心逻辑
        if (!matchResult.isAllMatched()) {
            String reason = createOnBeanNoMatchReason(matchResult);
            return ConditionOutcome.noMatch(spec.message().because(reason));
        }
        matchMessage = spec.message(matchMessage).found("bean", "beans").items(Style.QUOTE,
                                                                               matchResult.getNamesOfAllMatches());
    }
    ...
    return ConditionOutcome.match(matchMessage);
}
protected final MatchResult getMatchingBeans(ConditionContext context, Spec spec) {
...
    MatchResult result = new MatchResult();
    Set beansIgnoredByType = getNamesOfBeansIgnoredByType(classLoader, beanFactory, considerHierarchy,spec.getIgnoredTypes(), parameterizedContainers);
    for (String type : spec.getTypes()) {
        // 更具注解类型从容器中获取bean
        Collection typeMatches = getBeanNamesForType(classLoader, considerHierarchy, beanFactory, type, parameterizedContainers);
        typeMatches.removeAll(beansIgnoredByType);
        if (typeMatches.isEmpty()) {
            result.recordUnmatchedType(type);
        }
        else {
            result.recordMatchedType(type, typeMatches);
        }
    }
    ...
    return result;
}

从 BeanFactory 中获取对应的实例,如果有则匹配。

org.springframework.boot.autoconfigure.condition.ConditionalOnClass

对应的注解实现是: org.springframework.boot.autoconfigure.condition.OnClassCondition

当工程上下文中存在该类时才调用方法 实现原理,就是通过反射的方式,如果反射有异常则返回 false,如果反射没异 常返回 true

@Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypemetadata metadata) {
   ClassLoader classLoader = context.getClassLoader();
   ConditionMessage matchMessage = ConditionMessage.empty();
   List onClasses = getCandidates(metadata, ConditionalOnClass.class);
   if (onClasses != null) {
       // 核心逻辑
      List missing = filter(onClasses, ClassNameFilter.MISSING, classLoader);
      if (!missing.isEmpty()) {
         return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnClass.class)
               .didNotFind("required class", "required classes").items(Style.QUOTE, missing));
      }
      matchMessage = matchMessage.andCondition(ConditionalOnClass.class)
            .found("required class", "required classes")
            .items(Style.QUOTE, filter(onClasses, ClassNameFilter.PRESENT, classLoader));
   }
   List onMissingClasses = getCandidates(metadata, ConditionalOnMissingClass.class);
   if (onMissingClasses != null) {
      List present = filter(onMissingClasses, ClassNameFilter.PRESENT, classLoader);
      if (!present.isEmpty()) {
         return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnMissingClass.class)
               .found("unwanted class", "unwanted classes").items(Style.QUOTE, present));
      }
      matchMessage = matchMessage.andCondition(ConditionalOnMissingClass.class)
            .didNotFind("unwanted class", "unwanted classes")
            .items(Style.QUOTE, filter(onMissingClasses, ClassNameFilter.MISSING, classLoader));
   }
   return ConditionOutcome.match(matchMessage);
}
protected final List filter(Collection classNames, ClassNameFilter classNameFilter,
                                    ClassLoader classLoader) {
    if (CollectionUtils.isEmpty(classNames)) {
        return Collections.emptyList();
    }
    List matches = new ArrayList<>(classNames.size());
    for (String candidate : classNames) {
        if (classNameFilter.matches(candidate, classLoader)) { // 一个枚举方法,看入参的实现
            matches.add(candidate);
        }
    }
    return matches;
}
MISSING {

    @Override
    public boolean matches(String className, ClassLoader classLoader) {
        return !isPresent(className, classLoader);
    }

};
static boolean isPresent(String className, ClassLoader classLoader) {
    if (classLoader == null) {
        classLoader = ClassUtils.getDefaultClassLoader();
    }
    try {
        resolve(className, classLoader); // 看是否有异常
        return true;
    }
    catch (Throwable ex) {
        return false;
    }
}
8. Redis 自动配置

自动配置类

org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,

为什么可以在程序里面直接依赖注入 RedisTemplate,在自动配置类创建了该实

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RedisOperations.class) // 更具class决定是否引入该功能
@EnableConfigurationProperties(RedisProperties.class) // 开启配置属性的java bean
@import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class }) // 导入功能相关类
public class RedisAutoConfiguration {

	@Bean
	@ConditionalOnMissingBean(name = "redisTemplate") // 没有bean时候才注入
	public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory)
			throws UnknownHostException {
		RedisTemplate template = new RedisTemplate<>();
		template.setConnectionFactory(redisConnectionFactory);
		return temp
            late; // 我们使用的RedisTemplate就是通过@Bean方式注入的, 所以@Bean注解在SpringBoot中使用非常频繁
	}

	@Bean // 同上
	@ConditionalOnMissingBean
	public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory)
			throws UnknownHostException {
		StringRedisTemplate template = new StringRedisTemplate();
		template.setConnectionFactory(redisConnectionFactory);
		return template;
	}
    
}
9. 数据源自动配置

自动配置类

org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@EnableConfigurationProperties(DataSourceProperties.class)
// 导入公共类
@import({ DataSourcePoolmetadataProvidersConfiguration.class, DataSourceInitializationConfiguration.class })
public class DataSourceAutoConfiguration {

	@Configuration(proxyBeanMethods = false)
	@Conditional(EmbeddedDatabaseCondition.class)
	@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
	@import(EmbeddedDataSourceConfiguration.class) // 导入需要的类
	protected static class EmbeddedDatabaseConfiguration {

	}

	@Configuration(proxyBeanMethods = false)
	@Conditional(PooledDataSourceCondition.class)
	@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
	@import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,
			DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.Generic.class,
			DataSourceJmxConfiguration.class })
	protected static class PooledDataSourceConfiguration {

	}

	
	static class PooledDataSourceCondition extends AnyNestedCondition {

		PooledDataSourceCondition() {
			super(ConfigurationPhase.PARSE_CONFIGURATION);
		}

		@ConditionalOnProperty(prefix = "spring.datasource", name = "type")
		static class ExplicitType {

		}

		@Conditional(PooledDataSourceAvailableCondition.class)
		static class PooledDataSourceAvailable {

		}

	}

	
	static class PooledDataSourceAvailableCondition extends SpringBootCondition {

		@Override
		public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypemetadata metadata) {
			ConditionMessage.Builder message = ConditionMessage.forCondition("PooledDataSource");
			if (DataSourceBuilder.findType(context.getClassLoader()) != null) {
				return ConditionOutcome.match(message.foundExactly("supported DataSource"));
			}
			return ConditionOutcome.noMatch(message.didNotFind("supported DataSource").atAll());
		}

	}

	
	static class EmbeddedDatabaseCondition extends SpringBootCondition {

		private final SpringBootCondition pooledCondition = new PooledDataSourceCondition();

		@Override
		public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypemetadata metadata) {
			ConditionMessage.Builder message = ConditionMessage.forCondition("EmbeddedDataSource");
			if (anyMatches(context, metadata, this.pooledCondition)) {
				return ConditionOutcome.noMatch(message.foundExactly("supported pooled data source"));
			}
			EmbeddedDatabaseType type = EmbeddedDatabaseConnection.get(context.getClassLoader()).getType();
			if (type == null) {
				return ConditionOutcome.noMatch(message.didNotFind("embedded database").atAll());
			}
			return ConditionOutcome.match(message.found("embedded database").items(type));
		}

	}

}

默认是有 Hikari 数据源对象的。

// org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration.Hikari
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(HikariDataSource.class)
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.zaxxer.hikari.HikariDataSource",
                       matchIfMissing = true)
static class Hikari {

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.hikari")
    HikariDataSource dataSource(DataSourceProperties properties) {
        HikariDataSource dataSource = createDataSource(properties, HikariDataSource.class);
        if (StringUtils.hasText(properties.getName())) {
            dataSource.setPoolName(properties.getName());
        }
        return dataSource;
    }

}
10. JdbcTemplate 自动配置
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ DataSource.class, JdbcTemplate.class })
@ConditionalOnSingleCandidate(DataSource.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
@EnableConfigurationProperties(JdbcProperties.class)
@import({ JdbcTemplateConfiguration.class, NamedParameterJdbcTemplateConfiguration.class })
public class JdbcTemplateAutoConfiguration {

}

JdbcTemplateConfiguration配置JdbcTemplate的bean

@Configuration(proxyBeanMethods = false) // false, 说明,每次调用都会原始方法,即不代理原始方法
@ConditionalOnMissingBean(JdbcOperations.class)
class JdbcTemplateConfiguration {

	@Bean
	@Primary
	JdbcTemplate jdbcTemplate(DataSource dataSource, JdbcProperties properties) {
		JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
		JdbcProperties.Template template = properties.getTemplate();
		jdbcTemplate.setFetchSize(template.getFetchSize());
		jdbcTemplate.setMaxRows(template.getMaxRows());
		if (template.getQueryTimeout() != null) {
			jdbcTemplate.setQueryTimeout((int) template.getQueryTimeout().getSeconds());
		}
		return jdbcTemplate;
	}

}
11. 事务管理器自动配置
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ JdbcTemplate.class, PlatformTransactionManager.class })
@AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE)
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceTransactionManagerAutoConfiguration {

	@Configuration(proxyBeanMethods = false) // 不使用代理(CGLIB代理:true), 即每次都调用原始的@Bean方法
	@ConditionalOnSingleCandidate(DataSource.class)
	static class DataSourceTransactionManagerConfiguration {

		@Bean
		@ConditionalOnMissingBean(PlatformTransactionManager.class)
		DataSourceTransactionManager transactionManager(DataSource dataSource,
				ObjectProvider transactionManagerCustomizers) {
			DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(dataSource);
			transactionManagerCustomizers.ifAvailable((customizers) -> customizers.customize(transactionManager));
			return transactionManager;
		}

	}

}
12. 事务自动配置
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,

编程式事务

@Configuration(proxyBeanMethods = false)
@ConditionalOnSingleCandidate(PlatformTransactionManager.class)
public static class TransactionTemplateConfiguration {

    @Bean
    @ConditionalOnMissingBean(TransactionOperations.class)
    public TransactionTemplate transactionTemplate(PlatformTransactionManager transactionManager) {
        return new TransactionTemplate(transactionManager);
    }

}

事务功能导入注解

@Configuration(proxyBeanMethods = false)
@ConditionalOnBean(TransactionManager.class)
@ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class)
public static class EnableTransactionManagementConfiguration {

    @Configuration(proxyBeanMethods = false)
    @EnableTransactionManagement(proxyTargetClass = false) // 开启事务管理器代理
    @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
                           matchIfMissing = false)
    public static class JdkDynamicAutoProxyConfiguration {

    }

    @Configuration(proxyBeanMethods = false)
    @EnableTransactionManagement(proxyTargetClass = true) // 开启事务管理器代理
    @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
                           matchIfMissing = true)
    public static class CglibAutoProxyConfiguration {

    }

}
13. DispatcherServlet 自动配置
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,

DispatcherServlet

@Configuration(proxyBeanMethods = false)
@Conditional(DefaultDispatcherServletCondition.class)
@ConditionalOnClass(ServletRegistration.class)
@EnableConfigurationProperties({ HttpProperties.class, WebMvcProperties.class })
protected static class DispatcherServletConfiguration {

    @Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
    public DispatcherServlet dispatcherServlet(HttpProperties httpProperties, WebMvcProperties webMvcProperties) {
        DispatcherServlet dispatcherServlet = new DispatcherServlet();
        dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());
        dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());
        dispatcherServlet.setThrowExceptionIfNoHandlerFound(webMvcProperties.isThrowExceptionIfNoHandlerFound());
        dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());
        dispatcherServlet.setEnableLoggingRequestDetails(httpProperties.isLogRequestDetails());
        return dispatcherServlet;
    }

    @Bean
    @ConditionalOnBean(MultipartResolver.class)
    @ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
    public MultipartResolver multipartResolver(MultipartResolver resolver) {
        // Detect if the user has created a MultipartResolver but named it incorrectly
        return resolver;
    }

}

DispatcherServletRegistrationBean

@Configuration(proxyBeanMethods = false)
@Conditional(DispatcherServletRegistrationCondition.class)
@ConditionalOnClass(ServletRegistration.class)
@EnableConfigurationProperties(WebMvcProperties.class)
@import(DispatcherServletConfiguration.class)
protected static class DispatcherServletRegistrationConfiguration {

    @Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
    @ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
    public DispatcherServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet,
                                                                           WebMvcProperties webMvcProperties, ObjectProvider multipartConfig) {
        DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet,
                                                                                               webMvcProperties.getServlet().getPath());
        registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
        registration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());
        multipartConfig.ifAvailable(registration::setMultipartConfig);
        return registration;
    }

}
14. MVC 自动配置
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,

其实 mvc 的自动配置就是把一些支持 mvc 功能的类创建出来 比如:handlerMapping,HandlerAdapter,ViewResolver 等等实例

@Bean
@Override
public RequestMappingHandlerAdapter requestMappingHandlerAdapter( // 映射处理适配器
    @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
    @Qualifier("mvcConversionService") FormattingConversionService conversionService,
    @Qualifier("mvcValidator") Validator validator) {
    RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter(contentNegotiationManager,
                                                                              conversionService, validator);
    adapter.setIgnoreDefaultModelOnRedirect(
        this.mvcProperties == null || this.mvcProperties.isIgnoreDefaultModelOnRedirect());
    return adapter;
}

@Override
protected RequestMappingHandlerAdapter createRequestMappingHandlerAdapter() { // 被调用的方法
    if (this.mvcRegistrations != null && this.mvcRegistrations.getRequestMappingHandlerAdapter() != null) {
        return this.mvcRegistrations.getRequestMappingHandlerAdapter();
    }
    return super.createRequestMappingHandlerAdapter();
}

@Bean
@Primary
@Override
public RequestMappingHandlerMapping requestMappingHandlerMapping( // 映射处理器
    @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
    @Qualifier("mvcConversionService") FormattingConversionService conversionService,
    @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
    // Must be @Primary for MvcUriComponentsBuilder to work
    return super.requestMappingHandlerMapping(contentNegotiationManager, conversionService,
                                              resourceUrlProvider);
}

@Bean // 欢迎页面映射
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext,
                                                           FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
    WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(
        new TemplateAvailabilityProviders(applicationContext), applicationContext, getWelcomePage(),
        this.mvcProperties.getStaticPathPattern());
    welcomePageHandlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider));
    return welcomePageHandlerMapping;
}

private Optional getWelcomePage() { // 获取欢迎页面
    String[] locations = getResourceLocations(this.resourceProperties.getStaticLocations());
    return Arrays.stream(locations).map(this::getIndexHtml).filter(this::isReadable).findFirst();
}

private Resource getIndexHtml(String location) { // 获取默认的索引页面, index.html
    return this.resourceLoader.getResource(location + "index.html");
}


@Bean
@Override
public FormattingConversionService mvcConversionService() {
    WebConversionService conversionService = new WebConversionService(this.mvcProperties.getDateFormat());
    addFormatters(conversionService);
    return conversionService;
}

@Bean
@ConditionalOnMissingBean
public InternalResourceViewResolver defaultViewResolver() { // 内部视图解析器
    InternalResourceViewResolver resolver = new InternalResourceViewResolver();
    resolver.setPrefix(this.mvcProperties.getView().getPrefix());
    resolver.setSuffix(this.mvcProperties.getView().getSuffix());
    return resolver;
}

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5719666.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-18
下一篇 2022-12-18

发表评论

登录后才能评论

评论列表(0条)