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
相关推荐
Bingo_BIG1 天前
Java Spring框架:单表的查询、新增、修改、删除、导入、导出
java·spring·前后端
程序猿_极客1 天前
【免费】分享一套优质的基于SpringBoot的扶贫助农管理系统(详解)
java·springboot·课程设计·计算机项目
paopaokaka_luck1 天前
智慧社区综合服务小程序(人脸识别、AI问答、Echarts图形化分析)
前端·javascript·spring boot·spring·数据分析·echarts
牧瀬クリスだ1 天前
YAML配置详解:SpringBoot实战指南
java·spring·yml
需要8261 天前
JVM 内存区域与对象创建:一次 GC 从哪来
java·jvm·spring boot·spring·servlet·tomcat
paopaokaka_luck1 天前
考研政治刷题小程序(AI推荐题目、ECharts数据分析、章节练习与专项训练、模拟考试、错题本与收藏夹、学习打卡与目标管理、题库和组卷维护)
前端·javascript·spring boot·spring·数据分析·echarts
步行cgn2 天前
Spring 基于 XML 的自动装配:byType 详解
java·后端·spring
边境悍匪2 天前
蜗牛学苑 Java 智能体学习 Day46|贯穿项目 2 思维导图复盘
java·开发语言·vue.js·学习·spring
步行cgn2 天前
Spring c 命名空间注入详解
java·后端·spring
需要8262 天前
MySQL 索引 B+ 树与“查询为什么变慢了
java·spring boot·spring·spring cloud·tomcat