分布式微服务: springboot底层机制实现

在这里插入图片描述

上文中, 我们学习的是springboot容器功能

搭建SpringBoot底层机制开发环境

1.创建 Maven 项目 zzw-springboot, 参考springboot快速入门
在这里插入图片描述

2.在pom.xml引入SpringBoot父工程和web项目场景启动器

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zzw</groupId>
    <artifactId>quickStart</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <!--导入springboot父工程-规定写法[在mybatis中讲过]-->
    <parent>
        <artifactId>spring-boot-starter-parent</artifactId>
        <groupId>org.springframework.boot</groupId>
        <version>2.5.3</version>
    </parent>

    <!--导入web项目场景启动器: 会自动导入和web开发相关的所有依赖[库/jar]
    后面还会说明spring-boot-starter-web 到底引入哪些相关依赖-->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
</project>

3.创建com.zzw.springboot.MainApp.java SpringBoot引用主程序

/**
 * @SpringBootApplication: 表示这是一个springboot引用/项目
 */
@SpringBootApplication
public class MainApp {
    public static void main(String[] args) {
        //启动springboot应用程序/项目
        //提示问题:当我们执行run方法时,怎么就启动了我们的内置的Tomcat?
        //在分析run方法底层机制的基础上, 我们自己尝试实现
        ApplicationContext ioc =
                SpringApplication.run(MainApp.class, args);
    }
}

4.启动项目 ok, 大家注意Tomcat也启动了.[这里请同学们先思考, 是如何实现的?]
在这里插入图片描述

@Configuration+@Bean会发生什么,并分析机制

1.创建D:\idea_project\zzw_springboot\zzw-springboot\src\main\java\com\zzw\springboot\bean\Dog.java

public class Dog {}

2.创建com.zzw.springboot.config

/**
 * @Configuration:指明当前类是一个配置类;充当Spring容器/Spring配置文件
 * 如果该配置类, 在springboot扫描的包/子包下, 会被注入到Spring容器中
 * 在该类中, 可以通过@Bean 来注入其它的组件
 */
@Configuration
public class Config {
    /**
     * 1.通过@Bean的方式, 将new出来的Bean对象, 放入到Spring容器
     * 2.该bean在Spring容器的name/id 默认就是 方法名
     * 3.通过方法名, 可以得到注入到容器中的dog对象
     */
    @Bean
    public Dog dog() {
        return new Dog();
    }
}

3.修改com.zzw.springboot.MainApp.java, 看看容器中是否已经注入了 dog 实例

debug

在这里插入图片描述

ioc容器中已经注入了 dog 实例

在这里插入图片描述

@Configuration注解标注的配置类也会被实例化并被注入到Spring容器.

在这里插入图片描述

4.底层机制分析: 仍然是 我们实现Spring容器那一套机制 IO/文件扫描+注解+反射+集合+映射. 提示: 回去复习一下 实现Spring底层机制.

(1)快捷键查看ioc->singletonObjects->table列表 有多少元素? table右键->Customize Data Views->Enable alternative view for… 但是勾选上会少很多东西
在这里插入图片描述
这里是按照索引排序,无法按照字母排序。

在这里插入图片描述

(2)debug时元素按照字母排列

在这里插入图片描述
在这里插入图片描述

提出问题: SpringBoot 是怎么启动Tomcat, 并可以支持访问@Controller

1.创建com.zzw.springboot.controller.HiController
RestController解释手动实现Tomcat底层机制

/**
 * 1.因为 HiController 被 @RestController 标注, 所以就是一个控制器
 * 2.HiController 在扫描包/子包下,就会被注入到Spring容器
 */
@RestController
public class HiController {

    @RequestMapping("/hi")
    public String hi() {
        return "hi zzw HiController";
    }
}

2.完成测试, 浏览器输入 http://localhost:8080/hi
在这里插入图片描述

3.提出问题: SpringBoot 是怎么内嵌 Tomcat, 并启动Tomcat的? => 追踪源码

源码分析: SpringApplication.run()

