• SpringBoot 底层机制分析


    SpringBoot 底层机制分析

    主要内容:【Tomcat 启动分析 + Spring 容器初始化 +Tomcat 如何关联 Spring 容器 】

    1.搭建 SpringBoot 底层机制开发环境

    1、创建 Maven 项目 llp-springboot

    image-20220730103418193

    2、修改pom.xml,导入相关的依赖

    
    <parent>
       <artifactId>spring-boot-starter-parentartifactId>
       <groupId>org.springframework.bootgroupId>
       <version>2.5.3version>
    parent>
    
    <dependencies>
       <dependency>
          <groupId>org.springframework.bootgroupId>
          <artifactId>spring-boot-starter-webartifactId>
       dependency>
    
    dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    3.创建src\main\java\com\llp\springboot\MainApp.java

    @SpringBootApplication
    public class MainApp {
        public static void main(String[] args) {
            ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);
            System.out.println(ioc);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    4、启动项目 ok, Tomcat 也启动了[如何实现的?]

    image-20220730103605413

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

    1.创建src\main\java\com\llp\springboot\bean\Dog.java

    public class Dog {
    }
    
    • 1
    • 2

    2.创建src\main\java\com\llp\springboot\config\BeanConfig.java

    @Configuration
    public class BeanConfig {
    
        @Bean
        public Dog dog(){
            return new Dog();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3.启动容器,看看容器中是否已经注入了 dog 实例

    可以看到容器已经注入了dog实例

    image-20220730104019367

    这里有一个小的技巧,我们这里查看singletonObjects单例池时时简化的显示的,如果需要查看完成数据结构可以参考如下设置

    image-20220730104124449

    image-20220730104348459

    再次查看,可以看到debug集合显示的数据结构更完整了,这个设置可以按需灵活切换

    image-20220730104431775

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

    1.创建src\main\java\com\llp\springboot\controller\HelloController.java

    @RestController
    public class HelloController {
    
        @RequestMapping("/hi")
        public String hello(){
            return "hello llp-SpringBoot";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2.访问测试

    image-20220730104734278

    4.源码分析: SpringApplication.run()

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

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

    @SpringBootApplication
    public class MainApp {
        public static void main(String[] args) {
            //启动springboot应用程序/项目
            //提出问题: 当我们执行run方法时,怎么就启动我们的内置的tomcat?
            ConfigurableApplicationContext 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 :  运行 Spring 应用程序,创建并刷新一个新的ApplicationContext 。
             *
             *  public ConfigurableApplicationContext run(String... args) {
             *        StopWatch stopWatch = new StopWatch();
             *        stopWatch.start();
             *        DefaultBootstrapContext bootstrapContext = createBootstrapContext();
             *        ConfigurableApplicationContext context = null;
             *        configureHeadlessProperty();
             *        SpringApplicationRunListeners listeners = getRunListeners(args);
             *        listeners.starting(bootstrapContext, this.mainApplicationClass);
             *        try {
             *           ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
             *           ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
             *           configureIgnoreBeanInfo(environment);
             *           Banner printedBanner = printBanner(environment);
             *           context = createApplicationContext(); //严重分析: 创建容器
             *           context.setApplicationStartup(this.applicationStartup);
             *           prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
             *           refreshContext(context); //严重分析: 刷新应用程序上下文,比如 初始化默认设置/注入相关Bean/启动tomcat
             *           afterRefresh(context, applicationArguments);
             *           stopWatch.stop();
             *           if (this.logStartupInfo) {
             *              new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
             *                        }
             *           listeners.started(context);
             *           callRunners(context, applicationArguments);*      }
             *        catch (Throwable ex) {
             *           handleRunFailure(context, ex, listeners);
             *           throw new IllegalStateException(ex);
             *        }
             *
             *        try {
             *           listeners.running(context);
             *        }
             *        catch (Throwable ex) {
             *           handleRunFailure(context, ex, null);
             *           throw new IllegalStateException(ex);
             *        }
             *        return context;
             *    }
             *
             *     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 ex) {
             *           throw new IllegalStateException("Unable create a default ApplicationContext instance, "
             *                 + "you may need a custom ApplicationContextFactory", ex);
             *        }
             *    };
             *
             *     6. SpringApplication.java
             *     private void refreshContext(ConfigurableApplicationContext context) {
             *        if (this.registerShutdownHook) {
             *           shutdownHook.registerApplicationContext(context);
             *                }
             *        refresh(context); //严重分析,真正执行相关任务
             *  }
             *
             *  7. SpringApplication.java
             *  protected void refresh(ConfigurableApplicationContext applicationContext) {
             *        applicationContext.refresh();
             *    }
             *
             *
             *  8. ServletWebServerApplicationContext.java
             *  @Override
             *        public final void refresh() throws BeansException, IllegalStateException {
             *        try {
             *           super.refresh();//分析这个方法
             *        }
             *        catch (RuntimeException ex) {
             *           WebServer webServer = this.webServer;
             *           if (webServer != null) {
             *              webServer.stop();
             *            }
             *           throw ex;
             *        }
             *    }
             *
             * 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
             *  @Override
             *    protected void onRefresh() {
             *        super.onRefresh();
             *        try {
             *           createWebServer();//看到胜利的曙光,创建webserver 可以理解成会创建指定web服务-Tomcat
             *                }
             *        catch (Throwable ex) {
             *           throw new ApplicationContextException("Unable to start web server", ex);
             *        }    *   }
             *   11. ServletWebServerApplicationContext.java
             *
             *   private void createWebServer() {
             *        WebServer webServer = this.webServer;
             *        ServletContext servletContext = getServletContext();
             *        if (webServer == null && servletContext == null) {
             *           StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");
             *           ServletWebServerFactory factory = getWebServerFactory();
             *           createWebServer.tag("factory", factory.getClass().toString());
             *           this.webServer = factory.getWebServer(getSelfInitializer());//严重分析,使用TomcatServletWebServerFactory 创建一个TomcatWebServer
             *           createWebServer.end();
             *           getBeanFactory().registerSingleton("webServerGracefulShutdown",
             *                 new WebServerGracefulShutdownLifecycle(this.webServer));
             *           getBeanFactory().registerSingleton("webServerStartStop",
             *                 new WebServerStartStopLifecycle(this, this.webServer));
             *                }
             *        else if (servletContext != null) {
             *           try {
             *              getSelfInitializer().onStartup(servletContext);
             *            }
             *           catch (ServletException ex) {
             *              throw new ApplicationContextException("Cannot initialize servlet context", ex);
             *            }
             *        }
             *        initPropertySources();    *    }
             *
             *     12. TomcatServletWebServerFactory.java 会创建Tomcat 并启动Tomcat
             *
             *        @Override
             *    public WebServer getWebServer(ServletContextInitializer... initializers) {
             *        if (this.disableMBeanRegistry) {
             *           Registry.disableRegistry();
             *        }
             *        Tomcat tomcat = new Tomcat();//创建了Tomcat对象
             *        File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
             *         //做了一系列的设置
             *        tomcat.setBaseDir(baseDir.getAbsolutePath());
             *
             *        Connector connector = new Connector(this.protocol);
             *        connector.setThrowOnFailure(true);
             *        tomcat.getService().addConnector(connector);
             *        customizeConnector(connector);
             *        tomcat.setConnector(connector);
             *        tomcat.getHost().setAutoDeploy(false);
             *        configureEngine(tomcat.getEngine());
             *        for (Connector additionalConnector : this.additionalTomcatConnectors) {
             *           tomcat.getService().addConnector(additionalConnector);
             *        }
             *        prepareContext(tomcat.getHost(), initializers);
             *        return getTomcatWebServer(tomcat); //严重分析该方法.
             *    }
             *
             *    13. TomcatServletWebServerFactory.java , 这里做了校验创建 TomcatWebServer
             *    protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
             *        return new TomcatWebServer(tomcat, getPort() >= 0, getShutdown());
             *        }
             *    14. TomcatServletWebServerFactory.java
             *    public TomcatWebServer(Tomcat tomcat, boolean autoStart, Shutdown shutdown) {
             *        Assert.notNull(tomcat, "Tomcat Server must not be null");
             *        this.tomcat = tomcat;
             *        this.autoStart = autoStart;
             *        this.gracefulShutdown = (shutdown == Shutdown.GRACEFUL) ? new GracefulShutdown(tomcat) : null;
             *        initialize();//分析这个方法.
             *        }
             *    15.TomcatServletWebServerFactory.java
             *
             *    private void initialize() throws WebServerException {
             *        logger.info("Tomcat initialized with port(s): " + getPortsDescription(false));
             *        synchronized (this.monitor) {
             *           try {
             *              addInstanceIdToEngineName();
             *
             *              Context context = findContext();
             *              context.addLifecycleListener((event) -> {
             *                 if (context.equals(event.getSource()) && Lifecycle.START_EVENT.equals(event.getType())) {
             *                    // Remove service connectors so that protocol binding doesn't
             *                    // happen when the service is started.
             *                    removeServiceConnectors();
             *                                        }                *            });
             *
             *              // Start the server to trigger initialization listeners
             *              this.tomcat.start(); //启动Tomcat
             *
             *              // We can re-throw failure exception directly in the main thread
             *              rethrowDeferredStartupExceptions();
             *
             *              try {
             *                 ContextBindings.bindClassLoader(context, context.getNamingToken(), getClass().getClassLoader());
             *                }
             *              catch (NamingException ex) {
             *                 // Naming is not enabled. Continue
             *                }
             *
             *              // Unlike Jetty, all Tomcat threads are daemon threads. We create a
             *              // blocking non-daemon to stop immediate shutdown
             *              startDaemonAwaitThread();
             *            }
             *           catch (Exception ex) {
             *              stopSilently();
             *              destroySilently();
             *              throw new WebServerException("Unable to start embedded Tomcat", ex);
             *            }
             *        }
             *    }
             */
            System.out.println(ioc);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301

    5.实现 SpringBoot 底层机制 【Tomcat 启动分析 + Spring 容器初始化+Tomcat 如何关联 Spring 容器 】

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

    1.说明: 创建 Tomcat, 并启动

    2.分析+代码实现

    1.修改pom.xml

    
    <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.0modelVersion>
    
       <groupId>com.llpgroupId>
       <artifactId>llp-springbootartifactId>
       <version>1.0-SNAPSHOTversion>
    
       
       <parent>
          <artifactId>spring-boot-starter-parentartifactId>
          <groupId>org.springframework.bootgroupId>
          <version>2.5.3version>
       parent>
    
       <dependencies>
          <dependency>
             <groupId>org.springframework.bootgroupId>
             <artifactId>spring-boot-starter-webartifactId>
             
             <exclusions>
                 <exclusion>
                     <groupId>org.springframework.bootgroupId>
                     <artifactId>spring-boot-starter-tomcatartifactId>
                 exclusion>
             exclusions>
          dependency>
    
    
          
          <dependency>
              <groupId>org.apache.tomcat.embedgroupId>
              <artifactId>tomcat-embed-coreartifactId>
              <version>8.5.75version>
          dependency>
    
          
          <dependency>
              <groupId>org.apache.tomcatgroupId>
              <artifactId>tomcat-jasperartifactId>
              <version>8.5.75version>
          dependency>
    
       dependencies>
    
    
    project>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    2.创建src\main\java\com\llp\llpspringboot\LLPSpringApplication.java

    public class LLPSpringApplication {
    
        public static void run() {
            try {
                //创建tomcat对象
                Tomcat tomcat = new Tomcat();
                //设置端口
                tomcat.setPort(9090);
                //启动
                tomcat.start();
    
                //等待请求接入
                System.out.println("=====9090====等待请求");
                tomcat.getServer().await();
            } catch (LifecycleException e) {
                e.printStackTrace();
            }
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    3.创建主启动类src\main\java\com\llp\llpspringboot\LLPMainApp.java

    /**
     * 模拟主程序
     */
    public class LLPMainApp {
        public static void main(String[] args) {
            LLPSpringApplication.run();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3.完成测试

    image-20220730181035195

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

    1.说明: 创建 Spring 容器

    2.分析+代码实现

    ● 代码实现

    1.创建bean src\main\java\com\llp\llpspringboot\bean\Monster.java

    public class Monster {
    }
    
    • 1
    • 2

    2.创建配置类

    /**
     * LLPBeanConfig:配置类-作为Spring的配置文件
     * 在配置类可以指定要扫描包: @ComponentScan("com.llp.llpspringboot")
     */
    @Component
    @ComponentScan("com.llp.llpspringboot")
    public class LLPBeanConfig {
    
        @Bean
        public Monster monster() {
            return new Monster();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    3.创建src\main\java\com\llp\llpspringboot\Controller\LLPHelloController.java

    @RestController
    public class LLPHelloController {
    
        @RequestMapping("llphi")
        public String hello(){
            return "hi llp";
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    4.创建src\main\java\com\llp\llpspringboot\LLPWebApplicationInitializer.java,作为Spring容器

    /**
     * 1. 创建我们的Spring 容器
     * 2. 加载/关联Spring容器的配置-按照注解的方式
     * 3. 完成Spring容器配置的bean的创建, 依赖注入
     * 4. 创建前端控制器 DispatcherServlet , 并让其持有Spring容器
     * 5. 当DispatcherServlet 持有容器, 就可以进行分发映射
     * 6. 这里onStartup 是Tomcat调用, 并把ServletContext 对象传入
     */
    public class LLPWebApplicationInitializer implements WebApplicationInitializer {
        @Override
        public void onStartup(ServletContext servletContext) throws ServletException {
    
            System.out.println("startup ....");
            //加载Spring web application configuration => 容器
            AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
            //在ac中注册 LLPBeanConfig.class 配置类
            ac.register(LLPBeanConfig.class);
            //完成bean的创建和配置
            ac.refresh();
    
            //1. 创建注册非常重要的前端控制器 DispatcherServlet
            //2. 让DispatcherServlet 持有容器
            //3. 这样就可以进行映射分发
            //LLPDispatcherServlet
            DispatcherServlet dispatcherServlet = new DispatcherServlet(ac);
            //返回了ServletRegistration.Dynamic对象
            ServletRegistration.Dynamic registration = servletContext.addServlet("app", dispatcherServlet);
            //当tomcat启动时,加载 dispatcherServlet 如果不在启动时加载前端控制器则无法进行请求分发
            registration.setLoadOnStartup(1);
    
    
            //拦截请求,并进行分发处理
    
            // /不会拦截页面,只会拦截路径。
            // /* 会路径和页面
            // / 和 /*  拦截所有请求进行分发处理
            // /* 是拦截所有的文件夹,不包含子文件夹
            // /** 是拦截所有的文件夹及里面的子文件夹
            registration.addMapping("/");
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

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

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

    2.分析+代码实现

    ● 代码实现

    1.修改src\main\java\com\llp\llpspringboot\LLPSpringApplication.java

    public class LLPSpringApplication {
    
        public static void run() {
            try {
                //创建tomcat对象
                Tomcat tomcat = new Tomcat();
                //让tomcat可以将请求转发到springweb容器,因此需要进行关联
                // ”/llpboot“ 就是项目的工程路径(application context)
                // "E:\\IdeaProjects\\llp-springboot" 指定项目的目录
                tomcat.addWebapp("/llpboot", "E:\\IdeaProjects\\llp-springboot");
                //设置端口
                tomcat.setPort(9090);
                //启动
                tomcat.start();
    
                //等待请求接入
                System.out.println("=====9090====等待请求");
                tomcat.getServer().await();
            } catch (LifecycleException e) {
                e.printStackTrace();
            }
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    1. debug 一下, 看看是否进行 Spring 容器的初始化工作, 可以看到 ac.refresh() 会将 LLPBeanConfig.class 中配置 Bean 实例化装入到容器中

    可以看到,在 ac.refresh()之前,beanFactory为空

    image-20220730181735321

    在执行了 ac.refresh()之后,将bean被注入到了容器中

    image-20220730181908330

    3.完成测试

    image-20220730182004664

    image-20220730182124728

    4.注意事项和细节

    1、如果启动包异常, 如下:

    java.lang.ClassNotFoundException: org.apache.jasper.servlet.JspServlet

    2 、解决方案 ,引入对应版本的 jasper 包 即 可 , 修 改 D:\hsp_springboot_temp\hsp-springboot2\pom.xm

    
    <dependency>
        <groupId>org.apache.tomcatgroupId>
        <artifactId>tomcat-jasperartifactId>
        <version>8.5.75version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
  • 相关阅读:
    python试题实例
    K8S原理架构与实战教程
    无线耳机什么质量好?音质较高的无线蓝牙耳机推荐
    Mysql底层数据结构为什么选择B+树
    JavaScript的垃圾回收机制
    [附源码]计算机毕业设计农村人居环境治理监管系统Springboot程序
    python 获取文件夹中的全部文件
    解决web项目导入到idea后,文件的蓝色小点消失了(web文件资源根路径)
    redis教程
    ceph 线程池分析
  • 原文地址:https://blog.csdn.net/qq_44981526/article/details/126075961