您当前的位置:首页 > 电脑百科 > 程序开发 > 框架

SpringBoot自定义自动配置这些知识点你需要了解

时间:2023-03-02 14:44:26  来源:  作者:Springboot实战案例锦集
如果使用@ConditionalOnClass或@ConditionalOnMissingClass作为元注释的一部分来组合自己的组合注释,则必须使用name,因为在这种情况下引用类不会被处理。

理解自动配置bean

在底层,自动配置是用标准的@Configuration类实现的。附加的@Conditional注释用于约束何时应用自动配置。通常,自动配置类使用@ConditionalOnClass和@ConditionalOnMissingBean注释。这确保了自动配置仅在找到相关类且尚未声明自己的@configuration时适用。

你可以浏览spring-boot-autoconfigure的源代码,以查看Spring提供的@Configuration类(参见META-INF/spring.factories 文件)。

定位候选自动配置

Spring Boot检查是否存在META-INF/spring.factories文件在你发布的jar中。该文件应该在EnableAutoConfiguration为key下列出你的配置类,如下例所示:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=
com.pack.bus.autoconfigure.BusAutoConfiguration,
com.pack.bus.autoconfigure.BusWebAutoConfiguration

自动配置只能以这种方式加载。确保它们是在特定的包空间中定义的,并且它们永远不是组件扫描的目标。此外,自动配置类不应该允许组件扫描来查找其他组件。应该使用特定的@Imports。

如果你的配置需要按特定顺序应用,你可以使用@AutoConfigureAfter或@AutoConfigureBefore注释。例如,如果你提供了特定于web的配置,你的类可能需要应用在WebMvcAutoConfiguration之后。

可以使用@AutoConfigureOrder。该注释具有与常规@Order注释相同的语义,但为自动配置类提供了专用的顺序。

与标准的@Configuration类一样,自动配置类的应用顺序只影响其bean定义的顺序。随后创建这些bean的顺序不受影响,由每个bean的依赖关系和@DependsOn关系决定。

条件注释

你几乎总是希望在自动配置类中包含一个或多个@Conditional注解。@ConditionalOnMissingBean注解是一个常见的例子,它允许开发人员在对默认值不满足时覆盖自动配置。

Spring Boot包含很多@Conditional注解,你可以在自己的代码中重用这些注解,方法是注解@Configuration类或单独的@Bean方法。这些注释包括:

  • Class Conditions

@ConditionalOnClass和@ConditionalOnMissingClass注解让@Configuration类根据特定类的存在与否被包含。由于注释元数据是通过ASM解析的,因此你可以使用value属性来引用真正的类,即使这个类可能实际上没有出现在正在运行的应用程序类路径中。如果想用字符串指定类名,也可以使用name属性。

这种机制不适用于@Bean方法,因为@Bean方法的返回类型通常是条件的目标:在方法的条件应用之前,JVM将加载类并可能处理方法引用,如果类不存在,则这些引用将失败。

为了处理这种情况,可以使用一个单独的@Configuration类来隔离这种情况,如下面的例子所示:

@Configuration(proxyBeanMethods = false)
// Some conditions ...
public class MyAutoConfiguration {
  // Auto-configured beans ...
  @Configuration(proxyBeanMethods = false)
  @ConditionalOnClass(SomeService.class)
  public static class SomeServiceConfiguration {
    @Bean
    @ConditionalOnMissingBean
    public SomeService someService() {
      return new SomeService();
    }


  }
}

如果使用@ConditionalOnClass或@ConditionalOnMissingClass作为元注释的一部分来组合自己的组合注释,则必须使用name,因为在这种情况下引用类不会被处理。

  • Bean Conditions

@ConditionalOnBean和@ConditionalOnMissingBean注解让一个bean根据特定bean的存在与否被包含进来。可以使用value属性按类型指定bean,也可以使用name指定bean。search属性允许您限制在搜索bean时应该考虑的ApplicationContext层次结构。

当放在@Bean方法上时,目标类型默认为方法的返回类型,如下面的例子所示:

@Configuration(proxyBeanMethods = false)
public class MyAutoConfiguration {


  @Bean
  @ConditionalOnMissingBean
  public SomeService someService() {
    return new SomeService();
  }
}
  • Property Conditions