1.Debug SpringApplication.run(MainApp.class, args); 看看SpringBoot 是如何启动Tomcat的.

2.我们的Debug目标: 紧抓一条线, 就是看到 tomcat 被启动的代码, 比如 tomcat.start().

3.源码如下

@SpringBootApplication
public class MainApp {
    public static void main(String[] args) {
        //启动springboot应用程序/项目
        //提示问题:当我们执行run方法时,怎么就启动了我们的内置的Tomcat?
        //在分析run方法底层机制的基础上, 我们自己尝试实现
        ApplicationContext ioc =
                SpringApplication.run(MainApp.class, args);

        /**
         *  这里我们开始Debug SpringApplication.run();
         *  1.SpringApplication.java
         *   public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
         *      return run(new Class[]{primarySource}, args);
         *  }
         *  2.SpringApplication.java: 创建返回 ConfigurableApplicationContext(这是个接口)对象
         * public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
         *      return (new SpringApplication(primarySources)).run(args);
         *  }
         *  3.SpringApplication.java
         * public ConfigurableApplicationContext run(String... args) {
         *     StopWatch stopWatch = new StopWatch();
         *     stopWatch.start();
         *     DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
         *     ConfigurableApplicationContext context = null;
         *     this.configureHeadlessProperty();
         *     SpringApplicationRunListeners listeners = this.getRunListeners(args);
         *     listeners.starting(bootstrapContext, this.mainApplicationClass);
         *
         *     try {
         *         ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
         *         ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
         *         this.configureIgnoreBeanInfo(environment);
         *         Banner printedBanner = this.printBanner(environment);
         *         context = this.createApplicationContext();//严重分析: 创建容器
         *         context.setApplicationStartup(this.applicationStartup);
         *         this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
         *         this.refreshContext(context);//严重分析: 刷新应用程序上下文, 比如 初始化默认设置/注入相关bean/启动tomcat
         *         this.afterRefresh(context, applicationArguments);
         *         stopWatch.stop();
         *         if (this.logStartupInfo) {
         *             (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
         *         }
         *
         *         listeners.started(context);
         *         this.callRunners(context, applicationArguments);
         *     } catch (Throwable var10) {
         *         this.handleRunFailure(context, var10, listeners);
         *         throw new IllegalStateException(var10);
         *     }
         *
         *     try {
         *         listeners.running(context);
         *         return context;
         *     } catch (Throwable var9) {
         *         this.handleRunFailure(context, var9, (SpringApplicationRunListeners)null);
         *         throw new IllegalStateException(var9);
         *     }
         * }
         * 4.SpringApplication.java: 容器类型很多, 会根据你的this.webApplicationType创建对应的容器
         * this.webApplicationType 默认是 Servlet, 也就是web容器, 可以处理servlet
         * protected ConfigurableApplicationContext createApplicationContext() {
         *     return this.applicationContextFactory.create(this.webApplicationType);
         * }
         * 5.ApplicationContextFactory.java
         *  ApplicationContextFactory DEFAULT = (webApplicationType) -> {
         *      try {
         *          switch(webApplicationType) {
         *          case SERVLET://默认进入到这个分支, 返回AnnotationConfigServletWebServerApplicationContext容器
         *              return new AnnotationConfigServletWebServerApplicationContext();
         *          case REACTIVE:
         *              return new AnnotationConfigReactiveWebServerApplicationContext();
         *          default:
         *              return new AnnotationConfigApplicationContext();
         *          }
         *      } catch (Exception var2) {
         *          throw new IllegalStateException("Unable create a default ApplicationContext instance, you may need a custom ApplicationContextFactory", var2);
         *      }
         *  };
         *  6.SpringApplication.java
         *  private void refreshContext(ConfigurableApplicationContext context) {
         *      if (this.registerShutdownHook) {
         *          shutdownHook.registerApplicationContext(context);
         *      }
         *
         *      this.refresh(context);//严重分析, 真正执行相关任务
         *  }
         *  7.SpringApplication.java
         *  protected void refresh(ConfigurableApplicationContext applicationContext) {
         *     applicationContext.refresh();
         * }
         * 8.ServletWebServerApplicationContext.java
         * public final void refresh() throws BeansException, IllegalStateException {
         *     try {
         *         super.refresh();//分析这个方法
         *     } catch (RuntimeException var3) {
         *         WebServer webServer = this.webServer;
         *         if (webServer != null) {
         *             webServer.stop();
         *         }
         *
         *         throw var3;
         *     }
         * }
         * 9.AbstractApplicationContext.java
         * @Override
         * 	public void refresh() throws BeansException, IllegalStateException {
         * 		synchronized (this.startupShutdownMonitor) {
         * 			StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
         *
         * 			// Prepare this context for refreshing.
         * 			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.
         * 				postProcessBeanFactory(beanFactory);
         *
         * 				StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
         * 				// Invoke factory processors registered as beans in the context.
         * 				invokeBeanFactoryPostProcessors(beanFactory);
         *
         * 				// Register bean processors that intercept bean creation.
         * 				registerBeanPostProcessors(beanFactory);
         * 				beanPostProcess.end();
         *
         * 				// 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();
         * 			}
         *
         * 			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();
         * 				contextRefresh.end();
         * 			}
         * 		}
         * 	}
         * 	10.ServletWebServerApplicationContext.java
         *  protected void onRefresh() {
         *     super.onRefresh();
         *
         *     try {
         *         this.createWebServer();//看到胜利的曙光. 创建webserver 可以理解成会创建指定web服务-Tomcat
         *     } catch (Throwable var2) {
         *         throw new ApplicationContextException("Unable to start web server", var2);
         *     }
         * }
         * 11.ServletWebServerApplicationContext.java
         *  private void createWebServer() {
         *      WebServer webServer = this.webServer;
         *      ServletContext servletContext = this.getServletContext();
         *      if (webServer == null && servletContext == null) {
         *          StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");
         *          ServletWebServerFactory factory = this.getWebServerFactory();
         *          createWebServer.tag("factory", factory.getClass().toString());
         *          this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});//严重分析, 使用TomcatServletWebServerFactory 创建一个TomcatWebServer
         *          createWebServer.end();
         *          this.getBeanFactory().registerSingleton("webServerGracefulShutdown", new WebServerGracefulShutdownLifecycle(this.webServer));
         *          this.getBeanFactory().registerSingleton("webServerStartStop", new WebServerStartStopLifecycle(this, this.webServer));
         *      } else if (servletContext != null) {
         *          try {
         *              this.getSelfInitializer().onStartup(servletContext);
         *          } catch (ServletException var5) {
         *              throw new ApplicationContextException("Cannot initialize servlet context", var5);
         *          }
         *      }
         *
         *      this.initPropertySources();
         *  }
         *  12.TomcatServletWebServerFactory.java: 会创建Tomcat, 并启动
         *  public WebServer getWebServer(ServletContextInitializer... initializers) {
         *     if (this.disableMBeanRegistry) {
         *         Registry.disableRegistry();
         *     }
         *
         *     Tomcat tomcat = new Tomcat();//创建了Tomcat对象
         *     File baseDir = this.baseDirectory != null ? this.baseDirectory : this.createTempDir("tomcat");
         *     //这里做了一系列配置
         *     tomcat.setBaseDir(baseDir.getAbsolutePath());
         *     Connector connector = new Connector(this.protocol);
         *     connector.setThrowOnFailure(true);
         *     tomcat.getService().addConnector(connector);
         *     this.customizeConnector(connector);
         *     tomcat.setConnector(connector);
         *     tomcat.getHost().setAutoDeploy(false);
         *     this.configureEngine(tomcat.getEngine());
         *     Iterator var5 = this.additionalTomcatConnectors.iterator();
         *
         *     while(var5.hasNext()) {
         *         Connector additionalConnector = (Connector)var5.next();
         *         tomcat.getService().addConnector(additionalConnector);
         *     }
         *
         *     this.prepareContext(tomcat.getHost(), initializers);
         *     return this.getTomcatWebServer(tomcat);//严重分析该方法.
         * }
         * 13.TomcatServletWebServerFactory.java
         * protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
         *     return new TomcatWebServer(tomcat, this.getPort() >= 0, this.getShutdown());
         * }
         * 14.TomcatServletWebServerFactory.java
         * public TomcatWebServer(Tomcat tomcat, boolean autoStart, Shutdown shutdown) {
         *     this.monitor = new Object();
         *     this.serviceConnectors = new HashMap();
         *     Assert.notNull(tomcat, "Tomcat Server must not be null");
         *     this.tomcat = tomcat;
         *     this.autoStart = autoStart;
         *     this.gracefulShutdown = shutdown == Shutdown.GRACEFUL ? new GracefulShutdown(tomcat) : null;
         *     this.initialize();//分析这个方法
         * }
         * 15.TomcatServletWebServerFactory.java
         *  private void initialize() throws WebServerException {
         *     logger.info("Tomcat initialized with port(s): " + this.getPortsDescription(false));
         *     Object var1 = this.monitor;
         *     synchronized(this.monitor) {
         *         try {
         *             this.addInstanceIdToEngineName();
         *             Context context = this.findContext();
         *             context.addLifecycleListener((event) -> {
         *                 if (context.equals(event.getSource()) && "start".equals(event.getType())) {
         *                     this.removeServiceConnectors();
         *                 }
         *
         *             });
         *             this.tomcat.start();//启动Tomcat
         *             this.rethrowDeferredStartupExceptions();
         *
         *             try {
         *                 ContextBindings.bindClassLoader(context, context.getNamingToken(), this.getClass().getClassLoader());
         *             } catch (NamingException var5) {
         *                 ;
         *             }
         *
         *             this.startDaemonAwaitThread();
         *         } catch (Exception var6) {
         *             this.stopSilently();
         *             this.destroySilently();
         *             throw new WebServerException("Unable to start embedded Tomcat", var6);
         *         }
         *
         *     }
         * }
         */
        System.out.println("ok.");
    }
}

