0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Spring Boot Starter需要些什么

科技绿洲 来源:了不起 作者:了不起 2023-09-25 11:35 次阅读

前面我们简单介绍了如何使用消息中间件 Apache Pulsar ,但是在项目中那样使用,显然是不太好的,不管从易用性和扩展性来看,都是远远不够, 为了和springboot项目集成,写一个pulsar-spring-boot-starter是非常有必要的,在此之前,我们先看看一个starter需要些什么。

Spring Boot Starter

spring-boot的强大之处在于其提供的大量starter组件,基本涵盖了我们开发中的各个技术领域,比如数据库访问有jdbc、jpa,缓存有redis,全文检索有elasticsearch,消息队列有amqp、kafka等等。

在项目中你只需要按需引入相应的依赖 spring-boot-starter-xxx ,然后只需要替换对应的配置参数即可,就能快速使用对应的功能,不得不说简直是为开发者插上了翅膀。

命名风格

对于starter模块如何命名,spring官方是这样建议:

  • Spring官方命名格式为:spring-boot-starter-{name}
  • 非Spring官方建议命名格式:{name}-spring-boot-starter

准备工作

如果你之前有看过spring官方starter组件,你会发现主要是基于AutoConfigure及@Enable来实现的。

  • 其中AutoConfigure也就是我们常说的自动装配,在spring-boot-autoconfigure包中的目录/METE-INF/spring.factories对应文件中,你可以看到这样的配置:图片

当启动Spring Boot项目时这些配置都会被加载(这么多的配置全部加载并处理,难怪启动那么慢)。

在starter中依赖的具体实现包中,一般都会提供一个@Enable注解作为部分扩展功能的开关,我们可以在系统中通过该注解引入按需引入配置

图片

AutoConfigure配置的一定会被加载,而@Enable有开发者选择使用使用,当然有些组件是没有AutoConfigure,必须通过@Enable来启用

下面我们先对这块内容做个简单的认识,方便后续在写具体starter时知道怎么写以及为什么那样写。

AutoConfigure

在目录中创建src/main/resources/MATE-INF中创建文件spring.factories,定义SpringBoot应用启动时的需要注册的配置,这个主要是基于SPI机制来实现, 下面是当前spring-boot-autoconfigure中spring.factories文件的部分内容

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,
org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration,
...

配置在这里的带有@Configuration的类(如果没有被Conditional条件过滤掉)都会作为配置将相关Bean注册到Spring容器.

主要实现基于@SpringBootApplication注解上的注解@EnableAutoConfiguration

Enable

以Spring Aop相关的注解@EnableAspectJAutoProxy为例,我们看下 Spring官方是怎么使用@Enable注解来实现配置加载的:

@EnableAspectJAutoProxy

改注解除了一般注解的基础(@Target、@Retention)元素外,还包含了两个配置属性proxyTargetClass、exposeProxy以及一个@Import

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
    
 boolean proxyTargetClass() default false;
    
 boolean exposeProxy() default false;

}

@Import

在@Import中我们可以配置需要导入的配置类,有以下几个选择:

  • 直接导入@Configuration标识的类
  • 导入实现了接口ImportBeanDefinitionRegistrar的类,来向容器注册BeanDefinition
  • 导入实现了接口ImportSelector的类(不需要@Configuration)来选择配置
@Import(AspectJAutoProxyRegistrar.class)

ImportBeanDefinitionRegistrar

在上面@EnableAspectJAutoProxy注解上,通过@Import,引入了AspectJAutoProxyRegistrar,而该类又实现了接口ImportBeanDefinitionRegistrar, 该接口能够通过BeanDefinitionRegistry向Spring容器注册我们期望的BeanDefinition,看代码:

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
    
  @Override
  public void registerBeanDefinitions(
          AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

    AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

    AnnotationAttributes enableAspectJAutoProxy =
            AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
    if (enableAspectJAutoProxy != null) {
      if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
        AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
      }
      if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
        AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
      }
    }
  }
}

这里我们可以拿到@EnableAspectJAutoProxy的元数据以及对应的属性配置,这样就可以基于开发者的配置实现不同逻辑

ImportSelector

上面说到了,@Import还可以配置实现了ImportSelector接口的类,进而控制具体需要使用的Configuration,下面是@EnableAsync中@Import配置的类

