首页 > 其他分享 >手写SpringBoot启动器主要步骤

手写SpringBoot启动器主要步骤

时间:2023-06-17 22:39:14浏览次数:42  
标签:启动器 SpringBoot Spring Boot 应用程序 class 2.2 手写 public



这里写目录标题

  • 背景
  • 过程
  • 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宏观

手写SpringBoot启动器主要步骤_属性注入

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之间互相依赖的问题又该如何进行解决呢,是不是就要引入三级缓存呢?请大家思考。


标签:启动器,SpringBoot,Spring,Boot,应用程序,class,2.2,手写,public
From: https://blog.51cto.com/u_15845711/6506381

相关文章

  • 手写nacos
    目录背景过程Demo1端Demo2端SDK端Serve端1、某一个服务启动,将此服务信息放到注册表中2、当注册表中有新添加的信息,遍历整个注册列表,每个服务都拉下来一份新的注册列表3、哪个服务中的配置文件发生过改变,就让哪个服务重新拉取配置文件4、服务1调用服务2分为几步:服务1先去拿到最新的......
  • springboot中自定义注解在service方法中,aop失效
    问题描述写了个自定义注解,但是该注解只会出现在serviece层中的方法中。启动发现aop未拦截到问题原因:调用service中的xx()方法时,Spring的动态代理帮我们动态生成了一个代理的对象,暂且叫他$XxxxService。所以调用xx()方法实际上是代理对象$XxxxService调用的。但是在xx()方法内调用同......
  • springboot注册过滤器
    springboot注册过滤器需要使用过滤器的话,优先选择拦截器。因为拦截器符合aop思想。在springboot中使用过滤器有三种方式。分别如下方式一:传统web在传统javaweb、ssm中使用过滤器差不多类似,这里以java配置为例,实现Filter接口@WebFilter("/*")publicclassMyFilter01i......
  • SpringBoot整合ActiveMQ
    第一步: 第二步: 第三步: 下面如有需要才使用 ......
  • Springboot整合mongodb
    入门案例创建工程,导入依赖导入依赖点击查看代码<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb</artifactId><version>2.3.9.RELEASE</version>......
  • SpringBoot--MQ不生效
    Cannotresolveconfigurationproperty'rabbitmq.username'rabbitmq:username:adminpassword:adminvirtual-host:test_datalistener:simple:#表示消费者消费成功消息以后需要手工的进行签收(ack确认),默认为autoacknowledge-mode:manualprefet......
  • springboot @Bean自动注册
    这个注解,可以注册Bean到spring容器中@BeanpublicXXXBeanxxxBean(){returnnewXXXBean();}这个注解也可以用在void方法上,用在在spring容器启动后固定执行某个代码逻辑:@BeanpublicvoidxxxHandler(){System.out.println("我想容器启动后执行一次某个代......
  • SpringBoot学习笔记
    新建SpringBoot项目阿里云地址:https://start.aliyun.com异常消息处理//1.自定义异常类,继承RuntimeExceptionpublicclassMyExceptionextendsRuntimeException{publicMyException(){}}//2.定义全局异常类@RestControllerAdvicepublicclassGloabExcept......
  • SpringBoot整合JavaMail
    第一步:第二步: 第三步:第四步: ......
  • springboot2 自动装配原理
    springboot自动装配Spring支持两种bean配置方式:XML配置、JavaConfig配置@SpringBootApplication注解我们创建一个springboot项目后,一般要用该注解,然后在springbootApplication.run方法传入标注了该注解的类,这样就可以去加载spring的相关操作@SpringBootApplicationpublic......