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
相关推荐
NE_STOP2 天前
springMVC-HTTP消息转换器与文件上传、下载、异常处理
spring
JavaGuide3 天前
Claude Opus 4.6 真的用不起了!我换成了国产 M2.5,实测真香!!
java·spring·ai·claude code
玹外之音3 天前
Spring AI MCP 实战:将你的服务升级为 AI 可调用的智能工具
spring·ai编程
来一斤小鲜肉3 天前
Spring AI入门:第一个AI应用跑起来
spring·ai编程
NE_STOP3 天前
springMVC-常见视图组件与RESTFul编程风格
spring
what丶k4 天前
Spring AI 多模态开发全解析:从入门到企业级落地
后端·spring·ai编程
NE_STOP4 天前
springMVC-获取前端请求的数据与三个作用域
spring
莫寒清4 天前
Spring MVC:@PathVariable 注解详解
java·spring·mvc
-大头.4 天前
从 0 开始理解 Spring 的核心思想 —— IoC 和 DI(1)
spring
前网易架构师-高司机4 天前
带标注的驾驶员安全带识别数据集,识别率99.5%,可识别有无系安全带,支持yolo,coco json,pascal voc xml格式
xml·yolo·数据集·交通·安全带