手写SpringBoot启动器主要步骤

news2024/11/25 0:43:21

这里写目录标题

  • 背景
  • 过程
    • 2.1自启动实现原理
    • 2.2手动实现SpringBoot自启动
      • 2.2.1宏观
      • 2.2.1微观
        • 2.2.1.1三个服务之间调用
        • 2.2.1.2自定义注解
        • 2.2.1.1业务组装
        • 2.2.1.3启动类
    • 升华
      • 自定义注解:
      • 手动装配组件:
      • 简化启动过程:
      • 自动化注入依赖:
      • 简化启动类:

背景

更好的理解框架:通过手写Spring Boot启动类,你将深入了解框架的内部机制和工作原理。你可以手动配置各种组件、定义Bean以及设置各种属性,从而更好地理解框架的运行方式。

过程

2.1自启动实现原理

1、Spring Boot是一个用于构建Java应用程序的开源框架,它简化了Spring应用程序的配置和部署。以下是一个模拟的Spring Boot启动过程的简要描述:

2、加载配置:当应用程序启动时,Spring Boot首先会加载应用程序的配置。这些配置可以包括应用程序的属性、数据库配置、日志配置等。

3、创建应用程序上下文:Spring Boot会创建一个应用程序上下文,该上下文包含了所有被管理的Bean以及它们之间的依赖关系。这个上下文可以让您访问和管理应用程序中的各个组件。

4、扫描和注册Bean:Spring Boot会扫描应用程序中的所有类,查找带有注解的Bean,并将它们注册到应用程序上下文中。常见的注解包括@Component、@Service、@Controller等。

6、自动配置:Spring Boot具有自动配置的特性,它根据应用程序的依赖和配置自动配置各种功能。例如,如果应用程序依赖于数据库,Spring Boot可以自动配置数据源和持久化框架。

7、启动应用程序:一旦所有的Bean都注册到应用程序上下文中,Spring Boot会启动应用程序,开始监听HTTP请求或其他入口点。

8、运行应用程序:应用程序开始运行,处理来自客户端的请求。根据应用程序的配置,Spring Boot可以处理路由、控制器、服务等,以满足客户端的需求。

2.2手动实现SpringBoot自启动

2.2.1宏观

在这里插入图片描述

2.2.1微观

2.2.1.1三个服务之间调用

@MyComponent("classService")
public class ClassService {
    @MyAutowired
    private TestService testService;

    public void test(){
        this.testService.test();
    }
}

@MyComponent("testService")
public class TestService {
    @MyAutowired
    private UserService userService;


    private String name;

    public void test(){
        userService.test();
    }
}
@MyComponent("userService")
public class UserService {


//    @MyAutowired
//    ClassService classService;
    public void test(){
//        classService.test();
        System.out.println("你好");
    }
}

2.2.1.2自定义注解

MyComponent :装配注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyComponent {
    String value();
}

MyAutowired :属性注入的注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface MyAutowired {
}

MyComponentScan :扫包的注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyComponentScan {
    String value();
}

2.2.1.1业务组装

BeanDefinition:对对象的信息进行包装

public class BeanDefinition {
    private Class beanClass;

    public Class getBeanClass() {
        return beanClass;
    }

    public void setBeanClass(Class beanClass) {
        this.beanClass = beanClass;
    }
}

上下文类:

public class MyApplicationContext {
    private Map<String,BeanDefinition> beanDefinitionMap = new HashMap<>();

    private Map<String,Object> singletonObjects =new HashMap<>();

    //1、获取自动配置类相关信息
    public void run(Class configClass) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        //2、扫包
        this.scanPackage(configClass);