public class AsyncConfigurationSelector extends AdviceModeImportSelector< EnableAsync > {

  private static final String ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME =
          "org.springframework.scheduling.aspectj.AspectJAsyncConfiguration";
  
  @Override
  @Nullable
  public String[] selectImports(AdviceMode adviceMode) {
    switch (adviceMode) {
      case PROXY:
        return new String[] {ProxyAsyncConfiguration.class.getName()};
      case ASPECTJ:
        return new String[] {ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME};
      default:
        return null;
    }
  }
}

ImportAware

同样和@Import配合使用,针对基于ImportSelector选择的Configuration,只要实现了ImportAware接口,就可以拿到@Import对应@Enable注解的元数据

@Configuration
public abstract class AbstractAsyncConfiguration implements ImportAware {
    
  @Override
  public void setImportMetadata(AnnotationMetadata importMetadata) {
    this.enableAsync = AnnotationAttributes.fromMap(
            importMetadata.getAnnotationAttributes(EnableAsync.class.getName(), false));
    if (this.enableAsync == null) {
      throw new IllegalArgumentException(
              "@EnableAsync is not present on importing class " + importMetadata.getClassName());
    }
  }
}

上面主要根据Spring源代码中的例子,了解@Enable、@Import、ImportBeanDefinitionRegistrar、ImportSelector、ImportAware如何搭配使用, 从而实现Spring的动态配置,用一张关系图表示:

图片
relation

其他扩展

spring-boot-configuration-processor

我们知道SpringBoot的配置我们都会写在application.yml(.properties)文件中,为了简化配置工作,如果能有智能提示就好了。这不,别人也想到了。只用这样做:

  1. 现在只需要在项目中引入依赖:
< dependency >
    < groupId >org.springframework.boot< /groupId >
    < artifactId >spring-boot-configuration-processor< /artifactId >
    < optional >true< /optional >
< /dependency >
  1. 定义一个Properties文件
@Data
@ConfigurationProperties(prefix = "myProp")
public class MyProperties {
  private Boolean enable;
  private String name;
}
  1. 在Configuration中导入
@Configuration
@EnableConfigurationProperties({MyProperties.class})
public class WebApiAutoConfiguration {
    
}
  1. 打包
mvn clean install
  1. 生产metadata.json 可以看到,在jar中的/META-INF目录下多了一个spring-configuration-metadata.json文件

@Conditional

实现spring bean的可插拔,我们可以基于属性、配置、类或者Bean来控制配置(@Configuration)是否生效,常见的有下面的这些:

  • ConditionalOnBean 容器存在Bean时配置有效
  • ConditionalOnClass classpath中有指定class时配置有效
  • ConditionalOnMissingBean 容器不存在Bean时配置有效
  • ConditionalOnMissingClass classpath中没有指定class时配置有效
  • ConditionalOnProperty 属性配置对应值成立时配置有效

AutoConfigure和@Enable

AutoConfigure是在spring.factories中配置了就会加载,但是可以通过@Conditional让配置中的Bean不生效;@Enable需要显示地使用才能有效,且先于AutoConfigure生效,从而可以配合@Conditional来阻断AutoConfigure的配置

结束语

关于Spring框架的学习后面会慢慢增多,我们会从原理到实践来介绍其功能,如果你有感兴趣的技术点或者开发中的问题,可以通过留言进行交流分享。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • SPI
    SPI
    +关注

    关注

    17

    文章

    1615

    浏览量

    89602
  • 缓存
    +关注

    关注

    1

    文章

    220

    浏览量

    26443
  • 数据库
    +关注

    关注

    7

    文章

    3591

    浏览量

    63371
  • spring
    +关注

    关注

    0

    文章

    332

    浏览量

    14161
  • Starter
    +关注

    关注

    0

    文章

    8

    浏览量

    7502
