使用场景:解决spring中的循环依赖问题
如:A 依赖 B ,B 依赖 A .此时若使用@Autowired注入对象则会出现循环依赖导致项目启动失败。
这时,不如换个方向,即不通过注入的方式去获取对象,在需要对象时直接中从Spring容器中获取使用,就可以避免循环依赖的问题
以下为自己封装好的工具库,用于从Spring容器中获取对象
/**
* spring应用工具类
* 可以获取spring容器中的bean实例以及环境变量信息
*
* @author ZSJ
* @date 2023/5/17 9:47
*/
@Component
public class ElinkApplicationUtil implements ApplicationContextAware, EnvironmentAware {
private static ApplicationContext applicationContext;
private static Environment environment;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ElinkApplicationUtil.applicationContext = applicationContext;
}
@Override
public void setEnvironment(Environment environment) {
ElinkApplicationUtil.environment = environment;
}
/**
* 根据bean的类型从spring容器中获取bean实例
*
* @param clazz bean的类型
* @param <T>
* @return 指定类型的bean实例
*/
public static <T> T getBean(Class<T> clazz) {
return applicationContext.getBean(clazz);
}
/**
* 根据bean名称和bean的类型从spring容器中获取bean实例
*
* @param name bean的名称
* @param clazz bean的类型
* @param <T>
* @return 指定类型的bean实例
*/
public static <T> T getBean(String name, Class<T> clazz) {
return applicationContext.getBean(name, clazz);
}
/**
* 根据bean的名称从spring容器中获取bean实例
*
* @param beanName bean的名称
* @return
*/
public static Object getBean(String beanName) {
return applicationContext.getBean(beanName);
}
/**
* 判断spring容器中是否有指定bean名称的bean实例
*
* @param name bean的名称
* @return
*/
public static boolean containsBean(String name) {
return applicationContext.containsBean(name);
}
/**
* 根据bean名称从spring容器中获取bean名称对应实例的类型
*
* @param name bean的名称
* @return
* @throws NoSuchBeanDefinitionException
*/
public static Class<?> getType(String name) throws NoSuchBeanDefinitionException {
return applicationContext.getType(name);
}
/**
* 根据配置项key的名称获取对应的配置项的值
* 比如application.properties配置文件中有 url=www.baidu.com的配置,
* 则getProperty("url")的值就是www.baidu.com
*
* @param key 配置项的名称,比如url
* @return
*/
public static String getProperty(String key) {
return environment.getProperty(key);
}
/**
* 根据配置项key的名称获取配置项的值,并将值转换为指定的类型
* 比如application.properties配置文件中有age=18的配置项
* 因为age的值是个整数,所以我们可以直接通过本方法获取整数的age值
* getProperty("age",Integer.class)的结果就是整数18
*
* @param key 配置项的名称
* @param targetType 配置项对应的值的类型
* @param <T>
* @return 指定类型的配置项的值
*/
public static <T> T getProperty(String key, Class<T> targetType) {
return environment.getProperty(key, targetType);
}
}
使用真实场景业务代码:
业务场景 :
我在DevFillingTableServiceImpl中注入了 GoodsArchivesService ,用来调用商品中的api方法
同时,我又想在IGoodsArchivesService 的实现类中调用 IDevFillingTableService 的api方法,这时就会有循环依赖,导致服务启动失败。
public interface IDevFillingTableService extends IService<DevFillingTableEntity> {
/**
* 根据款ID新增充绒表
* @param goodId 款ID
* @return 是否成功 true:成功 false:不成功
*/
Boolean addFilling(Long goodId);
}
@Service
@Slf4j
public class DevFillingTableServiceImpl extends ServiceImpl<DevFillingTableDao, DevFillingTableEntity> implements IDevFillingTableService {
@Autowired
private GoodsArchivesService goodsArchivesService;
}
public interface IGoodsArchivesService {
void addGoodsArchives(GoodsArchivesAddDTO dto);
}
重点代码:上文中已经在DevFillingTableServiceImpl 中注入GoodsArchivesService ,
这时如果在GoodsArchivesServiceImpl 中也注入DevFillingTableService就会出现循环依赖。
我可以不注入依赖,在使用的时候从spring容器中获取到DevFillingTableService去使用
@Service
@Slf4j
public class GoodsArchivesServiceImpl extends ServiceImpl<GoodsArchivesDao, GoodsArchivesEntity> implements IGoodsArchivesService {
//这样注入会导致循环依赖
//@Autowired
//private IDevFillingTableService devFillingTableService;
@Override
public void addGoodsArchivesInner(GoodsArchivesAddInnerDTO dto) {
//使用的时候从spring容器中获取,避免循环依赖
IDevFillingTableService bean = ElinkApplicationUtil.getBean(IDevFillingTableService.class);
bean.addFilling();
}
}