欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

一个接口多个实现类,如何调用哪个实现类的方法

程序员文章站 2022-12-20 21:33:33
扯淡最近在做某“马店”项目中的报表,定时任务(更新报表数据)实现类中使用 @Autowired 注入每张报表的逻辑类。随着报表的增多,@Autowired 越来越多。记录一次使用 ApplicationContextAware 优化的过程。学习总结:链接:【Java基础、springboot、springcloud、docker 等,学习目录】前期代码:@Slf4j@Componentpublic class ScheduleBox { @Autowired privat...

扯淡

最近在做某“马店”项目中的报表,定时任务(更新报表数据)实现类中使用 @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

相关标签: 随笔