简单说下依赖问题
- Spring团队提倡使用基于构造方法的注入,在上个项目中我也把 @Autowired 注解大部分都换成了构造器。当然如果没有使用 lombok 的 RequiredArgsConstructor 注解,自己手动往构造器里添加参数确实挺麻烦。
- 在遇到循环依赖问题的时候,可以在出现循环的类上继承 SmartInitializingSingleton 接口,该接口的 afterSingletonsInstantiated 方法会在所有 bean 创建完后才会调用。
使用 SmartInitializingSingleton 解决循环依赖
public class ClassA {
private ClassB classB;
public ClassA(ClassB classB) {
this.classB = classB;
}
...
}
// 因为 ClassA 和 ClassB 互相依赖,所以 ClassB 在构造器里不注入 ClassA,
// 而是借助 SmartInitializingSingleton 的特性,在 ClassA 创建完后再注入到 ClassB 中。
public class ClassB implements SmartInitializingSingleton,
ApplicationContextAware {
private ClassA classA;
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
ClassB.applicationContext = applicationContext;
}
@Override
public void afterSingletonsInstantiated() {
classA = applicationContext.getBean(classA.class);
}
...
}
上面使用 SmartInitializingSingleton 的代码是很啰嗦,比如可以通过自定义接口的方式减少冗余代码。
public interface InitSupport {
void init(ApplicationContext applicationContext);
}
public Class ClassB implements InitSupport {
private ClassA classA;
@Override
public void init(ApplicationContext applicationContext) {
classA = applicationContext.getBean(classA.class);
}
...
}
// 获取所有继承 InitSupport 的 bean,然后调用这些 bean 的 init 方法初始。
// 还可以进一步新建个 RuntimeProvider 这样的接口类代替 ApplicationContext 去获取 bean 。
public Class InitSupportScanBean implements SmartInitializingSingleton,
ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
InitSupportScanBean.applicationContext = applicationContext;
}
@Override
public void afterSingletonsInstantiated() {
Map<String, InitSupport> beanMap = applicationContext
.getBeansOfType(InitSupport.class);
// 调用初始方法
beanMap.forEach((beanName, initSupport) -> {
initSupport.init(applicationContext);
});
}
}