SpringBoot的debug流程

在这里插入图片描述

F7, Step Into
在这里插入图片描述

F7, Step Into

在这里插入图片描述

F7, Step Into

在这里插入图片描述

F7, Step Into

在这里插入图片描述

webApplicationType类型可以在配置文件中修改

在这里插入图片描述

F7, Step Into

在这里插入图片描述

Shift+F8, Step Out

在这里插入图片描述

在这里插入图片描述

F7, Step Into

在这里插入图片描述

F7, Step Into

在这里插入图片描述

F7, Step Into

在这里插入图片描述

看看父类的类型

在这里插入图片描述

F7, Step Into

在这里插入图片描述

F7, Step Into

在这里插入图片描述

F7, Step Into

在这里插入图片描述

在这里插入图片描述

F7, Step Into

在这里插入图片描述

F7, Step Into

在这里插入图片描述

放行 Resume Problem

在这里插入图片描述

F7, Step Into

在这里插入图片描述

放行 Resume Problem
在这里插入图片描述

对容器进行估值

在这里插入图片描述

实现SpringBoot底层机制[Tomcat启动分析 + Spring容器初始化 + Tomcat如何关联Spring容器]

实现任务阶段1-创建Tomcat, 并启动

🥦说明:创建Tomcat, 并启动