        //4、属性注入
        initAutowired();

    }
    private void scanPackage(Class configClass) throws ClassNotFoundException {
        MyComponentScan myComponentScan = (MyComponentScan) configClass.getAnnotation(MyComponentScan.class);
        String packagePath =  myComponentScan.value();
        packagePath = packagePath.replace(".","/");
        //拿到service包中所有的类的class对象
        List<Class> beanClass = getBeanClass(packagePath, configClass);

        for (Class aClass : beanClass) {
            //3、创建bean对象
            if (aClass.isAnnotationPresent(MyComponent.class)){
                BeanDefinition beanDefinition = new BeanDefinition();
                beanDefinition.setBeanClass(aClass);
                MyComponent myComponent = (MyComponent) aClass.getAnnotation(MyComponent.class);
                String beanName = myComponent.value();
                //将创建的bean对象放到map中
                beanDefinitionMap.put(beanName,beanDefinition);
            }

        }
    }

    private List<Class> getBeanClass(String packagePath,Class configClass) throws ClassNotFoundException {
        List<Class> beanClassList = new ArrayList<>();
        URL resource = configClass.getClassLoader().getResource(packagePath);
        File file = new File(resource.getFile());
        File[] files = file.listFiles();
        for (File f : files) {
            String fileName = f.getAbsolutePath();
            System.out.println(fileName);
            fileName = fileName.substring(fileName.indexOf("com"),fileName.indexOf(".class"));
            fileName = fileName.replace("\\",".");
            Class clazz = Class.forName(fileName);
            beanClassList.add(clazz);
        }
        return beanClassList;
    }


//将注入的属性进行初始化
    private void initAutowired() throws InstantiationException, IllegalAccessException {
        for (String beanName : beanDefinitionMap.keySet()) {
            BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
            Class beanClass = beanDefinition.getBeanClass();
            Object instance = beanClass.newInstance();
            //TestService
			//读取每个类中的属性
            Field[] declaredFields = beanClass.getDeclaredFields();
            for (Field field : declaredFields) {
                if (field.isAnnotationPresent(MyAutowired.class)){
                    field.setAccessible(true);
                    String fieldName = field.getName();
                    BeanDefinition definition = beanDefinitionMap.get(fieldName);
                    Object newInstance = definition.getBeanClass().newInstance();
                    field.set(instance,newInstance);
                }
            }
            //属性注入的对象放到另外一个容器里边
            singletonObjects.put(beanName,instance);
        }
    }

    public Object getBean(String beanName){
        return singletonObjects.get(beanName);
    }
}

2.2.1.3启动类

@MyComponentScan("com.example.demo.service")
public class DemoApplication {
    public static void main(String[] args) throws Exception {
        MyApplicationContext myApplicationContext = new MyApplicationContext();
        myApplicationContext.run(DemoApplication.class);

        Object testService = myApplicationContext.getBean("classService");
        Method method = testService.getClass().getMethod("test");
        method.invoke(testService);
    }
}

升华

自定义注解:

通过自定义注解(@MyComponent和@MyAutowired),你可以标识需要被Spring容器管理的组件,以及需要进行属性注入的依赖关系。这样可以实现基于注解的组件装配和依赖注入,简化了配置和编码工作。

手动装配组件:

在MyApplicationContext类中,你手动进行了组件的扫描、创建和属性注入过程。这样可以实现自定义的组件装配逻辑,灵活控制组件的创建和初始化过程。

简化启动过程:

通过MyApplicationContext类的run()方法,你可以一次性完成组件的扫描、创建和属性注入等启动过程。这样可以简化启动代码,减少了手动配置的工作量。

自动化注入依赖:

在MyApplicationContext类的initAutowired()方法中,你实现了自动注入属性依赖的逻辑。当一个组件需要依赖其他组件时,通过@MyAutowired注解,你可以自动将依赖的实例注入到目标组件中。这样可以减少手动编写属性注入的代码,提高开发效率。

简化启动类:

在启动类DemoApplication中,你只需实例化MyApplicationContext并调用run()方法即可完成启动过程。这样可以将启动类的逻辑简化为几行代码,提高了可读性和维护性。

这个示例是一个简化版的Spring Boot启动器,并没有涵盖完整的Spring Boot功能和特性。实际的Spring Boot启动器通常会涉及更复杂的配置和功能,例如自动配置、条件化装配等。手写Spring Boot启动器可以让你更深入地理解Spring Boot的原理和机制,并根据实际需求进行定制和扩展。

如果要解决各个Service之间互相依赖的问题又该如何进行解决呢,是不是就要引入三级缓存呢?请大家思考。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/648356.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

