如何用ArchUnit检查禁止直接调用Spring Bean创建方法?
问题:通过ArchUnit禁止直接调用@Bean标注的方法
Spring支持通过标注@Bean的方法创建Bean,示例代码如下:
@Bean public DataSource springBatchDataSource() { SimpleDriverDataSource dataSource = new SimpleDriverDataSource(); // 省略其余初始化代码 return dataSource; }
该方法定义了名为springBatchDataSource的单例Bean,正常应通过@Autowired注入使用:
// 正确用法 @Autowired DataSource ds;
但团队里的初级同事常会错误地直接调用该方法创建对象:
// 错误用法 DataSource ds = springBatchDataSource();
这种做法会生成多个实例(而非预期的单例Bean),引发严重的应用问题。因此希望添加ArchUnit检查来禁止这类调用。目前找到了callMethodWhere方法和areAnnotatedWith(Bean.class)断言,但不知道如何组合使用,请问代码片段中的???应替换为什么?
@ArchTest void checkNoCallToBeanCreators(JavaClasses classes) { ArchRule rule = noClasses() .should().callMethodWhere(???.areAnnotatedWith(Bean.class)); rule.check(classes); }
或者有没有更优雅直接的实现方式?
解决方案
1. 填充???的正确写法
你需要用target()来指代被调用的目标方法,所以???处应替换为target(),完整代码如下:
@ArchTest void checkNoCallToBeanCreators(JavaClasses classes) { ArchRule rule = noClasses() .should().callMethodWhere(target().areAnnotatedWith(Bean.class)); rule.check(classes); }
这段规则会扫描所有类,禁止它们调用任何被@Bean注解标注的方法。
2. 更严谨的优化写法
考虑到Spring允许@Configuration类内部调用@Bean方法来复用Bean实例(Spring会自动处理这类调用,确保返回单例),可以优化规则,只禁止外部类的非法调用:
@ArchTest void checkNoExternalCallToBeanCreators(JavaClasses classes) { ArchRule rule = noClasses() .that().areNotAnnotatedWith(Configuration.class) .should().callMethodWhere(target().areAnnotatedWith(Bean.class)); rule.check(classes); }
3. 语义更清晰的等价写法
你也可以使用methods()语法来定义规则,语义更直观,可读性更强:
@ArchTest void checkNoCallToBeanMethods(JavaClasses classes) { ArchRule rule = noClasses() .should().call(methods().that().areAnnotatedWith(Bean.class)); rule.check(classes); }
这段代码和第一种写法效果完全一致,但表达更直接。
内容的提问来源于stack exchange,提问作者mmo
相关产品推荐
相关产品推荐

