好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

使用spring动态获取接口的不同实现类

spring动态获取接口的不同实现类

最近做项目,有个需求是和外部对接,从接口获取新闻数据,把数据和缓存中的数据对比,多了的添加到数据库,少了的删掉。

接口有两个,一开始我是在业务类里写了两个方法,代码太长,简单说就是两个部分:

?

1

2

3

4

5

6

7

8

9

public Object saveANews() {

     //1、获取A接口新闻列表

     //2、和缓存对比,存数据到数据库

}

 

public Object saveBNews() {

     //1、获取B新闻列表

     //2、和缓存对比,存数据到数据库

}

写完后我发现,因为操作的是数据库的同一张表,2的部分代码完全一模一样,只有1的部分不同,而1的部分其实就只有一行代码。。。

这必须得复用啊,而且是一个业务,也没必要分别用两个方法,于是我改成了这样:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

//业务接口实现方法

public Object saveNews(NewsUtilService service) {

     //1、获取接口新闻列表

     List<NewsVO> list = service.queryNews();

     //2、和缓存对比,存数据到数据库

}

 

//定义新闻数据接口

public interface NewsUtilService {

     List<NewsVO> queryNews();

}

 

//接口的两个实现类

@Service

public class ANewsDataServiceImpl implements NewsUtilService {

     @Autowired

     private NewsDataMapper newsDataMapper;

 

     @Override

     public List<NewsVO> queryNews(){

         //对接数据

     }

}

 

@Service

public class BNewsDataServiceImpl implements NewsUtilService {

     @Override

     public List<NewsVO> queryNews(){

         //对接数据

     }

}

 

//定义工厂类

@Service

public class NewsUtilServiceFactory {  

     /**

      *

      * Method Name:  getNewsUtilService

      * @param source

      * @return

      */

     public NewsUtilService getNewsUtilService(String source){

         switch (source){

             case "a" :

                 return new ANewsDataServiceImpl();

             case "b" :

                 return new BNewsDataServiceImpl();

             default :

                 return null ;

         }

     }

}

 

//控制层调用

@RestController

public class NewsDataController {

     @Resource

     private NewsDataService newsDataService;

    

     @Resource

     private NewsUtilServiceFactory factory;

 

     public Object getNewsData(){

         String[] sources = { "a" , "b" };

             for ( int i = 0 ; i < sources.length; i++) {

                 NewsUtilService newsUtilService = factory.getNewsUtilService(sources[i]);

                 newsDataService.saveNews(newsUtilService);

             }

     }

}

本来以为这就大工告成了,谁知道运行后控制台居然报错了:

经过一步步调试,总算发现了是什么问题:

其中一个实现类中注入的Mapper没有实例化,是null。

一开始我还以为是构造函数调用和注入的顺序问题,查了半天才明白不是,问题在这里:

使用new关键字实例化的对象不是被spring创建的,不归spring管,所以A类实现类中Mapper注入的注解根本不生效!

但是因为业务需要,那个mapper又需要用到,怎么办呢?

当时想到了两种解决办法

1、在接口的方法参数里加入mapper,把mapper作为参数传进去,但这实在太奇怪了,先不说B类实现类根本用不到mapper,而且一个接口定义出来后根本不管它的实现类吧,因为实现类的问题去改接口,,,似乎有点非呀。

于是决定用第二种,修改工厂类变成如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

//定义工厂类

@Service

public class NewsUtilServiceFactory {  

     @Autowired

     private ANewsDataServiceImpl aNewsDataServiceImpl;

     @Autowired

     private BNewsDataServiceImpl bNewsDataServiceImpl;

     public NewsUtilService getNewsUtilService(String source){

         switch (source){

             case "a" :

                 return aNewsDataServiceImpl;

             case "b" :

                 return bNewsDataServiceImpl;

             default :

                 return null ;

         }

     }

}