🥦分析+代码实现

1.修改E:\idea_project\zzw_springboot\zzw-springboot\pom.xml

<!--导入web项目场景启动器: 会自动导入和web开发相关的所有依赖[库/jar]
后面还会说明spring-boot-starter-web 到底引入哪些相关依赖-->
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <!--
            因为我们自己要创建Tomcat对象, 并启动.
            因此我们先排除 内嵌的 spring-boot-starter-tomcat
        -->
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-tomcat</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

    <!--我们指定tomcat版本, 引入tomcat依赖/库

    1.使用指定的tomcat 8.5.75, 请小伙伴也引入这个版本
    2.如果我们引入自己指定的tomcat, 一定要记住把前面spring-boot-starter-tomcat排除
    3.如果你不排除, 会出现 GenericServlet Not Found 的错误提示.
    -->
    <dependency>
        <groupId>org.apache.tomcat.embed</groupId>
        <artifactId>tomcat-embed-core</artifactId>
        <version>8.5.75</version>
    </dependency>
</dependencies>

2.创建src/main/java/com/zzw/zzwspringboot/ZzwSpringApplication.java

public class ZzwSpringApplication {
    //这里我们会创建Tomcat对象, 并关联Spring容器, 并启动
    public static void run() {
        try {
            //创建Tomcat对象
            Tomcat tomcat = new Tomcat();
            //设置9090端口
            tomcat.setPort(9090);
            //启动, 就会在9090端口监听
            tomcat.start();
            //等待请求接入
            System.out.println("====9090 等待请求接入====");
            tomcat.getServer().await();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

3.主程序src/main/java/com/zzw/zzwspringboot/ZzwMainApp.java

//主程序
public class ZzwMainApp {
    public static void main(String[] args) {
        //启动ZzwSpringBoot项目/程序
        ZzwSpringApplication.run();
    }
}

🥦完成测试

1.运行效果
在这里插入图片描述

2.浏览器请求 http://localhost:9090/, 这时没有返回信息, 因为还没有写Controller.
在这里插入图片描述

3.管理员权限运行cmd窗口, 输入netstat -anb. 证明9090端口真的在监听.

在这里插入图片描述

实现任务阶段2-创建Spring容器

🥦说明:创建Spring容器

🥦分析+代码实现

1.新建src/main/java/com/zzw/zzwspringboot/bean/Monster.java, 做一个测试Bean

public class Monster {
}

2.新建src/main/java/com/zzw/zzwspringboot/controller/ZzwHiController.java, 作为Controller

@RestController
public class ZzwHiController {
    @RequestMapping("/hi")
    public String hi() {
        return "hi ZzwHiController";
    }
}

3.新建src/main/java/com/zzw/zzwspringboot/config/ZzwConfig.java, 作为Spring的配置文件

/**
 * ZzwConfig 配置类 作为Spring的配置文件
 * 这里有一个问题, 容器怎么知道要扫描哪些包 ?=> 一会代码体现
 *
 * 在配置类中可以指定要扫描的包: @ComponentScan("com.zzw.zzwspringboot")
 */
@Configuration
@ComponentScan("com.zzw.zzwspringboot")
public class ZzwConfig {
    //注入Bean - monster 对象到Spring容器
    @Bean
    public Monster monster() {
        return new Monster();
    }
}

4.新建src/main/java/com/zzw/zzwspringboot/ZzwWebApplicationInitializer.java

/**
 * 解读
 * 1.创建我们的Spring容器, Initializer-初始化器
 * 2.加载/关联Spring容器的配置-按照注解的方式
 * 3.完成Spring容器配置的bean的创建, 依赖注入
 * 4.创建前端控制器 DispatcherServlet, 并让其持有Spring容器
 * 5.当 DispatcherServlet 持有容器, 就可以进行分发映射, 回忆实现SpringMVC底层机制
 * 6.这里onStartup 是Tomcat调用, 并把ServletContext 对象传入
 */
public class ZzwWebApplicationInitializer implements WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {

        System.out.println("startup ...");

        //加载Spring web application configuration => 容器
        //自己实现的Spring容器叫做 ZzwSpringApplicationContext
        AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
        //在ac中, 注册 ZzwConfig.class配置类
        ac.register(ZzwConfig.class);
        //刷新
        ac.refresh();//完成bean的创建和配置

        //1.创建注册非常重要的前端控制器 DispatcherServlet
        //2.让DispatcherServlet 持有容器
        //3.这样就可以进行映射分发, 回忆一下我们自己实现的SpringMVC的机制
        DispatcherServlet dispatcherServlet = new DispatcherServlet(ac);
        //返回了ServletRegistration.Dynamic 对象
        ServletRegistration.Dynamic registration
                = servletContext.addServlet("app", dispatcherServlet);
        //当tomcat启动时,加载 dispatcherServlet
        registration.setLoadOnStartup(1);
        //拦截请求, 并进行分发处理
        //这里再提示一下 / 和 /* 的区别
        registration.addMapping("/");
    }
}

实现任务阶段3-将Tomcat 和 Spring容器关联, 并启动Spring容器

🥦说明:将Tomcat 和 Spring容器关联, 并启动Spring容器

🥦分析+代码实现

1.修改src/main/java/com/zzw/zzwspringboot/ZzwSpringApplication.java

public class ZzwSpringApplication {
    //这里我们会创建Tomcat对象, 并关联Spring容器, 并启动
    public static void run() {
        try {
            //创建Tomcat对象
            Tomcat tomcat = new Tomcat();

            //1. 让tomcat可以将请求转发到spring web容器, 因此需要进行关联
            //2. "/zzwboot" 就是我们项目的 application context, 就是我们原来配置tomcat时, 指定的 application context
            //3. "E:\idea_project\zzw_springboot\zzw-springboot" 指定项目的目录
            tomcat.addWebapp("/zzwboot", "E:\\idea_project\\zzw_springboot\\zzw-springboot");

            //设置9090端口
            tomcat.setPort(9090);
            //启动, 就会在9090端口监听
            tomcat.start();
            //等待请求接入
            System.out.println("====9090 等待请求接入====");
            tomcat.getServer().await();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

2.debug运行一下, 这时会报错, 解决方案

在这里插入图片描述

refresh()负责注入初始化相关bean, 在未执行refresh方法前, spring容器是没有bean的

在这里插入图片描述

初始化后, 容器中有了bean文件

在这里插入图片描述

🥦完成测试

1.拿掉断点, 运行程序

2.浏览器请求 http://localhost:9090/zzwboot/hi
在这里插入图片描述

🥦注意事项和细节

1.如果启动包异常, 如下:
严重: Servlet [jsp] in web application [/zzwboot] threw load() exception
java.lang.ClassNotFoundException: org.apache.jasper.servlet.JspServlet

2.解决方案: 引入对应版本的jasper包即可, 修改E:\idea_project\zzw_springboot\zzw-springboot\pom.xml

<dependency>
    <groupId>org.apache.tomcat</groupId>
    <artifactId>tomcat-jasper</artifactId>
    <version>8.5.75</version>
</dependency>

接下来, 我们将学习 springboot知识点大全
在这里插入图片描述

  • 28
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
分布式服务架构:原理、设计与实战pdf》是一本介绍分布式服务架构的书籍,以下是我对这本书的回答。 这本书是关于分布式服务架构的原理、设计和实战的指南。分布式服务架构是一种软件架构模式,它通过将一个应用程序分解为多个独立的服务来处理不同的业务逻辑。每个服务都可以独立部署、扩展和管理,通过网络进行通信和协作。 在这本书中,作者首先介绍了分布式服务架构的基本原理和概念。他们解释了为什么分布式服务架构在现代软件开发中如此重要,以及如何将其与传统的单体应用程序架构进行对比。接着,他们详细讨论了设计分布式服务架构的一些关键问题,如服务的边界划分、通信机制、数据一致性和容错机制等。同时,他们还介绍了一些常用的分布式服务框架和工具,如Dubbo、Spring Cloud和Kubernetes等。 在实战部分,作者提供了一些实际案例和应用场景,展示了如何应用分布式服务架构来解决现实世界中的问题。他们从不同的角度和维度分析了这些案例,包括性能优化、系统可用性、弹性伸缩和容灾等。通过这些案例,读者可以更好地理解和应用分布式服务架构。 总的来说,这本书在分布式服务架构的原理、设计和实战方面提供了全面的指导。无论是对于初学者还是有一定经验的开发人员来说,这本书都是一个宝贵的参考资料。它不仅介绍了基本原理和关键概念,还提供了一些实际的案例和经验教训。通过阅读这本书,读者可以更好地理解和应用分布式服务架构,从而提高软件开发的效率和质量。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

~ 小团子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值