前言
我的項(xiàng)目 AngBoot 使用的是 SpringSecurity 做權(quán)限管理與認(rèn)證, 但是, 項(xiàng)目初衷是作為開發(fā)模板結(jié)構(gòu), 所以, 為了應(yīng)對(duì)微服務(wù)以及更靈活的使用場(chǎng)景, 我引入了 Dubbo 以提供遠(yuǎn)程認(rèn)證服務(wù). 這樣, 可以通過修改配置很容易的從我內(nèi)嵌的認(rèn)證系統(tǒng)遷移到任何一個(gè)開發(fā)者自己的認(rèn)證系統(tǒng).
今天在自己項(xiàng)目中引入 Dubbo 時(shí)遇到一個(gè)問題, 項(xiàng)目本身是 SpringBoot 項(xiàng)目, 如果需要 Dubbo 就可以使用
@EnableDubbo以及注解配置的方式方便的引入 Dubbo 到 SpringBoot 環(huán)境, 但是, 我的需求是需要配置化,靈活, 動(dòng)態(tài)的引入 Dubbo rpc 遠(yuǎn)程服務(wù), 簡(jiǎn)單的說就是默認(rèn)使用內(nèi)嵌的模塊, 但是依然可以通過配置使用遠(yuǎn)程服務(wù), 所以直接為 SpringBoot 添加@EnableDubbo直接的方式使用 Dubbo 顯得并不是那么合適, 因?yàn)槟J(rèn)并沒有遠(yuǎn)程調(diào)用
參看 Dubbo 文檔可以發(fā)現(xiàn)Dubbo 的 API 配置方式, 但是官網(wǎng)寫的比較粗糙, 但是直覺猜測(cè)應(yīng)該是可以把
ApplicationConfig,RegistryConfig等對(duì)象放入 IOC 中, 然后通過ReferenceConfig將遠(yuǎn)程對(duì)象拿到并加入 IOC 中, 這樣就不會(huì)對(duì)其他模塊和代碼產(chǎn)生影響. 所以寫個(gè) exmaple 進(jìn)行驗(yàn)證.
創(chuàng)建服務(wù)提供者 provider-ticket
服務(wù)提供者無所謂那種配置方式, 我們就用最快最簡(jiǎn)單的 SpringBoot +
@EnableDubbo注解進(jìn)行配置.
- SpringBoot 入口類
@SpringBootApplication
@EnableDubbo
public class ProviderTicketApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderTicketApplication.class, args);
}
}
- 服務(wù)接口
package com.jack.ticket.service;
public interface TicketService {
public String getTicket();
}
- 服務(wù)實(shí)現(xiàn)
package com.jack.ticket.service;
import com.alibaba.dubbo.config.annotation.Service;
import org.springframework.stereotype.Component;
@Component // 將服務(wù)加入 IOC
@Service // 將服務(wù)發(fā)布出去
public class TicketServiceImpl implements TicketService {
@Override
public String getTicket() {
return "厲害了, 我的國(guó)....";
}
}
- Dubbo 配置
dubbo.application.name=provider-ticket
# 注冊(cè)中心地址
dubbo.registry.address=zookeeper://127.0.0.1:2181
# 包掃描需要提供的服務(wù)
dubbo.scan.base-packages=com.jack.ticket.service
- 開啟 Zookeeper, 啟動(dòng)服務(wù)提供者
ProviderTicketApplication
file
API 配置創(chuàng)建服務(wù)消費(fèi)者 consumer-user-api
- SpringBoot 入口類. 注意沒有 EnableDubbo 注解
@SpringBootApplication
public class ConsumerUserApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerUserApplication.class, args);
}
}
- 遠(yuǎn)程服務(wù)接口
package com.jack.ticket.service;
public interface TicketService {
String getTicket();
}
- 創(chuàng)建一個(gè) Configuration 類去獲取遠(yuǎn)程服務(wù)
package com.jack.user.config;
import com.alibaba.dubbo.config.ApplicationConfig;
import com.alibaba.dubbo.config.ReferenceConfig;
import com.alibaba.dubbo.config.RegistryConfig;
import com.jack.ticket.service.TicketService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class DubboConfiguration {
/**
* 創(chuàng)建 ApplicationConfig 對(duì)象.
* 將其加入 IOC 并不是必須的, 因?yàn)橹挥性讷@取遠(yuǎn)程對(duì)象時(shí)才需要該實(shí)例,
* 因此, 當(dāng)遠(yuǎn)程服務(wù)較多需要多次獲取時(shí)將該實(shí)例加入 IOC 才顯得有必要,
* 當(dāng)然, 你也可以將其作為成員屬性持有復(fù)用.
*/
@Bean
public ApplicationConfig applicationConfig() {
ApplicationConfig application = new ApplicationConfig();
application.setName("consumer-user");
return application;
}
/**
* 創(chuàng)建 RegistryConfig 以配置注冊(cè)中心信息.
* @see DubboConfiguration#applicationConfig() 同樣的加入 IOC 不是必須的
*/
@Bean
public RegistryConfig registryConfig() {
RegistryConfig registry = new RegistryConfig();
registry.setAddress("zookeeper://127.0.0.1:2181");
return registry;
}
/**
* 獲取遠(yuǎn)程服務(wù)對(duì)象.
* 實(shí)際上, 如果遠(yuǎn)程對(duì)象只調(diào)用一次, 也沒有必要加入 IOC, 在使用時(shí)獲取一次就好了,
* 但是大部分場(chǎng)景都是需要多次重復(fù)調(diào)用的, 而且獲取遠(yuǎn)程服務(wù)對(duì)象的代價(jià)昂貴, 所以,
* 將其加入 IOC 容器以復(fù)用很明顯是較好實(shí)踐, 獲取可以自行緩存.
*/
@Bean
public TicketService ticketService() {
// 此實(shí)例很重,封裝了與注冊(cè)中心的連接以及與提供者的連接,請(qǐng)自行緩存,否則可能造成內(nèi)存和連接泄漏
ReferenceConfig<TicketService> reference = new ReferenceConfig<>();
reference.setApplication(applicationConfig());
// 多個(gè)注冊(cè)中心可以用setRegistries()
reference.setRegistry(registryConfig());
reference.setInterface(TicketService.class);
// 和本地bean一樣使用 TicketService
// 注意:此代理對(duì)象內(nèi)部封裝了所有通訊細(xì)節(jié),對(duì)象較重,請(qǐng)緩存復(fù)用
TicketService ticketService = reference.get();
return ticketService;
}
}
- 創(chuàng)建 UserService 使用遠(yuǎn)程服務(wù)對(duì)象
由于遠(yuǎn)程服務(wù)對(duì)象已經(jīng)被獲取并加入到當(dāng)前 IOC 中, 所以就可以通過
@Autowired進(jìn)行依賴注入.
package com.jack.user.service;
import com.jack.ticket.service.TicketService;
import org.springframework.stereotype.Service;
@Service
public class UserService {
public final TicketService ticketService;
public UserService(TicketService ticketService) {
this.ticketService = ticketService;
}
public void buyTicket() {
String ticket = ticketService.getTicket();
System.out.println("買到票了, ticket: " + ticket);
}
}
- 運(yùn)行測(cè)試
package com.jack.user.service;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserServiceTests {
@Autowired
private UserService userService;
@Test
public void testBuyTicket() {
Assert.assertNotNull("init user service failed...", userService);
userService.buyTicket();
}
}

總結(jié)
至此, Dubbo 的 API 配置方式就介紹完了, 我們可以在 Spring/SpringBoot 環(huán)境中方便的使用和配合 Spring 的 Conditional 靈活的進(jìn)行擴(kuò)展式編程以是自己的項(xiàng)目/產(chǎn)品可以應(yīng)對(duì)更多使用場(chǎng)景.
更多請(qǐng)關(guān)注我的項(xiàng)目 AngBoot
日常求贊: 歡迎大家點(diǎn)贊, 評(píng)論, 關(guān)注, 轉(zhuǎn)發(fā). 要是能給點(diǎn)贊賞就更好了, 哈哈哈.... https://blog.csdn.net/DreamLi1314
