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


  • 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 = https://www.isolves.com/it/cxkf/kj/2023-03-02/"true")@EnableAspectJAutoProxypublic class LogsAutoConfiguration {private static final Logger logger = LoggerFactory.getLogger(LogsAutoConfiguration.class) ;@Resourceprivate LogsProperties logsProperties ;@Beanpublic 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);@Overridepublic 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 = https://www.isolves.com/it/cxkf/kj/2023-03-02/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();}}


推荐阅读