Hello, all 。这里请教一个 Spring 循环依赖的问题。
我定义了三个类:配置类 AppConfig 、业务类 AppBiz 、自动装载类 AppAutoConfiguration 。三个类的简化代码如下所示:
// AppConfig
@ConfigurationProperties(prefix="app")
public class AppConfig
{
private String version = “1.0.0”;
}
// AppBiz
public class AppBiz {
private final AppConfig config;
public AppBiz(AppConfig config){
this.config = config;
}
}
// AppAutoConfiguration
@EnableConfigurationProperties(AppConfig.class)
public class AppAutoConfiguraion{
@Resource
private AppConfig config;
@Bean
public AppBiz buildAppBiz(){
return new AppBiz(config);
}
}
当我将这个项目作为一个 jar 包提供给其他系统的时候,希望通过读取配置文件 app.version 自动装载,实现一些逻辑。
现在的情况是,我不在配置文件里写 app.version
时,项目可以正常启动,自动装配 AppAutoConfiguration ;当我在配置文件中加上 app.version
,自动装载配置类就报循环依赖的问题。提示是 AppBiz 和 AppConfig 循环依赖。
有大哥能看下上面的代码有什么问题吗。
2
BBCCBB 2023-07-11 20:51:37 +08:00
你这只有 AppBiz 依赖 appconfig, appconfig 也没有依赖 appBiz 呀.
|
4
ak1ak OP @BBCCBB #1 加上 `@Lazy` 才显示具体的循环依赖信息;不加 `@Lazy` 会提示「创建 AppAutoConfiguration Bean 失败,这个 Bean 中依赖的其他 Bean 正在创建,可能有没有解决的循环依赖 」:-(
|
5
ak1ak OP @zoharSoul #3 你的意思是将 AppBiz 改成一个 `@Component`,然后通过 `@Autowired` 的方式注入 AppConfig 吗。这个应该行不通,我这边想做的是通过在 AppAutoConfiguration 控制是否加载 AppBiz 。也就是 buildAppBiz 方法上会有 `@Conditional` 条件
|
7
ak1ak OP @retanoj #6 不行的。这个 AppAutoConfiguration 这个类要作为一个自动装配模块提供给其他系统调用,如果通过 `@Component` 进行标记,其他系统要通过 componentScan 扫描这个类路径,和自动装配的初衷不符。理想情况下是在其他系统通过配置文件,条件化地加载 AppAutoConfiguration 中的各个组件。
|
8
fulln 2023-07-12 10:17:25 +08:00
spring 当处理构造器注入 bean 的时候,会出现这种问题, 你试下成员变量用注解注入 bean
|
9
retanoj 2023-07-12 10:34:06 +08:00
@Configuration
@EnableConfigurationProperties(AppConfig.class) class AppAutoConfiguraion{} 使用方 @Autowired AppAutoConfiguraion appAutoConfiguraion; |
10
cppc 2023-07-12 10:57:48 +08:00
感觉遗漏了信息,上个 demo 看看
|
11
ak1ak OP @cppc #10 demo 代码在 https://pastebin.ubuntu.com/p/bcS3Kkq797/。使用的第三方库是 jasypt-spring-boot 。这个库的作用是读取一个 encryptablePropertyResolver 的 Bean 实例之后,通过判断配置的前缀是否是指定前缀,如果是,根据 EncryptablePropertyResolver#resolvePropertyValue 进行解析。(我感觉是这个依赖的问题,EncryptablePropertyResolver 依赖一个 AppConfig 的 Bean ,但是先要初始化一个 EncryptablePropertyResolver 的 Bean 来判断是否需要对 AppConfig 配置进行解密,因此出现了循环依赖。隐约感觉是这个问题,不知道怎么解决。
|
12
ediron 2023-07-12 12:21:23 +08:00
|
13
YCNQc647Cfngdp89 2023-07-12 12:57:42 +08:00
改成 buildAppBiz(AppConfig config),把 resource 注解的 bean 删掉
|
14
258 2023-07-12 13:22:04 +08:00
这个没有循环依赖呀
|
15
running17 2023-07-12 15:11:35 +08:00
单从代码看不出来有问题,建议把报错信息脱敏一下放上来看看
|
16
ak1ak OP @258 @running17 从这个代码的确看不出为什么会有循环依赖,所以可能就是 #11 分析的问题。
通过 `@Resource` field 注入提示的错误: ![setter 注入失败]( https://s3.bmp.ovh/imgs/2023/07/12/35f7b818c71647d5.png) 通过构造函数或者 `@Resource` + `@Lazy` 注入提示的错误: ![构造函数注入失败]( https://s3.bmp.ovh/imgs/2023/07/12/a8994322e6668044.png) |
17
wanghaoxu 2023-07-12 16:42:00 +08:00
简单调试了一下,循环依赖大概是这个问题
encryptablePropertyResolver 依赖 config config 依赖 application.properties 文件,application.properties 文件依赖你用的那个加解密组件, 加密组件又依赖 properties 文件 建议新建一个 xxx.propertiesconfig 文件,这里面写初始化加解密组件的配置,让 config 依赖 xxx.properties 文件(使用 @PropertySource("classpath:xxx.properties")指定配置文件),猜测 xxx.propertiesconfig 文件不会依赖那个加密文件,不会参与加解密,试了下没有循环依赖问题了,你可以试试 |
18
ak1ak OP @wanghaoxu 你这种方式我没有试过,不过理论上提供一个额外的 PropertySource 似乎和直接在 application.properties 中指定没有区别 (逃。我看了下 jasypt-spring-boot GitHub 上的文档中处理自身配置的说明,是根据一个 EncryptablePropertyFilter 实例来过滤掉特定配置避免循环依赖的问题的。所以我仿照它的写法,提供一个同名的 Bean ,然后用 `@Lazy` + 构造器注入的方式引入 AppConfig 类,问题解决。感谢各位的建议!( Peace~
|