@ConditionalOnProperty注解让配置基于Spring环境属性包含。使用prefix和name属性指定要检查的属性。默认情况下,匹配任何存在且不等于false的属性。你还可以使用havingValue和matchIfMissing属性来创建更高级的检查。

  • Resource Conditions

@ConditionalOnResource注解让配置只在特定资源存在时才包含。可以使用常用的Spring约定来指定资源,如下面的例子所示。

  • Web Application Conditions

@ConditionalOnWebApplication和@ConditionalOnNotWebApplication注解让应用程序根据是否是“web应用程序”来包含配置。基于servlet的web应用程序是任何使用Spring WebApplicationContext、定义会话范围或具有ConfigurableWebEnvironment的应用程序。任何使用ReactiveWebApplicationContext或者ConfigurableReactiveWebEnvironment的应用都可以被称为响应式web应用。

@ConditionalOnWarDeployment注解根据应用程序是否是部署到容器中的传统WAR应用程序来包含配置。此条件不适用于与嵌入式服务器一起运行的应用程序。

  • SpEL Expression Conditions

@ConditionalOnExpression注解让配置基于SpEL表达式的结果包含。

创建自己的Starter

  • 命名

你应该确保为你的starter程序提供适当的命名空间。即使你用了不同的Maven groupId,也不要用spring-boot来启动模块名。我们可能会在未来为你的自动配置提供官方支持。

根据经验,你应该在starter之后命名一个组合模块。例如,假设你正在为“acme”创建一个starter程序,并且你将自动配置模块命名为acme-spring-boot,而starter程序命名为acme-spring-boot-starter。如果只有一个模块组合了这两个模块,请将其命名为acme-spring-boot-starter。

  • 配置key

如果starter提供了配置key,它们使用唯一的命名空间。不要把key放在Spring Boot使用的命名空间中(比如server、management、Spring等)。

为每个属性添加JAVAdoc,确保配置项有文档记录,如下面的例子所示。

@ConfigurationProperties("acme")
public class AcmeProperties {


  /**
   * Whether to check the location of acme resources.
   */
  private boolean checkLocation = true;
  /**
   * Timeout for establishing a connection to the acme server.
   */
  private Duration loginTimeout = Duration.ofSeconds(3);
}
  • 完整示例

本示例主要功能是实现日志记录功能

自动配置类

@Configuration
@EnableConfigurationProperties(LogsProperties.class)
@ConditionalOnProperty(prefix = "logs", name = "enabled", havingValue = "true")
@EnableAspectJAutoProxy
public class LogsAutoConfiguration {
  
  private static final Logger logger = LoggerFactory.getLogger(LogsAutoConfiguration.class) ;
  
  @Resource
  private LogsProperties logsProperties ;
  
  @Bean
  public AspectJExpressionPointcutAdvisor logAdvisor() {
    AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor() ;
    logger.info("执行表达式:{}", logsProperties.getPointcut()) ;
    advisor.setExpression(logsProperties.getPointcut()) ;
    advisor.setAdvice(new SystemAroundOperator()) ;
    return advisor ;
  }
}

自定义注解

@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface SystemLog {
  
  /**
   * <p>操作说明</p>
   * @return
  */
  String value() default "" ;
}

属性key配置

/**
 *   日志功能属性配置
 *   @author xg
 */
@ConfigurationProperties(prefix = "logs")
public class LogsProperties {
  /**
   *   切入点定义<br/>
   *    示例:execution(public * com.pack.controller.*.*(..))
   */
  private String pointcut ;
  /**
   *   是否开启日志功能
   */
  private boolean enabled = true ;
}

Advice定义

public class SystemAroundOperator implements MethodInterceptor {


  private static final Logger logger = LoggerFactory.getLogger(SystemAroundOperator.class);


  @Override
  public Object invoke(MethodInvocation invocation) throws Throwable {
    // 开始执行时间
    long start = System.currentTimeMillis();
    Method method = invocation.getMethod() ;
    SystemLog annoLog = null ;
    if (method.isAnnotationPresent(SystemLog.class)) {
      annoLog = method.getAnnotation(SystemLog.class) ;
      String value = annoLog.value() ;
      try {
        Object result = invocation.proceed() ;
        // 方法执行时间
        Long execTime = System.currentTimeMillis() - start ;
        logger.info("{}, 业务执行时间:{} ms", value, execTime) ;
        return result ;
      } catch (Throwable t) {
        Long execTime = System.currentTimeMillis() - start ;
        logger.info("{}, 业务执行时间:{} ms,发生异常信息:{}", value, execTime, t.getMessage()) ;
        throw t ;
      }
    }
    return invocation.proceed();
  }
}

