0
点赞
收藏
分享

微信扫一扫

Red Hat Enterprise Linux Server release 6.7 挂载虚拟光驱ISO文件

非凡兔 03-23 22:30 阅读 2

自己手写的SpringBoot启动器, 是一个学习了解SpringBoot启动逻辑和了解springboot原理的不错的实践Demo. 废话不多说,直接上代码:

项目结构

maven多项目结构, 

myspringboot  自己手写的SpringBoot启动器

service-demo 用来测试SpringBoot启动器的示例项目

项目pom依赖

1. 主项目Maven Pom

<?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>
    <parent>
        <groupId>cn.tekin</groupId>
        <artifactId>myspringboot-app</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>myspringboot</artifactId>
    <packaging>jar</packaging>
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring-version>5.3.29</spring-version>
        <tomcat-version>9.0.80</tomcat-version>
    </properties>

    <dependencies>

        <!-- https://mavenlibs.com/maven/dependency/org.springframework/spring-web -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-version}</version>
        </dependency>


        <!-- https://mavenlibs.com/maven/dependency/org.apache.tomcat.embed/tomcat-embed-core -->
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-core</artifactId>
            <version>${tomcat-version}</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
        <!--  这个插件用于生成可执行jar文件或者war文档 -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

2. 测试项目Maven Pom

<?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>
    <parent>
        <groupId>cn.tekin</groupId>
        <artifactId>myspringboot-app</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>service-demo</artifactId>
    <packaging>jar</packaging>

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

    <dependencies>

        <dependency>
            <groupId>cn.tekin</groupId>
            <artifactId>myspringboot</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        <!-- https://mavenlibs.com/maven/dependency/org.redisson/redisson -->
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.23.3</version>
        </dependency>
        <dependency>
            <groupId>de.ruedigermoeller</groupId>
            <artifactId>fst</artifactId>
            <version>2.57</version>
        </dependency>


    </dependencies>
</project>

 

手写SpringBoot启动器项目核心代码

自定义的SpringBootApplication启动类

package cn.tekin;

import cn.tekin.webserver.MyWebServer;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;

import java.util.Map;

/**
 * 自定义的SpringBootApplication启动类
 */
public class MySpringbootApplication {
    public static void run(Class clazz, String[] args) {
        // 创建一个Spring容器
        AnnotationConfigWebApplicationContext applicationContext= new AnnotationConfigWebApplicationContext();
        // 注册启动类
        applicationContext.register(clazz);
        // 刷新容器
        applicationContext.refresh();


      // 从spring容器中获取WebServer bean 这样就可以解耦 避免if else判断要使用那个WebServer了
        MyWebServer webserver = getWebServer(applicationContext);
        webserver.start(applicationContext);
    }

    /**
     * 这里通过使用上下文中的 getBeansOfType 方法,通过将接口类来获取容器中的所有实现类,从而达到解耦的目的.
     * @param applicationContext
     * @return
     */
    private static MyWebServer getWebServer(WebApplicationContext applicationContext) {
        // 从spring容器中获取WebServer Bean对象
        Map<String, MyWebServer> webservers = applicationContext.getBeansOfType(MyWebServer.class);
        if (webservers.isEmpty()) {
            throw new NullPointerException();
        }

        // 返回map中的第一个对象; 如果有多个Bean, 这里只返回第一个
        return webservers.values().stream().findFirst().get();
    }


}

自定义的SpringBoot注解 @MySpringbootApp

package cn.tekin.anno;

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

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 自定义的Spingboot注解
 *
 * 注意:这里@ComponentScan的没有指定扫描的基础包, spring默认会扫描run参数中传递的类所在的包下面的所有类
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Configuration
@ComponentScan(basePackages = {"cn.tekin.config","ws.yunnan.demo"})
public @interface MySpringbootApp {

}

自定义的webserver服务自动配置类 MyWebServerAutoConfiguration

package cn.tekin.config;

import cn.tekin.condition.MyJettyCondition;
import cn.tekin.webserver.MyJettyWebServer;
import cn.tekin.condition.MyTomcatCondition;
import cn.tekin.webserver.MyTomcatWebServer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;


@Configuration
public class MyWebServerAutoConfiguration implements MyAutoConfiguration {

    @Bean
    @Conditional(MyTomcatCondition.class)
    public MyTomcatWebServer tomcatWebServer() {
        return new MyTomcatWebServer();
    }

    @Bean
    @Conditional(MyJettyCondition.class)
    public MyJettyWebServer jettyWebServer() {
        return new MyJettyWebServer();
    }

}

自定义的Tomcat服务启动类 MyTomcatWebServer

package cn.tekin.webserver;

import org.apache.catalina.*;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.core.StandardEngine;
import org.apache.catalina.core.StandardHost;
import org.apache.catalina.startup.Tomcat;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

public class MyTomcatWebServer implements MyWebServer {
    @Override
    public void start(WebApplicationContext applicationContext) {
        Tomcat tomcat = new Tomcat();

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

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

        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 Started");
    }
}

@Conditional条件注解 条件判断类 MyTomcatCondition

package cn.tekin.condition;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class MyTomcatCondition implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        try {
            // 通过从上下文中 加载Tomcat的核心类来判断pom中是否添加了Tomcat依赖
            conditionContext.getClassLoader().loadClass("org.apache.catalina.startup.Tomcat");
            return true;
        } catch (ClassNotFoundException e) {
            return false;
        }
    }
}

service-demo MySpringBootApp服务测试代码

package ws.yunnan.demo;

import cn.tekin.MySpringbootApplication;
import cn.tekin.anno.MySpringbootApp;

@MySpringbootApp
public class MyApplication {

    public static void main(String[] args) {
        // 这里的MyApplication.class 就是传入Spring容器的配置类, 一般是使用的当前的类, 也可以是其他的类
        MySpringbootApplication.run(MyApplication.class, args);
    }

}

完整项目代码见

Gitee码云
https://gitee.com/tekintian/myspringboot-app

Github
https://github.com/tekintian/myspringboot-app

举报

相关推荐

0 条评论