马原第三章复习1.

唯物史观和唯心史观过去出过小题 社会意识出小题 社会存在一般出大题 124 社会存在和社会意识(往往出大题) 社会历史性的基本问题 两种根本对立的历史史观 唯心主义: 至多考察人的思想动机 没有考虑思想背后的物质动因和经济根源 把社会史观看成人的思想,,不懂得…

关于酒店宾馆电气火灾隐患的预防与整改措施介绍 安科瑞 许敏

摘要&#xff1a;本文分析了酒店、宾馆电气火灾隐患的特点及产生的主要原因&#xff0c;并依此提出了消除火灾隐患的整改措施。 关键词:酒店宾馆&#xff1b;火灾&#xff1b;隐患&#xff1b;预防&#xff1b;整改&#xff1b;措施 1前言 随着旅居服务业的快速发展&#xf…

CVPR 2023 | 香港理工提出GrowSP:3D场景的无监督语义分割

点击下方卡片&#xff0c;关注“CVer”公众号 AI/CV重磅干货&#xff0c;第一时间送达 点击进入—>【目标检测和Transformer】交流群 GrowSP: Unsupervised Semantic Segmentation of 3D Point Clouds 论文链接&#xff1a;https://arxiv.org/abs/2305.16404 代码&#xff1…

2023/6/11总结

CSS Less嵌套 子元素的选择器可以直接写在父元素里面。 如果不是它的后代元素&#xff0c;比如你想写伪类选择器、交集选择器&#xff0c;需要在前面加&号。 Less运算&#xff1a; 加减乘除都可以&#xff0c;运算符必须用空格隔开。如果俩个元素都有单位&#xff0…

binfmt_misc

一&#xff1a;binfmt_misc是什么 binfmt_misc是内核中的一个功能&#xff0c;它能将非本机的二进制文件与特定的解析器自动匹配起来&#xff0c;进行二进制解析。 例如&#xff0c;在x86上解析arm64架构的二进制。 通过binfmt_misc可以注册解析器来处理指定二进制文件格式的请…

Qt|QDialog的创建及使用

文章目录 创建一个新的类继承QDialog设置标题去掉问号&#xff0c;只保留关闭使窗口在屏幕中心显示设置窗口大小QDialog没有任务栏窗口图标问题将窗口永远置于上层可见 不会被遮盖阻塞除当前窗口之外的所有窗口添加closeEvent hideEvent同理调用dialog类接收dialog返回状态&…

华为OD机试真题 JavaScript 实现【跳房子II】【2023 B卷 100分】,附详细解题思路

一、题目描述 跳房子&#xff0c;也叫跳飞机&#xff0c;是一种世界性的儿童游戏。 游戏参与者需要分多个回合按顺序跳到第1格直到房子的最后一格&#xff0c;然后获得一次选房子的机会&#xff0c;直到所有房子都被选完&#xff0c;房子最多的人获胜。 跳房子的过程中&…

XGBoost超参数调优指南

本文将详细解释XGBoost中十个最常用超参数的介绍&#xff0c;功能和值范围&#xff0c;及如何使用Optuna进行超参数调优。 对于XGBoost来说&#xff0c;默认的超参数是可以正常运行的&#xff0c;但是如果你想获得最佳的效果&#xff0c;那么就需要自行调整一些超参数来匹配你的…

jupyter lab升级或者安装插件后编译失败

错误回显 报错提示&#xff1a;please run ‘jupyter lab build’ on the server for full output&#xff0c;那么就进入prompt执行一下jupyter lab build 继续接着报错 If you dont already have a jupyter_config.py file, you can create one by adding a blank file of th…

线下实体衰落,真是电商惹祸?实是贪婪以及服务理念落后所致

网上时不时就有人指责电商的兴起导致了线下实体衰落&#xff0c;然而如果各位比较了线下实体与电商的差异&#xff0c;就会明白导致如此结果完全是咎由自取&#xff0c;因为线下实体太贪婪以及服务理念落后于时代。 笔者最近就购买了某款国产手机&#xff0c;在该国产手机品牌的…

集显独显并存,ubuntu安装显卡驱动的坑

