【Springboot】| 从深入自动配置原理到实现 自定义Springboot starter
作者:mmseoamin日期:2023-12-14

目录

  • 一. 🦁 前言
  • 二. 🦁 Spring-boot starter 原理实现分析
    • 2.1 自动配置原理
    • 三. 🦁 操作实践
      • 3.1 项目场景
      • 3.2 搭建项目
      • 3.3 添加相关依赖
      • 3.4 删除一些不需要的东西
      • 3.5 发邮件工具类逻辑编写
      • 3.6 创建相关配置类
      • 3.7 创建 Spring.factories 文件
      • 3.8 目录结构展示
      • 3.9 打包
      • 四. 🦁 测试使用
      • 五. 🦁 总结
        权限管理

        一. 🦁 前言

        Springboot starter是SpringBoot的一个重要概念,是“一站式服务 (one-stop)”的依赖 Jar 包包含 Spring 以及相关技术(比如 Redis)的所有依赖提供了自动配置的功能,开箱即用提供了良好的依赖管理,避免了包遗漏、版本冲突等问题。

        简单来说, Springboot starter 提供了一种自动配置的机制,我们只需要将需要的Starter引入项目中,它就会自动为我们配置相关的依赖和配置。这使得开发人员可以更加关注业务逻辑的实现;现在我们来学习一下它的原理,以便后面能更清晰地实现。

        二. 🦁 Spring-boot starter 原理实现分析

        2.1 自动配置原理

        在此之前,我们主要先来了解自动配置原理。

        1. 首先,我们可以把Springboot的启动流程简化成以下几步:

          Springboot启动流程

          在第3步加载处理所有配置类,其处理流程如下:

          在这里插入图片描述

          由上图可知道,加载配置类主要由两个注解完成,一个是@ComponentScan和@Import注解完成。

          其中,@ComponentScan其实就是@SpringbootApplication里面的注解之一,其作用是为了扫描其同级或者子包下的配置类(即与启动类同级或者子包下的配置类,这也是为啥我们做项目的时候,只需要导入一个starter就能实现某功能,其余工作都是Springboot帮我们干了),

          而 @Import 注解则在@EnableAutoConfiguration注解(其作用之一就是为了开启自动配置功能)里面,通过导入一个选择器ImportSelector的方式,提供了一种显式地从其它地方加载配置类的方式,这样可以避免使用性能较差的组件扫描(Component Scan)。

          那么以上哪种注解适合用来实现自动配置呢?

        无疑是使用导入选择器ImportSelector的@Import注解适合加载第三方jar包导入;

        回到 @SpringbootApplication 注解,其注解组成如下:

        在这里插入图片描述

        而@EnableAutoConfiguration则是开启自动配置的核心注解,它由以下注解组成:

        在这里插入图片描述

        它通过导入AutoConfigurationImportSelector.class来实现自动配置;

        而AutoConfigurationImportSelector类则是基于SpringFactories机制来实现的,现在来看一下它的主要源码:

        在这里插入图片描述

        getAutoConfigurationEntry(annotationMetadata)方法如下:

        在这里插入图片描述

        我们主要来看一下getCandidateConfigurations(annotationMetadata, attributes)方法:

        protected List getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
                List configurations = new ArrayList(SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader()));
                ImportCandidates.load(AutoConfiguration.class, this.getBeanClassLoader()).forEach(configurations::add);
                Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you are using a custom packaging, make sure that file is correct.");
                return configurations;
            }
        

        这个则是基于SpringFactories机制获得第三方jar包中所有自动配置类的方法。由代码可以知道,读取配置文件获取自动配置类时,使用的key是类EnableAutoConfiguration的全限定名。其主要流程如下:

        在这里插入图片描述

        最后总结一下:

        在这里插入图片描述

        这里狮子是学习了B站一个UP主的视频理解的,推荐给大家:码场安员外

        三. 🦁 操作实践

        3.1 项目场景

        前面狮子写了一篇《【SpringBoot】| 邮箱发送验证码,你会了吗?》深受伙伴们捧场,今天我们基于这个基础上再来封装一下spring-boot-starter-mail发送邮件类型的starter,方便后续使用。

        3.2 搭建项目

        我们先来搭建一个Springboot项目;根据Springboot starter的命名规范,属于Spring官方的就以spring-boot-starter-xxx的形式命名,其他技术自动整合Springboot的则按照xxx-spring-boot-starter命名。现在狮子起名为lion-email-spring-boot-starter,提高识别度(很规范(bushi),如下:

        在这里插入图片描述

        3.3 添加相关依赖

        先添加Lombok、spring-boot-starter-mail Spring Confguration Processor依赖(很重要,后面会体现它的价值);

        在这里插入图片描述

        3.4 删除一些不需要的东西

        1. 测试依赖

          在这里插入图片描述

        2. 打包插件

          在这里插入图片描述

        3. 启动类

          启动类也用不着,可以删了;

        3.5 发邮件工具类逻辑编写

        这种工具类写法比较固定,并不需要去记忆,自己积累一个就好。

        import lombok.AllArgsConstructor;
        import lombok.Data;
        import org.springframework.stereotype.Component;
        import javax.mail.*;
        import javax.mail.internet.InternetAddress;
        import javax.mail.internet.MimeMessage;
        import java.util.Properties;
        /**
         * 发邮件工具类
         */
        @Data
        @AllArgsConstructor
        public final class MailUtils {
            private String USER; // 发件人邮箱地址
            private String PASSWORD; // 如果是qq邮箱可以使户端授权码
            /**
             * 发送邮件
             * @param to 收件人邮箱
             * @param text 邮件正文
             * @param title 标题
             */
            public boolean sendMail(String to, String text, String title){
                try {
                    final Properties props = new Properties();
                    props.put("mail.smtp.auth", "true");
                    props.put("mail.smtp.host", "smtp.qq.com");
                    // 发件人的账号
                    props.put("mail.user", USER);
                    //发件人的密码
                    props.put("mail.password", PASSWORD);
                    // 构建授权信息,用于进行SMTP进行身份验证
                    Authenticator authenticator = new Authenticator() {
                        @Override
                        protected PasswordAuthentication getPasswordAuthentication() {
                            // 用户名、密码
                            String userName = props.getProperty("mail.user");
                            String password = props.getProperty("mail.password");
                            return new PasswordAuthentication(userName, password);
                        }
                    };
                    // 使用环境属性和授权信息,创建邮件会话
                    Session mailSession = Session.getInstance(props, authenticator);
                    // 创建邮件消息
                    MimeMessage message = new MimeMessage(mailSession);
                    // 设置发件人
                    String username = props.getProperty("mail.user");
                    InternetAddress form = new InternetAddress(username);
                    message.setFrom(form);
                    // 设置收件人
                    InternetAddress toAddress = new InternetAddress(to);
                    message.setRecipient(Message.RecipientType.TO, toAddress);
                    // 设置邮件标题
                    message.setSubject(title);
                    // 设置邮件的内容体
                    message.setContent(text, "text/html;charset=UTF-8");
                    // 发送邮件
                    Transport.send(message);
                    return true;
                }catch (Exception e){
                    e.printStackTrace();
                }
                return false;
            }
        }
        

        3.6 创建相关配置类

        创建LionEmailConfig配置类,在这里面干两个事:

        一是在配置类里实例化MailUtils类,并将邮箱地址以及授权码返回给mailUtils;

        二是配置参数:一般配置参数都是在Spring Boot 的application.yml中。我们会定义一个前缀标识来作为名称空间隔离各个组件的参数。对应的组件会定义一个XXXProperties 来自动装配这些参数。自动装配的机制基于@ConfigurationProperties注解,请注意一定要显式声明你配置的前缀标识(prefix)。

        这里需要添加几个注解,如下:

        1. @Configuration:在这里进行自动配置的工作。可以使用条件注解(@ConditionalOnClass、@ConditionalOnProperty 等)来根据情况决定是否应用自动配置。
        2. @ConfigurationProperties(“lion.email”):用于将外部配置属性绑定到 Spring Boot 应用程序中的 Java 对象上。这里加了一个lion.email前缀,则表示在配置文件(例如yaml文件)中,lion.email前缀下的字段值都会加载到Java对象中。
        import com.lion.emailstarter.utils.MailUtils;
        import lombok.Data;
        import org.springframework.boot.context.properties.ConfigurationProperties;
        import org.springframework.context.annotation.ComponentScan;
        import org.springframework.context.annotation.Configuration;
        @Configuration
        @ConfigurationProperties("lion.email")
        @ComponentScan
        @Data
        public class LionEmailConfig {
            private String user = "2373489842@qq.com"; // 发件人邮箱地址
            private String password = "abc-kpi"; // 如果是qq邮箱可以使户端授权码
        	@Bean
            public MailUtils mailUtils(){
                return new MailUtils(user,password);
            }
        }
        

        3.7 创建 Spring.factories 文件

        1. 在 src/main/resources 目录下,创建一个名为 META-INF/spring.factories 的文件。

          在这里插入图片描述

        2. 文件里面的内容为(写法很单一,cv即可):
        # spring boot starter
        org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.lion.emailstarter.LionEmailConfig
        

        3.8 目录结构展示

        在这里插入图片描述

        3.9 打包

        如下:

        在这里插入图片描述

        在这里插入图片描述

        显示成功则说明该starter已经打包到本地的版本库中,starter编写完成。

        四. 🦁 测试使用

        随便找一个SpringBoot项目,

        1. 导入刚刚创建好的lion-email-spring-boot-starter依赖
          
             com.lion
             lion-email-spring-boot-starter
             0.0.1-SNAPSHOT
        
        
        1. 参数编写

          我们在yaml文件编写相关参数:

          当我们输入lion的时候就会弹出相关提示,这是因为前面3.3节我们添加了Spring Confguration Processor的缘故,自动生成配置的代码提示。

        2. 测试
        @SpringBootTest
        class LionTelecomsApplicationTests {
            @Autowired
            private MailUtils mailUtils;
            @Test
            void contextLoads() {
                mailUtils.sendMail("2373489842@qq.com","有内鬼, 终止交易!","测试starter");
            }
        }
        
        1. 测试结果

          在这里插入图片描述

        五. 🦁 总结

        这个技能对你有用么??有用点个赞,咱们下期见!


        在这里插入图片描述

        🦁 其它优质专栏推荐 🦁

        🌟《Java核心系列(修炼内功,无上心法)》: 主要是JDK源码的核心讲解,几乎每篇文章都过万字,让你详细掌握每一个知识点!

        🌟 《SpringBoot 源码剥析核心系列》:一些场景的Springboot源码剥析以及常用Springboot相关知识点解读

        欢迎加入狮子的社区:『Lion-编程进阶之路』,日常收录优质好文

        更多文章可持续关注上方🦁的博客,2023咱们顶峰相见!