代码写出来自己都无语了,先把所有的实现类都实例化出来,在根据输入返回。这不是工厂模式,是商店模式吧。。。但是当时也想不到其他办法,就先这么写了,但一直觉得肯定有其他解决方案,直到今天有空,去查了一下,才发现自己都多low。。。

其实spring可以动态获取实现类的~~~

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

@Service

public class NewsUtilServiceFactory {  

     @Autowired

     private ApplicationContext applicationContext; 

     public NewsUtilService getNewsUtilService(String source){

         switch (source){

             case "web" :

                 return applicationContext.getBean(WebNewsDataServiceImpl. class );

             case "oa" :

                 return applicationContext.getBean(OANewDataServiceImpl. class );

             default :

                 return null ;

         }

     }

}

这才是正确写法有木有!

总算弄出来了,赶紧记录下来先~

获取某接口所有实现类

在springboot项目中,为了方便,我们可能需要获取某一个接口下面的所有实现类,根据名称进行匹配使用。

正文

1、ServiceLocator.java

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

package com.yang.config;

import com.yang.workOrder.service.IRootService;

import org.springframework.beans.BeansException;

import org.springframework.context.ApplicationContext;

import org.springframework.context.ApplicationContextAware;

import org.springframework.stereotype.Component;

import java.util.Map;

/**

  * explain:获取应用上下文并获取相应的接口实现类

  *

  * @author yang

  * @date 2021/1/5

  */

@Component

public class ServiceLocator implements ApplicationContextAware {

     /**

      * 用于保存接口实现类名及对应的类

      */

     private Map<String, IRootService> map;

     /**

      * 获取应用上下文并获取相应的接口实现类

      * @param applicationContext

      * @throws BeansException

      */

     @Override

     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

         //根据接口类型返回相应的所有bean

         map = applicationContext.getBeansOfType(IRootService. class );

     }

     /**

      * 获取所有实现集合

      * @return

      */

     public Map<String, IRootService> getMap() {

         return map;

     }

     /**

      * 获取对应服务

      * @param key

      * @return

      */

     public IRootService getService(String key) {

         return map.get(key);

     }

}

2、IRootService.java

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

package com.yang.workOrder.service;

import com.alibaba.fastjson.JSONObject;

import com.yang.workOrder.entity.WorkOrder;

/**

  * explain:基础流程操作服务接口

  *

  * @author yang

  * @date 2021/1/5

  */

public interface IRootService {

     /**

      * 开始流程

      * @param workOrder

      * @return

      */

     boolean startProcess(WorkOrder workOrder);

}

3、RootA001ServiceImpl.java

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

package com.yang.workOrder.service.impl;

import com.alibaba.fastjson.JSONObject;

import com.yang.workOrder.entity.WorkOrder;

import com.yang.workOrder.service.IRootService;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.stereotype.Service;

/**

  * explain:A_001流程审批实现类

  *

  * @author yang

  * @date 2021/1/5

  */

@Service ( "A_001" )

public class RootA001ServiceImpl implements IRootService {

     private static final Logger LOGGER = LoggerFactory.getLogger(RootA001ServiceImpl. class );

     @Override

     public boolean startProcess(WorkOrder workOrder) {

         return false ;

     }

}

4、RootA002ServiceImpl.java

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

package com.yang.workOrder.service.impl;

import com.alibaba.fastjson.JSONObject;

import com.yang.workOrder.entity.WorkOrder;

import com.yang.workOrder.service.IRootService;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.stereotype.Service;

/**

  * explain:A_002流程审批实现类

  *

  * @author yang

  * @date 2021/1/5

  */

@Service ( "A_002" )

public class RootA002ServiceImpl implements IRootService {

     private static final Logger LOGGER = LoggerFactory.getLogger(RootA002ServiceImpl. class );

     @Override

     public boolean startProcess(WorkOrder workOrder) {

         return false ;

     }

}

结果

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。

原文链接:https://blog.csdn.net/CarinaYang/article/details/81134603

查看更多关于使用spring动态获取接口的不同实现类的详细内容...

  阅读:49次