收藏 人收藏

    评论

    相关推荐

    Spring Boot如何实现异步任务

    上,用来告诉 Spring 这个方法是一个异步方法,Spring 会将这个方法的执行放在异步线程中进行。使用 @Async 注解需要满足以下条件: 需要
    的头像 发表于 09-30 10:32 488次阅读

    启动Spring Boot项目应用的三种方法

    ,从而使开发人员不再需要定义样板化的配置。用我的话来理解,就是spring boot其实不是什么新的框架,它默认配置了很多框架的使用方式,就像maven整合了所有的jar包,spring
    发表于 01-14 17:33

    Spring Boot使用Tomcat作为默认的嵌入式服务器

    默认情况下,Spring Boot使用Tomcat作为默认的嵌入式服务器,将其更改为Jetty,只需排除Tomcat并包含如下的Jetty即可:1. spring-boot-starter-webpom.xml org.spri
    发表于 12-15 08:59

    Spring Boot嵌入式Web容器原理是什么

    ,不需要配置任何特殊的XML配置,为了这个目标,Spring BootSpring 4.0框架之上提供了很多特性,帮助应用以“约定优于配置”“开箱即用”的方式来启动应用并运行上下文。
    发表于 12-16 07:57

    Spring Boot从零入门1 详述

    在开始学习Spring Boot之前,我之前从未接触过Spring相关的项目,Java基础还是几年前自学的,现在估计也忘得差不多了吧,写Spring
    的头像 发表于 12-10 22:18 418次阅读

    Spring认证」什么是Spring GraphQL?

    spring-boot-starter-web HTTP 春季MVC spring-boot-starter-websocket 网络结果 用于 Servlet 应用程序的 WebSocket
    的头像 发表于 08-10 14:08 611次阅读
    「<b class='flag-5'>Spring</b>认证」什么是<b class='flag-5'>Spring</b> GraphQL?

    学习Spring Boot 嵌入式服务器

    自官方文档使用其他Web服务器许多Spring Boot启动器都包含默认的嵌入式容器。对于servlet堆栈应用程序,spring-boot-starter-web包括Tomcatsprin...
    发表于 10-20 15:36 7次下载
    学习<b class='flag-5'>Spring</b> <b class='flag-5'>Boot</b> 嵌入式服务器

    Spring Boot特有的实践

    Spring Boot是最流行的用于开发微服务的Java框架。在本文中,我将与你分享自2016年以来我在专业开发中使用Spring Boot所采用的最佳实践。这些内容是基于我的个人经验
    的头像 发表于 09-29 10:24 644次阅读

    强大的Spring Boot 3.0要来了

    来源:OSC开源社区(ID:oschina2013) Spring Boot 3.0 首个 RC 已发布,此外还为两个分支发布了更新:2.7.5 2.6.13。 3.0.0-RC1: https
    的头像 发表于 10-31 11:17 1176次阅读

    Spring Boot Web相关的基础知识

    Boot的第一个接口。接下来将会将会介绍使用Spring Boot开发Web应用的相关内容,其主要包括使用spring-boot-starter-web组件来实现Web应用开发、UR
    的头像 发表于 03-17 15:03 461次阅读

    简述Spring Boot数据校验

    上一篇文章我们了解了Spring Boot Web相关的知识,初步了解了spring-boot-starter-web,还了解了@Contrler和@RestController的差别,如果
    的头像 发表于 03-17 15:07 547次阅读

    Spring Boot Actuator快速入门

    不知道大家在写 Spring Boot 项目的过程中,使用过 Spring Boot Actuator 吗?知道 Spring
    的头像 发表于 10-09 17:11 343次阅读

    Spring Boot启动 Eureka流程

    在上篇中已经说过了 Eureka-Server 本质上是一个 web 应用的项目,今天就来看看 Spring Boot 是怎么启动 Eureka 的。 Spring Boot 启动 E
    的头像 发表于 10-10 11:40 419次阅读
    <b class='flag-5'>Spring</b> <b class='flag-5'>Boot</b>启动 Eureka流程

    Spring Boot的启动原理

    可能很多初学者会比较困惑,Spring Boot 是如何做到将应用代码和所有的依赖打包成一个独立的 Jar 包,因为传统的 Java 项目打包成 Jar 包之后,需要通过 -classpath 属性
    的头像 发表于 10-13 11:44 370次阅读
    <b class='flag-5'>Spring</b> <b class='flag-5'>Boot</b>的启动原理

    Spring Boot 的设计目标

    什么是Spring Boot Spring BootSpring 开源组织下的一个子项目,也是 S
    的头像 发表于 10-13 14:56 312次阅读
    <b class='flag-5'>Spring</b> <b class='flag-5'>Boot</b> 的设计目标