xml文件的动态化配置,导入

1 背景

由于项目需要,得在通用框架中引入sdk,切面实现数据上报相关的功能,为最小化修改范围和影响,避免其他未用到改sdk的服务的启动、加载时间,实现了xml文件的动态化导入,满足条件才会加载。

服务是springboot项目,rpc接口。

2 实现

基于configuration、conditional,import,importResource注解,和thrift的interceptor实现。

  1. 实现Condition接口的matches(ConditionContext context, AnnotatedTypeMetadata metadata)方法,写一个条件类(conditional注解),满足该类的条件时才会执行xml的加载操作。
  2. 实现一个子配置类,importResource导入xml文件和相关bean
  3. 在主配置类Import子配置类,启动类import主配置类实现xml的动态带入和interceptor的动态注入

示例

java 复制代码
// 条件类
public class XXEnabledCondition implements Condition {
    private static final Logger LOGGER = LoggerFactory.getLogger(XXEnabledCondition.class);
    
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        try {
            boolean isEnabled = XXDebugConfig.isEnabled();
            LOGGER.info("XX Debug Condition Check: XX.debug.enable={}, condition={}", isEnabled, isEnabled);
            return isEnabled;
        } catch (Exception e) {
            LOGGER.warn("Failed to check XX Debug condition, XX Debug disabled", e);
            return false;
        }
    }
}
//子配置类
@Configuration
@Conditional(XXEnabledCondition.class)
@ImportResource(locations = {"classpath:XX-client.xml"})
public class XXClientConfiguration {
    private static final Logger LOGGER = LoggerFactory.getLogger(XXClientConfiguration.class);

    public XXClientConfiguration() {
        LOGGER.info("XXClientConfiguration initialized - XX Debug is enabled");
    }
}
//主配置类和子配置类一样的做法,就不贴了

3 扩展知识

conditional注解&condition接口

conditional注解是spring4.0引入的条件化bean注册注解,底层依赖Condition接口的match方法。

应用场景:

  • 根据文件 或 配置 差异定制化注册bean
  • 根据某个类是否存在判断是否注册bean

springboot基于conditional注解加了派生类:

  • @ConditionalOnProperty

  • @ConditionalOnClass

  • @ConditionalOnMissingBean

  • 等20+条件注解

注意事项

  1. 条件判断时机:发生在Bean定义阶段,早于Bean实例化

  2. 优先级问题@Conditional的优先级高于@Profile

  3. 避免循环依赖:条件判断中不要直接获取Bean实例

  4. 适用范围: 可以加在类 或 方法

  5. 调试技巧 :通过-Ddebug查看条件评估报告(Spring Boot)

高级用法见:https://blog.csdn.net/qq_62775328/article/details/145433841?ops_request_misc=elastic_search_misc&request_id=5bea71484c011adc0a57cdba124617f8&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-145433841-null-null.142^v102^pc_search_result_base8&utm_term=conditional%E6%B3%A8%E8%A7%A3&spm=1018.2226.3001.4187

configuration注解

核心作用:将 java类 转为spring配置类,保存在spring容器中,被统一管理。

高级用法:

  1. 模块化配置:@configuration + @import注解,不同模块分开配置。
  2. 条件化加载:利用@condition注解或springboot的@ConditionalOnProperty等注解
  3. 环境特定配置:结合@profile注解

注解参数:

  • proxyBeanMethods:bean代理方式,默认true,通过CGLIB代理,耗时更长!但确保单例(如通过serviceA()方法注入,多次调用该方法返回同个bean);false 耗时更短,但不保证单例。

  • value:配置bean名字

spring容器加载流程

java 复制代码
┌─────────────────┐
│  Spring 容器启动  │
└─────────┬───────┘
          │
          ▼
┌─────────────────┐
│ 扫描 @Configuration 类 │
└─────────┬───────┘
          │
          ▼
┌─────────────────┐
│  创建配置类实例   │
└─────────┬───────┘
          │
          ▼
┌─────────────────┐
│   处理 @Bean 方法  │
└─────────┬───────┘
          │
          ▼
┌─────────────────┐
│ proxyBeanMethods? │
└─────┬───────┬───┘
      │       │
      ▼       ▼
┌─────────┐ ┌─────────┐
│创建CGLIB│ │直接调用 │
│   代理   │ │  方法   │
└─────┬───┘ └─────┬───┘
      │           │
      └─────┬─────┘
            │
            ▼
┌─────────────────┐
│  注册 Bean 到容器 │
└─────────┬───────┘
          │
          ▼
┌─────────────────┐
│   处理依赖注入   │
└─────────┬───────┘
          │
          ▼
┌─────────────────┐
│    完成配置      │
└─────────────────┘

import注解

**作用:**把其他类拉进当前spring容器,解决bean扫不到的问题(如不在扫描路径下的第三方jar包的类,没加component等注解的普通类,想动态决定要不要引入的类)。

使用场景:

  1. 把普通类引入:这时类会被注入,spring会自动加载里面的各bean
  2. 导入配置类:把配置类里的bean导入
导入 "ImportSelector 接口实现类"------ 动态导入(高级用法)。
  1. 实现 ImportSelector 接口,在 selectImports 方法里返回要导入的类名数组
  2. 在配置类上 @Import 这个实现类

其实在被import的子配置上加condition注解也可实现3

importResource注解

**作用:**将xml配置加载到基于 Java 的到配置中,进而进入spring上下文中

@ImportResource支持各种 XML 配置文件的位置,包括:

  • 类路径classpath:beans.xml
  • 文件系统file:/path/to/beans.xml
  • URLhttp://example.com/beans.xml
相关推荐
BullSmall2 小时前
SEDA (Staged Event-Driven Architecture, 分阶段事件驱动架构
java·spring·架构
蓝眸少年CY3 小时前
(第七篇)spring cloud之Hystrix断路器
spring·spring cloud·hystrix
悟空码字4 小时前
SpringBoot集成Hera,分布式应用监控与追踪解决方案
java·springboot·编程技术·后端开发·hera
技术宅星云4 小时前
0x00.Spring AI Agent开发指南专栏简介
java·人工智能·spring
蓝眸少年CY5 小时前
(第八篇)spring cloud之zuul路由网关
后端·spring·spring cloud
long3165 小时前
弗洛伊德·沃肖算法 Floyd Warshall Algorithm
java·后端·算法·spring·springboot·图论
吴声子夜歌6 小时前
Maven——pom.xml详解
xml·java·maven
IT 行者6 小时前
深入理解 OAuth2/OIDC 中的 Issuer:身份认证的基石
spring
那我掉的头发算什么7 小时前
【SpringBoot】从创建第一个spring项目开始
spring boot·后端·spring