當系統為微服務時,需要模塊之間的調用,但是不太方便直接將模塊整個引入,所以就需要使用Feign進行調用,使用步驟進行總結,比如A模塊准備調用B模塊的C方法,按照這個進行整理。
第一步:
因為要調用B模塊,所以需要在B模塊創建一個對外的服務接口,並將業務進行實現,代碼如下:
package org.jeecg.modules.api.controller; /** * 服務化 system模塊 對外接口請求類 */ @Api(tags="對外接口請求類") @RestController @RequestMapping("/sys/api") @Slf4j public class SystemAPIController extends BaseController { @Resource private SysUserMapper userMapper; ....../** * 37根據多個用戶id(逗號分隔),查詢返回多個用戶信息 * @param ids * @return */ //todo feign 第三步在該模塊聲明接口 @RequestMapping("/queryUsersById") LoginUser queryUsersById(@RequestParam("ids") String ids){ log.info("fegin遠程調用:第三步"); //return this.sysBaseAPI.queryUsersById(ids); log.info("fegin遠程調用:直接隔斷"); SysUser user = userMapper.selectById(ids); LoginUser loginUser = new LoginUser(); if (user!=null){ loginUser.setId(user.getId()); loginUser.setAvatar(user.getAvatar()); loginUser.setRealname(user.getRealname()); } return loginUser; } ...... }
以上代碼中的對外接口就是”/sys/api/queryUsersById“。
第二步:
因為A模塊調用B模塊,也會存在其他模塊之間的調用,為了提供公共的對外接口,就需要一個額外的公共api模塊,於是有了如下路徑
jeecg-boot-base\jeecg-boot-base-api\jeecg-system-cloud-api\src\main\java\org\jeecg\common\system\api\ISysBaseAPI.java
為了區分是單體還是微服務,使用jeecg-system-cloud-api以及jeecg-system-local-api,也就是cloud和local進行區分。因為咱們使用的是微服務,所以重點說一下cloud模塊。
在cloud模塊中還有一下分類,system.api、online.api、bpm.api,見明知義,主要是按照你調用模塊的簡稱進行區分,調用jeecg-system模塊的api全都寫在system這個api中。
每個模塊中的文件夾都是固定的,接下來簡單說一下每個文件夾中文件的作用
如圖片所示,先簡單說一下2和3,其實他們就是一個東西,熔斷器,主要增加一層保險,當接口查詢不到數據,默認返回一些假數據,從而達到防止系統查詢不到數據導致崩潰的作用。2和3中有對方法的一些重寫,其實就是一模一樣的接口再重新寫一遍,但是返回的值
正常的話會進行處理,具體的使用看下邊代碼中標紅的fallbackFactory參數
接下來就是重點說1的作用了,1其實就是對位的api接口,底層通過http請求來找到對應模塊中的接口。代碼如下:
package org.jeecg.common.system.api;
@Component @FeignClient(contextId = "sysBaseRemoteApi", value = ServiceNameConstants.SYSTEM_SERVICE, fallbackFactory = SysBaseAPIFallbackFactory.class) public interface ISysBaseAPI extends CommonAPI { ......//todo feign 第一步聲明接口 @RequestMapping("/sys/api/queryUsersById") LoginUser queryUsersById(@RequestParam("ids") String ids); ...... }
//在接口上加 @FeignClient 注解來聲明 一個Feign Client,其中 value 為 遠程調用其他服務的服務名 //FeignConfig.class 為 Feign Client 的配置類,注入Retryer類的實例,這樣在遠程調用失敗后,feign會進行重試 //使用 Spring MVC 的注解來綁定具體該服務提供的 REST 接口 //fallback 配置回調處理類,該處理類是作為 Feign 熔斷器的邏輯處理類,實現FeignHystrixInter 接口 //fallbackFactory(類似於斷容器)與fallback方法。
看到標紅的地方沒,有沒有很熟悉,其實就是第一步中所謂的對外接口,這下基本上就已經對應上了。
需要重點注意@FeignClient后邊的三個參數。
- contextId:api接口的id
- value:對應模塊的名稱
- fallbackFactory:熔斷器的文件地址
第三步:
前兩步將准備工作已經做好,接下來就只需要引用然后調用即可。
在B模塊啟動類中,先啟用Feign,代碼如下:
package org.jeecg; import lombok.extern.slf4j.Slf4j; import org.jeecg.common.util.oConvertUtils; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.ComponentScan; import org.springframework.core.env.Environment; import java.net.InetAddress; import java.net.UnknownHostException; @Slf4j @EnableDiscoveryClient @SpringBootApplication @EnableFeignClients public class JeecgknowledgeCloudApplication extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(JeecgknowledgeCloudApplication.class); } public static void main(String[] args) throws UnknownHostException { long startTime = System.currentTimeMillis(); //獲取開始時間 ConfigurableApplicationContext application = SpringApplication.run(JeecgknowledgeCloudApplication.class, args); Environment env = application.getEnvironment(); String ip = InetAddress.getLocalHost().getHostAddress(); String port = env.getProperty("server.port"); String path = oConvertUtils.getString(env.getProperty("server.servlet.context-path")); log.info("\n----------------------------------------------------------\n\t" + "Application Jeecg-Boot is running! Access URLs:\n\t" + "Local: \t\thttp://localhost:" + port + path + "/doc.html\n" + "External: \thttp://" + ip + ":" + port + path + "/doc.html\n" + "Swagger文檔: \thttp://" + ip + ":" + port + path + "/doc.html\n" + "----------------------------------------------------------"); System.out.println("=====知識庫-啟動成功====="); long endTime = System.currentTimeMillis(); //獲取結束時間 System.out.println("程序運行時間:" + (endTime - startTime)/1000 + "秒"); //輸出程序運行時間 } }
標紅的位置是在啟動類啟動fegin的服務應用,然后引入api的模塊,接着在你需要的類中引用“ISysBaseAPI”這個類,從而去引用你想要引用的方法
package org.jeecg.modules.wiki.service.impl;/** * @Description: 頁面信息 * @Author: jeecg-boot * @Date: 2021-11-12 * @Version: V1.0 */ @Service @DS("knowledge") public class ContentServiceImpl extends ServiceImpl<ContentMapper, Content> implements IContentService { @Autowired private ContentMapper contentMapper; @Autowired private BodycontentMapper bodycontentMapper; @Autowired private IBodycontentService iBodycontentService; @Autowired private ISysBaseAPI iSysBaseAPI; ...... @Override public List<ContentVO> getAlllatelyWork(Content content) { List<ContentVO> list =new ArrayList<>(); LoginUser user01 = iSysBaseAPI.queryUsersById("e9ca23d68d884d4ebb19d07889727dae"); // 系統用戶信息 log.debug("數據查詢:"+user01.getUsername()); List<ContentVO> contentVOList = contentMapper.getUserWork(DateUtil.getDate(),DateUtil.getupperDate(),content.getUsername()); if (contentVOList.size()>0&&contentVOList!=null){ for (ContentVO contentVO : contentVOList) { if (!StringUtils.isEmpty(contentVO.getUsername())){ LoginUser user = iSysBaseAPI.queryUsersById(contentVO.getUsername()); // 系統用戶信息 if (user!=null){ contentVO.setLastName(user.getRealname()); contentVO.setActive(user.getAvatar()); } } list.add(contentVO); } } return list; } }
以上過程就完成了模塊之間的調用了。
對於feign參數的使用也進行過總結,鏈接:Feign使用總結-參數傳遞
大致的流程圖如下:
注意:
有些模塊已經引用了ISysBaseAPI這個類,但是調用的是local模塊,通過以上的流程圖進行調用的,當需要一個新的Feign接口時,一定要注意按照已經存在的形式進行使用,不能直接引用以下代碼,不然本該走local的直接走cloud,就會導致啟動異常。
<dependency> <groupId>org.jeecgframework.boot</groupId> <artifactId>jeecg-system-cloud-api</artifactId> </dependency>
eg:jeecg-boot-module-system模塊中JimuReportTokenService類中引用代碼(部分)
/** * 自定義積木報表鑒權(如果不進行自定義,則所有請求不做權限控制) * * 1.自定義獲取登錄token * * 2.自定義獲取登錄用戶 */ @Component public class JimuReportTokenService implements JmReportTokenServiceI { @Autowired private ISysBaseAPI sysBaseAPI;
在沒有引cloud之前走的是local,在引用后走的是cloud。就會導致出現問題。