手写springboot

这篇具有很好参考价值的文章主要介绍了手写springboot。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

 首先确定springboot在spring基础上主要做了哪些改动:
  1. 内嵌tomcat
  2. spi技术动态加载

一、基本实现

1. 建一个工程目录结构如下:
springboot:  源码实现逻辑
user         :   业务系统

手写springboot,spring boot,后端,java,springboot

2.springboot工程项目构建
1. pom依赖如下
   <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>
2. SpringBoot时,核心会用到SpringBoot一个类和注解:
  1. @SpringBootApplication,这个注解是加在应用启动类上的,也就是main方法所在的类
  2. SpringApplication,这个类中有个run()方法,用来启动SpringBoot应用的.

下面一一实现:

 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.TYPE)
 @Configuration
 @ComponentScan
 @Import(KcImportSelect.class)
public @interface KcSpringBootApplication {

}
public class KcSpringApplication {

    public static AnnotationConfigWebApplicationContext  run(Class cls){
        /**
         * spring启动步骤:
         * 1、构建上下文对象
         * 2、注册配置类
         * 3、刷新容器
         */
        AnnotationConfigWebApplicationContext  context=new AnnotationConfigWebApplicationContext();
        context.register(cls);
        context.refresh();
        /**
         * 内嵌tomcat\jetty  启动
         */
        WebServer  webServer=getWebServer(context);
        webServer.start();
        return context;
    }

    /**
     * 获取服务,有可能tomcat\jetty或者其他服务器
     * @param context
     * @return
     */
    public static WebServer getWebServer(AnnotationConfigWebApplicationContext  context){

        Map<String, WebServer> beansOfType = context.getBeansOfType(WebServer.class);

        if(beansOfType.isEmpty()||beansOfType.size()>1){
            throw new NullPointerException();
        }

        return beansOfType.values().stream().findFirst().get();
    }

}

3.内嵌tomcat、jetty服务器实现

项目根据pom配置动态实现tomcat\jetty内嵌要求如下:

  1. 如果项目中有Tomcat的依赖,那就启动Tomcat
  2. 如果项目中有Jetty的依赖就启动Jetty
  3. 如果两者都没有则报错
  4. 如果两者都有也报错

首先定义服务接口WebServer

public interface WebServer {

    void  start()  ;
}

tomcat服务实现:

public class TomcatWebServer implements WebServer {

    private Tomcat tomcat;

    public TomcatWebServer(WebApplicationContext webApplicationContext) {

        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(webApplicationContext));

        context.addServletMappingDecoded("/*", "dispatcher");

    }

    @Override
    public void start() {
        try {
            System.out.println("tomcat start......");
            tomcat.start();
        }catch (Exception e){
            e.printStackTrace();
        }

    }
}

jetty服务实现(具体实现逻辑没写,具体实现逻辑类似tomcat实现)

public class JettyWebServer implements WebServer{
    @Override
    public void start() {
        System.out.println("jetty  start......");
    }
}

思考:jetty\tomcat都已实现,总不能用if/else这样决定用哪个服务扩展性太差,基于此,就联想到spring的Condition条件注解和参考springboot中的OnClassCondition这个注解。

具体实现如下:

public class KcOnClassCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {

        Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(KcConditionalOnClass.class.getName());
        String value = (String) annotationAttributes.get("value");

        try {
            context.getClassLoader().loadClass(value);
        } catch (ClassNotFoundException e) {
            return false;
        }
        return true;
    }
}
@Configuration
public class WebServerConfiguration{

    @Bean
    @KcConditionalOnClass("org.apache.catalina.startup.Tomcat")
    public TomcatWebServer tomcatWebServer( WebApplicationContext webApplicationContext){
        return new TomcatWebServer(webApplicationContext);
    }
    @Bean
    @KcConditionalOnClass("org.eclipse.jetty.server.Server")
    public JettyWebServer  jettyWebServer(){
        return new JettyWebServer();
    }
}

至此,springboot简化版已实现完成,首先启动看看
手写springboot,spring boot,后端,java,springboot

4.基于JDK的SPI实现扫描AutoConfiguration接口
  • AutoConfiguration接口
public interface AutoConfiguration {
}

  • 实现DeferredImportSelector接口实现类(具体为什么实现Import这个接口,请看以前的文章,主要这个接口具有延迟功能)
public class KcImportSelect implements DeferredImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {

        ServiceLoader<AutoConfiguration> load = ServiceLoader.load(AutoConfiguration.class);

        List<String> list = new ArrayList<>();

        for (AutoConfiguration autoConfiguration : load) {
            list.add(autoConfiguration.getClass().getName());
        }
        return list.toArray(new String[0]);
    }
}
  • 即KcSpringBootApplication注解导入该配置类
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.TYPE)
 @Configuration
 @ComponentScan
 @Import(KcImportSelect.class)
public @interface KcSpringBootApplication {

}
  • WebServerConfiguration实现AutoConfiguration接口
@Configuration
public class WebServerConfiguration implements AutoConfiguration{

    @Bean
    @KcConditionalOnClass("org.apache.catalina.startup.Tomcat")
    public TomcatWebServer tomcatWebServer( WebApplicationContext webApplicationContext){
        return new TomcatWebServer(webApplicationContext);
    }
    @Bean
    @KcConditionalOnClass("org.eclipse.jetty.server.Server")
    public JettyWebServer  jettyWebServer(){
        return new JettyWebServer();
    }
}
  • 在springboot项目下创建META-INFO/service 接口全路径命名的文件,文件内容接口实现类全路径
    手写springboot,spring boot,后端,java,springboot

至此,springboot简易版已全部实现。

二、应用业务系统引入自己构建的springboot

