手写Springboot核心流程

发布时间:2024年01月15日

目录

Springboot启动流程

核心代码

验证效果


Springboot启动流程

  1. 创建Spring容器, 扫描并启动
  2. 容器选择Tomcat/Jetty
  3. 创建DispatchServlet, 与spring容器绑定
  4. 将DispatchServlet添加到Tomcat
  5. 启动Tomcat

核心代码

1. 首先, 创建两个module

?2. maven依赖

springboot模块依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.18</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>5.3.18</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.18</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
        </dependency>

        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-core</artifactId>
            <version>9.0.60</version>
        </dependency>
    </dependencies>

user模块依赖

        <dependency>
            <groupId>org.example</groupId>
            <artifactId>springboot</artifactId>
            <version>1.0-SNAPSHOT</version>
<!--            <exclusions>
                <exclusion>
                    <artifactId>tomcat-embed-core</artifactId>
                    <groupId>org.apache.tomcat.embed</groupId>
                </exclusion>
            </exclusions>-->
        </dependency>
<!--        切换netty-->
<!--        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-server</artifactId>
            <version>9.4.43.v20210629</version>
        </dependency>-->

3. springboot核心配置类?

public class KkSpringApplication {

    /*
        1. 创建Spring容器
        2. 创建Tomcat
        3. 创建DispatchServlet, 与spring容器绑定
        4. 将DispatchServlet添加到Tomcat
        5. 启动Tomcat
     */
    public static void run(Class clazz) {
        AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
        applicationContext.register(clazz);
        applicationContext.refresh();
        WebServer webServer = getWebServer(applicationContext);
        webServer.start(applicationContext);
    }

    private static WebServer getWebServer(AnnotationConfigWebApplicationContext applicationContext) {
        Map<String, WebServer> map = applicationContext.getBeansOfType(WebServer.class);
        if (map.isEmpty()) {
            throw new NullPointerException();
        }
        if (map.size() > 1) {
            throw new IllegalStateException();
        }
        return map.values().stream().findFirst().get();
    }
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Configuration
@ComponentScan
@Import(KkImportSeclet.class)
public @interface KkSpringBootApplication {

}

4. Import自动配置类

public class KkImportSeclet implements DeferredImportSelector {

    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        // 自动配置
        ServiceLoader<AutoConfiguration> loader = ServiceLoader.load(AutoConfiguration.class);
        List<String> list = new ArrayList<>();
        for (AutoConfiguration configuration : loader) {
            list.add(configuration.getClass().getName());
        }
        return list.toArray(new String[0]);
    }
}
@Configuration
public class WebServerAutoConfiguration implements AutoConfiguration{

    @Bean
    @ConditionalOnClass("org.apache.catalina.startup.Tomcat")
    public TomcatWebServer tomcatWebServer(){
        return new TomcatWebServer();
    }

    @Bean
    @ConditionalOnClass("org.eclipse.jetty.server.Server")
    public JettyWebServer jettyWebServer(){
        return new JettyWebServer();
    }
}

public interface AutoConfiguration {
}

?spi注入自动配置类. 资源目录创建文件

5. 条件注解

public class KkCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(ConditionalOnClass.class.getName());
        String className = (String) annotationAttributes.get("value");
        try {
            context.getClassLoader().loadClass(className);
            return true;
        } catch (ClassNotFoundException e) {
            return false;
        }

    }
}
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Conditional(KkCondition.class)
public @interface ConditionalOnClass {

    String value();
}

6. Tomcat启动类实现

public class TomcatWebServer implements WebServer{
    @Override
    public void start(AnnotationConfigWebApplicationContext applicationContext) {
        Tomcat tomcat = new Tomcat();

        Server server = tomcat.getServer();
        Service service = server.findService("Tomcat");

        Connector connector = new Connector();
        connector.setPort(8081);

        Engine engine = new StandardEngine();
        engine.setDefaultHost("localhost");

        Host host = new StandardHost();
        host.setName("localhost");

        String contextPath = "";
        Context context = new StandardContext();
        context.setPath(contextPath);
        context.addLifecycleListener(new Tomcat.FixContextListener());

        host.addChild(context);
        engine.addChild(host);

        service.setContainer(engine);
        service.addConnector(connector);

        tomcat.addServlet(contextPath, "dispatcher", new DispatcherServlet(applicationContext));
        context.addServletMappingDecoded("/*", "dispatcher");
        try {
            tomcat.start();
        } catch (LifecycleException e) {
            e.printStackTrace();
        }
        System.out.println("启动Tomcat ... ");
    }
}

7. User模块使用自定义springboot组件

@KkSpringBootApplication
public class MyApplication {

    public static void main(String[] args) {
        KkSpringApplication.run(MyApplication.class);
    }
}

验证效果

1. 启动MyApplication

?2. 调test接口

文章来源:https://blog.csdn.net/weixin_64027360/article/details/135577981
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。