一、安装和启动黑屏卡死 1、怎么办&#xff1f;显示器先接集显&#xff0c;完成驱动安装。 &#xff08;1&#xff09;屏蔽nouveau驱动 只要是安装过NVIDIA显卡驱动的&#xff0c;nouveau一般都被禁止了。可以通过命令&#xff1a; lsmod | grep nouveau 查看。如果没有任…

实现设备的延时控制

1. 引言 当搭建IoT管理后台后&#xff0c;APP、设备、云端三端就可以实现交互&#xff1b;当点击APP中的控制按钮&#xff0c;其控制指令就可以经过云端转发到设备执行&#xff0c;当设备执行后将设备的状态上报到云端&#xff0c;APP通过轮训可以取到设备此时的状态&#xff0…

Spring Boot 优雅集成 Spring Security 5.7(安全框架)

Spring Boot 集成 Spring Security &#xff08;安全框架&#xff09; 本章节将介绍 Spring Boot 集成 Spring Security 5.7&#xff08;安全框架&#xff09;。 &#x1f916; Spring Boot 2.x 实践案例&#xff08;代码仓库&#xff09; 介绍 Spring Security 是一个能够为基…

为行业变革注入新动能,行易道入选“高工智能汽车智驾榜单”

6月8日到9日&#xff0c;2023高工智能汽车开发者大会在上海成功举行。与会期间&#xff0c;北京行易道科技有限公司&#xff08;以下简称“行易道”&#xff09;营销副总裁袁泽雁带来了以“车载毫米波雷达进入成像时代”主题演讲&#xff0c;为大家分享了4D毫米波雷达如何以“新…

Java网络开发(Tomcat异步分页+增删改查)——从同步到异步 从jsp 到 js + axios + vue 实现 数据分页显示 数据增删改查

目录 引出一些固定的东西1.固定的响应格式2.name 变成 v-model 进行双向绑定3.下拉框选中--:value"type.id" v-model"companyDb.typeId"4.vue导包固定写法5.script固定写法6.axios的get请求7.axios的post请求---let params new URLSearchParams()8.前端美…

MYSQL 在优化器缺陷在次验证,与MYSQL 熄火了 还是 成熟了??

开头还是介绍一下群&#xff0c;如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;CTO&#xff0c;可以解决你的问题。加群请联系 liuaustin3 &#xff0c;在新加的朋友会分到2群&#xff08;共…

聊聊我做 NeRF-3D重建性能优化经历

我们新推出大淘宝技术年度特刊《长期主义&#xff0c;往往从一些小事开始——工程师成长总结专题》&#xff0c;专题收录多位工程师真诚的心路历程与经验思考&#xff0c;覆盖终端、服务端、数据算法、技术质量等7大技术领域&#xff0c;欢迎一起沟通交流。 本文为此系列第四篇…

飞桨携手第二届GitLink开源夏令营,邀你参与顶尖开源项目!

想参与顶尖开源项目开发&#xff1f; 想熟悉开源社区参与流程&#xff1f; 想获得资深导师指导和丰厚现金奖励&#xff1f; 机会来啦&#xff01; 2016年9月&#xff0c;飞桨框架正式开源&#xff0c;其兼备易用性、高效性、灵活性和可扩展性等特点。如今&#xff0c;百度飞桨在…

软件工程:说透软件5种常见的部署策略

hi&#xff0c;我是熵减&#xff0c;见字如面。 在软件工程中&#xff0c;最终的价值交付&#xff0c;都是要通过软件的部署上线来完成的。 那如何将新的或改进的软件功能交付给用户&#xff0c;同时还要确保高质量、稳定性和用户体验&#xff0c;选择适当的部署策略变得至关重…

数字中国,开鸿见日

讲个小故事&#xff0c;《晋书乐广传》记载&#xff0c;西晋名士乐广&#xff0c;请大文学家潘岳替自己写一篇文章。潘岳让乐广把意思完完整整告诉他&#xff0c;再由他来动笔&#xff0c;最终写成了名扬当时的《呈太尉辞河南尹表》。时人看过这篇文章&#xff0c;评价乐广是“…