1、user项目的pom依赖(引入自己构建的springboot项目)
    <dependencies>
        <dependency>
            <groupId>com.kc</groupId>
            <artifactId>springboot</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
2、启动类
@ComponentScan(basePackages = {
        "kc.*"})
    @KcSpringBootApplication
public class UserApplication {


    public static void main(String[] args) {
        AnnotationConfigWebApplicationContext run = KcSpringApplication.run(UserApplication.class);
        System.out.println(run.getBeanFactory());

    }
}
3、实现具体业务类
@RestController
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("test")
    public String test() {
        return userService.test();
    }
}
@Service
public class UserService {

    public String test() {
        return "hello  springboot";
    }
}

4、启动测试访问

手写springboot,spring boot,后端,java,springboot

三、项目地址

git地址文章来源地址https://www.toymoban.com/news/detail-634049.html

到了这里,关于手写springboot的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 手写超级好用的rabbitmq-spring-boot-start启动器

    手写超级好用的rabbitmq-spring-boot-start启动器   由于springBoot官方提供的默认的rabbitMq自动装配不是那么好用,一个项目中只能配置使用一个rabbitMq的服务器,队列也需要编码的方式定义,这种繁杂且不易使用,用一次需要写一次硬编码,之前有一个想法是,能不能使用springB

    2024年04月13日
    浏览(52)
  • Java后端实现不用pagehelper。手写分页如何实现?

    如果你不使用PageHelper这样的分页插件,你可以手动实现分页逻辑。下面是一个使用Java后端手写分页的示例: 首先,确定每页显示的数据量和当前页码。 确定查询总数据量的SQL语句。 执行上述SQL语句,获取总数据量。 根据总数据量和每页显示的数据量计算总页数。 根据当前

    2024年02月12日
    浏览(37)
  • Spring Boot 整合 Shiro(后端)

    1 Shiro 什么是 Shiro 官网: http://shiro.apache.org/ 是一款主流的 Java 安全框架,不依赖任何容器,可以运行在 Java SE 和 Java EE 项目中,它的主要作用是对访问系统的用户进行身份认证、 授权、会话管理、加密等操作。 Shiro 就是用来解决安全管理的系统化框架。 2 Shiro 核心组件 用

    2024年02月09日
    浏览(51)
  • Android前端+Spring Boot后端 登录功能实现

    创建项目后,自己添加包,框架如下   userController里的一些内容,只供参考,代码不全,无法实现 数据库是直接在社区版IDEA里连接Mysql,在控制台端创建的数据库和user表,用于数据交互。 Activity包里是Activity Java类,主要响应layout包里activity_login.xml等页面布局内的按钮响应 a

    2024年02月12日
    浏览(71)
  • React.js前端 + Spring Boot后端员工管理

    该项目是一个员工管理系统,前端使用 React.js 构建,后端使用 Spring Boot 和 Data JPA 和 Lombok 构建。它提供了有效管理员工信息的全面解决方案。 特征 响应式设计:响应式 UI 设计,确保跨各种设备的可用性。 数据验证:验证用户输入以确保数据完整性。 使用的技术 前端:R

    2024年04月28日
    浏览(50)
  • Spring Boot后端+Vue前端:打造高效二手车交易系统

    作者介绍: ✌️大厂全栈码农|毕设实战开发,专注于大学生项目实战开发、讲解和毕业答疑辅导。 🍅 获取源码联系方式请查看文末 🍅  推荐订阅精彩专栏 👇🏻 避免错过下次更新 Springboot项目精选实战案例 更多项目: CSDN主页YAML墨韵 学如逆水行舟,不进则退。学习如赶

    2024年04月28日
    浏览(63)
  • Spring Boot后端与Vue前端融合:构建高效旅游管理系统

    作者介绍: ✌️大厂全栈码农|毕设实战开发,专注于大学生项目实战开发、讲解和毕业答疑辅导。 🍅 获取源码联系方式请查看文末 🍅  推荐订阅精彩专栏 👇🏻 避免错过下次更新 Springboot项目精选实战案例 更多项目: CSDN主页YAML墨韵 学如逆水行舟,不进则退。学习如赶

    2024年04月28日
    浏览(58)
  • 【Spring Boot】请求参数传json数组,后端采用(pojo)新增案例(103)

    请求参数传json数组,后端采用(pojo)接收的前提条件: 1.pom.xml文件加入坐标依赖:jackson-databind 2.Spring Boot 的启动类加注解:@EnableWebMvc 3.Spring Boot 的Controller接受参数采用:@RequestBody 4.postman入参采用json格式 备注: 此处省略:pom文件加入坐标依赖和启动类加注解:@EnableWebM

    2024年02月14日
    浏览(39)
  • 【Spring Boot】请求参数传json对象,后端采用(pojo)CRUD案例(102)

    请求参数传json对象,后端采用(pojo)接收的前提条件: 1.pom.xml文件加入坐标依赖:jackson-databind 2.Spring Boot 的启动类加注解:@EnableWebMvc 3.Spring Boot 的Controller接受参数采用:@RequestBody 4.postman入参采用json格式 1.pom.xml文件加入坐标: 2.Spring Boot 启动类:加注解:@EnableWebMvc POJO类

    2024年02月14日
    浏览(42)
  • ELADMIN - 免费开源 admin 后台管理系统,基于 Spring Boot 和 Vue ,包含前端和后端源码

    一款简单好用、功能强大的 admin 管理系统,包含前端和后端源码,分享给大家。 ELADMIN 是一款基于 Spring Boot、Jpa 或 Mybatis-Plus、 Spring Security、Redis、Vue 的前后端分离的后台管理系统。 ELADMIN 的作者在 Github 和 Gitee 上看了很多的项目,发现大多数都是基于 Mybatis , 而基于 Sp

    2024年02月04日
    浏览(56)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包