一个接口多个实现类,如何调用哪个实现类的方法
扯淡
最近在做某“马店”项目中的报表,定时任务(更新报表数据)实现类中使用 @Autowired 注入每张报表的逻辑类。随着报表的增多,@Autowired 越来越多。记录一次使用 ApplicationContextAware 优化的过程。
个人学习总结:
链接:【Java基础、springboot、springcloud、docker 等,学习目录】
优化前部分代码:
@Slf4j
@Component
public class ScheduleBox {
@Autowired
private DynamicReporterTask dynamicReporterTask;
@Autowired
private UnitUserWaterTask unitUserWaterTask;
@Autowired
private AcceptPeriodStatisticsTask acceptPeriodStatisticsTask;
/* 动态配置报表 */
//@DistributedLock(lockedKey = "DynamicReporterLock", expireTime = 30)
@Scheduled(cron = "0/10 * * * * ?")
public void dynamicReporter() {
dynamicReporterTask.handle();
}
/* 用户登记周期统计表 */
// @DistributedLock(lockedKey = "AcceptPeriodStatisticsLock", expireTime = 30)
@Scheduled(cron = "0/10 * * * * ?")
public void acceptPeriodStatistics() {
acceptPeriodStatisticsTask.handle();
}
/* 单位用户用水报表 */
//@DistributedLock(lockedKey = "UnitUserWaterTaskLock", expireTime = 30)
@Scheduled(cron = "0/10 * * * * ?")
public void unitUserWater() {
unitUserWaterTask.handle();
}
}
每张报表对应一个task,定时任务中使用 @Autowired 注入。后期报表增加,@Autowired 会越来越多。
优化过程:
主要思路: 提供一个公共的接口,每张报表实现该接口。定时任务从spring容器中获取到对应报表实现类的bean,并使用该公共接口接收。调用接口方法即可。
1、公共接口
/**
* 报表公共接口
*/
public interface BaseTask {
public void handle();
}
2、接口实现类
每张报表一个实现类,均实现 BaseTask 接口。
/**
* 动态配置报表
*/
@Slf4j
@Component
public class DynamicReporterTask implements BaseTask {
@Override
public void handle() {
log.info("+++动态报表处理逻辑");
}
}
/**
* 用户登记周期统计表
*/
@Slf4j
@Component
public class AcceptPeriodStatisticsTask implements BaseTask {
// @Async
@Override
public void handle() {
log.info("+++用户登记周期控制统计表处理逻辑");
}
}
/**
* 单位用户用水表
*/
@Slf4j
@Component
public class UnitUserWaterTask implements BaseTask {
// @Async
@Override
public void handle() {
log.info("+++单位用户用水报表处理逻辑");
}
}
3、调用:
获取 spring 容器中接口的具体实现 bean。使用 ApplicationContextAware 接口。
/**
* 定时任务集合
* 当一个类实现了接口 ApplicationContextAware 之后,这个类就可以获得 ApplicationContext 中的所有 bean
*/
@Slf4j
@Component
public class ScheduleBox implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
/* 动态配置报表 */
//@DistributedLock(lockedKey = "DynamicReporterLock", expireTime = 30)
@Scheduled(cron = "0/10 * * * * ?")
public void dynamicReporter() { commonHandle("dynamicReporterTask"); }
/* 用户登记周期统计表 */
//@DistributedLock(lockedKey = "AcceptPeriodStatisticsLock", expireTime = 30)
@Scheduled(cron = "0/10 * * * * ?")
public void acceptPeriodStatistics() { commonHandle("acceptPeriodStatisticsTask"); }
/* 单位用户用水报表 */
//@DistributedLock(lockedKey = "UnitUserWaterTaskLock", expireTime = 30)
@Scheduled(cron = "0/10 * * * * ?")
public void unitUserWater() { commonHandle("unitUserWaterTask"); }
/**
* 公共处理方法
* @param bean BaseTask 接口实现类在 spring 容器中的名称
*/
private void commonHandle(String bean) {
BaseTask reporterTask = (BaseTask) applicationContext.getBean(bean);
reporterTask.handle();
}
}
ApplicationContextAware 接口:
spring 容器在初始化时,如果Spring配置文件中所定义的Bean实现了该接口,那么加载时会调用 setApplicationContext(ApplicationContext applicationContext) throws BeansException 方法,获得ApplicationContext对象。通过ApplicationContext对象就可以获取具体的实现类。
总结:
获取一个接口具体哪个实现类的方式
1、new 一个具体的接口实现类对象。
2、@Autowired 注入具体实现类。
3、使用 @Resource 注解指定实现类名称。
@Resource(name = "dynamicReporterTask")
private BaseTask baseTask;
4、@Qualifier 指定
@Autowired
@Qualifier("dynamicReporterTask")
private BaseTask baseTask;
5、ApplicationContextAware 接口。
问题:
项目常分 controller、service、dao 层。其中service层分“接口” 和 “Impl” 层,其中接口层有必要吗?
个人认为,当接口只有一个实现类的时时候,那么接口层就没必要了。service分两层有一个重要的原因,尼玛代码生成器已经帮我们把接口生成了。
本文地址:https://blog.csdn.net/cp026la/article/details/109580179
下一篇: ai怎么手绘卡通版本的乖巧女孩头像?