配置META-INFspring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=
com.pack.config.LogsAutoConfiguration

以上就实现自定义starter的流程。



Tags:SpringBoot   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
详解基于SpringBoot的WebSocket应用开发
在现代Web应用中,实时交互和数据推送的需求日益增长。WebSocket协议作为一种全双工通信协议,允许服务端与客户端之间建立持久性的连接,实现实时、双向的数据传输,极大地提升了用...【详细内容】
2024-01-30  Search: SpringBoot  点击:(17)  评论:(0)  加入收藏
SpringBoot如何实现缓存预热?
缓存预热是指在 Spring Boot 项目启动时,预先将数据加载到缓存系统(如 Redis)中的一种机制。那么问题来了,在 Spring Boot 项目启动之后,在什么时候?在哪里可以将数据加载到缓存系...【详细内容】
2024-01-19  Search: SpringBoot  点击:(86)  评论:(0)  加入收藏
SpringBoot3+Vue3 开发高并发秒杀抢购系统
开发高并发秒杀抢购系统:使用SpringBoot3+Vue3的实践之旅随着互联网技术的发展,电商行业对秒杀抢购系统的需求越来越高。为了满足这种高并发、高流量的场景,我们决定使用Spring...【详细内容】
2024-01-14  Search: SpringBoot  点击:(91)  评论:(0)  加入收藏
公司用了六年的 SpringBoot 项目部署方案,稳得一批!
本篇和大家分享的是springboot打包并结合shell脚本命令部署,重点在分享一个shell程序启动工具,希望能便利工作。 profiles指定不同环境的配置 maven-assembly-plugin打发布压...【详细内容】
2024-01-10  Search: SpringBoot  点击:(163)  评论:(0)  加入收藏
简易版的SpringBoot是如何实现的!!!
SpringBoot作为目前最流行的框架之一,同时是每个程序员必须掌握的知识,其提供了丰富的功能模块和开箱即用的特性,极大地提高了开发效率和降低了学习成本,使得开发人员能够更专注...【详细内容】
2023-12-29  Search: SpringBoot  点击:(135)  评论:(0)  加入收藏
用 SpringBoot+Redis 解决海量重复提交问题
前言 一:搭建redis的服务Api 二:自定义注解AutoIdempotent 三:token创建和检验 四:拦截器的配置 五:测试用例 六:总结前言:在实际的开发项目中,一个对外暴露的接口往往会面临很多...【详细内容】
2023-12-20  Search: SpringBoot  点击:(53)  评论:(0)  加入收藏
SpringBoot中如何优雅地个性化定制Jackson
当使用 JSON 格式时,Spring Boot 将使用ObjectMapper实例来序列化响应和反序列化请求。在本教程中,我们将了解配置序列化和反序列化选项的最常用方法。一、默认配置默认情况下...【详细内容】
2023-12-20  Search: SpringBoot  点击:(132)  评论:(0)  加入收藏
springboot-如何集成Validation进行参数校验
一、步骤概览 二、步骤说明1.引入依赖包在 pom.xml 文件中引入 validation 组件,它提供了在 Spring Boot 应用程序中进行参数校验的支持。<!-- WEB 程序依赖包 --><dependen...【详细内容】
2023-12-13  Search: SpringBoot  点击:(157)  评论:(0)  加入收藏
优雅的springboot参数校验,你学会了吗?
前言在后端的接口开发过程,实际上每一个接口都或多或少有不同规则的参数校验,有一些是基础校验,如非空校验、长度校验、大小校验、格式校验;也有一些校验是业务校验,如学号不能重...【详细内容】
2023-11-29  Search: SpringBoot  点击:(200)  评论:(0)  加入收藏
Springboot扩展点之BeanDefinitionRegistryPostProcessor,你学会了吗?
前言通过这篇文章来大家分享一下,另外一个Springboot的扩展点BeanDefinitionRegistryPostProcessor,一般称这类扩展点为容器级后置处理器,另外一类是Bean级的后置处理器;容器级...【详细内容】
2023-11-27  Search: SpringBoot  点击:(175)  评论:(0)  加入收藏
▌简易百科推荐
Web Components实践:如何搭建一个框架无关的AI组件库
一、让人又爱又恨的Web ComponentsWeb Components是一种用于构建可重用的Web元素的技术。它允许开发者创建自定义的HTML元素,这些元素可以在不同的Web应用程序中重复使用,并且...【详细内容】
2024-04-03  京东云开发者    Tags:Web Components   点击:(8)  评论:(0)  加入收藏
Kubernetes 集群 CPU 使用率只有 13% :这下大家该知道如何省钱了
作者 | THE STACK译者 | 刘雅梦策划 | Tina根据 CAST AI 对 4000 个 Kubernetes 集群的分析,Kubernetes 集群通常只使用 13% 的 CPU 和平均 20% 的内存,这表明存在严重的过度...【详细内容】
2024-03-08  InfoQ    Tags:Kubernetes   点击:(12)  评论:(0)  加入收藏
Spring Security:保障应用安全的利器
SpringSecurity作为一个功能强大的安全框架,为Java应用程序提供了全面的安全保障,包括认证、授权、防护和集成等方面。本文将介绍SpringSecurity在这些方面的特性和优势,以及它...【详细内容】
2024-02-27  风舞凋零叶    Tags:Spring Security   点击:(54)  评论:(0)  加入收藏
五大跨平台桌面应用开发框架:Electron、Tauri、Flutter等
一、什么是跨平台桌面应用开发框架跨平台桌面应用开发框架是一种工具或框架,它允许开发者使用一种统一的代码库或语言来创建能够在多个操作系统上运行的桌面应用程序。传统上...【详细内容】
2024-02-26  贝格前端工场    Tags:框架   点击:(47)  评论:(0)  加入收藏
Spring Security权限控制框架使用指南
在常用的后台管理系统中,通常都会有访问权限控制的需求,用于限制不同人员对于接口的访问能力,如果用户不具备指定的权限,则不能访问某些接口。本文将用 waynboot-mall 项目举例...【详细内容】
2024-02-19  程序员wayn  微信公众号  Tags:Spring   点击:(39)  评论:(0)  加入收藏
开发者的Kubernetes懒人指南
你可以将本文作为开发者快速了解 Kubernetes 的指南。从基础知识到更高级的主题,如 Helm Chart,以及所有这些如何影响你作为开发者。译自Kubernetes for Lazy Developers。作...【详细内容】
2024-02-01  云云众生s  微信公众号  Tags:Kubernetes   点击:(50)  评论:(0)  加入收藏
链世界:一种简单而有效的人类行为Agent模型强化学习框架
强化学习是一种机器学习的方法,它通过让智能体(Agent)与环境交互,从而学习如何选择最优的行动来最大化累积的奖励。强化学习在许多领域都有广泛的应用,例如游戏、机器人、自动驾...【详细内容】
2024-01-30  大噬元兽  微信公众号  Tags:框架   点击:(68)  评论:(0)  加入收藏
Spring实现Kafka重试Topic,真的太香了
概述Kafka的强大功能之一是每个分区都有一个Consumer的偏移值。该偏移值是消费者将读取的下一条消息的值。可以自动或手动增加该值。如果我们由于错误而无法处理消息并想重...【详细内容】
2024-01-26  HELLO程序员  微信公众号  Tags:Spring   点击:(86)  评论:(0)  加入收藏
SpringBoot如何实现缓存预热?
缓存预热是指在 Spring Boot 项目启动时,预先将数据加载到缓存系统(如 Redis)中的一种机制。那么问题来了,在 Spring Boot 项目启动之后,在什么时候?在哪里可以将数据加载到缓存系...【详细内容】
2024-01-19   Java中文社群  微信公众号  Tags:SpringBoot   点击:(86)  评论:(0)  加入收藏
花 15 分钟把 Express.js 搞明白,全栈没有那么难
Express 是老牌的 Node.js 框架,以简单和轻量著称,几行代码就可以启动一个 HTTP 服务器。市面上主流的 Node.js 框架,如 Egg.js、Nest.js 等都与 Express 息息相关。Express 框...【详细内容】
2024-01-16  程序员成功  微信公众号  Tags:Express.js   点击:(88)  评论:(0)  加入收藏
站内最新
站内热门
站内头条