前言
我的项目 AngBoot 使用的是 SpringSecurity 做权限管理与认证, 但是, 项目初衷是作为开发模板结构, 所以, 为了应对微服务以及更灵活的使用场景, 我引入了 Dubbo 以提供远程认证服务. 这样, 可以通过修改配置很容易的从我内嵌的认证系统迁移到任何一个开发者自己的认证系统.
今天在自己项目中引入 Dubbo 时遇到一个问题, 项目本身是 SpringBoot 项目, 如果需要 Dubbo 就可以使用
@EnableDubbo
以及注解配置的方式方便的引入 Dubbo 到 SpringBoot 环境, 但是, 我的需求是需要配置化,灵活, 动态的引入 Dubbo rpc 远程服务, 简单的说就是默认使用内嵌的模块, 但是依然可以通过配置使用远程服务, 所以直接为 SpringBoot 添加@EnableDubbo
直接的方式使用 Dubbo 显得并不是那么合适, 因为默认并没有远程调用
参看 Dubbo 文档可以发现Dubbo 的 API 配置方式, 但是官网写的比较粗糙, 但是直觉猜测应该是可以把
ApplicationConfig
,RegistryConfig
等对象放入 IOC 中, 然后通过ReferenceConfig
将远程对象拿到并加入 IOC 中, 这样就不会对其他模块和代码产生影响. 所以写个 exmaple 进行验证.
创建服务提供者 provider-ticket
服务提供者无所谓那种配置方式, 我们就用最快最简单的 SpringBoot +
@EnableDubbo
注解进行配置.
- SpringBoot 入口类
@SpringBootApplication
@EnableDubbo
public class ProviderTicketApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderTicketApplication.class, args);
}
}
- 服务接口
package com.jack.ticket.service;
public interface TicketService {
public String getTicket();
}
- 服务实现
package com.jack.ticket.service;
import com.alibaba.dubbo.config.annotation.Service;
import org.springframework.stereotype.Component;
@Component // 将服务加入 IOC
@Service // 将服务发布出去
public class TicketServiceImpl implements TicketService {
@Override
public String getTicket() {
return "厉害了, 我的国....";
}
}
- Dubbo 配置
dubbo.application.name=provider-ticket
# 注册中心地址
dubbo.registry.address=zookeeper://127.0.0.1:2181
# 包扫描需要提供的服务
dubbo.scan.base-packages=com.jack.ticket.service
- 开启 Zookeeper, 启动服务提供者
ProviderTicketApplication
API 配置创建服务消费者 consumer-user-api
- SpringBoot 入口类. 注意没有 EnableDubbo 注解
@SpringBootApplication
public class ConsumerUserApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerUserApplication.class, args);
}
}
- 远程服务接口
package com.jack.ticket.service;
public interface TicketService {
String getTicket();
}
- 创建一个 Configuration 类去获取远程服务
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 {
/**
* 创建 ApplicationConfig 对象.
* 将其加入 IOC 并不是必须的, 因为只有在获取远程对象时才需要该实例,
* 因此, 当远程服务较多需要多次获取时将该实例加入 IOC 才显得有必要,
* 当然, 你也可以将其作为成员属性持有复用.
*/
@Bean
public ApplicationConfig applicationConfig() {
ApplicationConfig application = new ApplicationConfig();
application.setName("consumer-user");
return application;
}
/**
* 创建 RegistryConfig 以配置注册中心信息.
* @see DubboConfiguration#applicationConfig() 同样的加入 IOC 不是必须的
*/
@Bean
public RegistryConfig registryConfig() {
RegistryConfig registry = new RegistryConfig();
registry.setAddress("zookeeper://127.0.0.1:2181");
return registry;
}
/**
* 获取远程服务对象.
* 实际上, 如果远程对象只调用一次, 也没有必要加入 IOC, 在使用时获取一次就好了,
* 但是大部分场景都是需要多次重复调用的, 而且获取远程服务对象的代价昂贵, 所以,
* 将其加入 IOC 容器以复用很明显是较好实践, 获取可以自行缓存.
*/
@Bean
public TicketService ticketService() {
// 此实例很重,封装了与注册中心的连接以及与提供者的连接,请自行缓存,否则可能造成内存和连接泄漏
ReferenceConfig<TicketService> reference = new ReferenceConfig<>();
reference.setApplication(applicationConfig());
// 多个注册中心可以用setRegistries()
reference.setRegistry(registryConfig());
reference.setInterface(TicketService.class);
// 和本地bean一样使用 TicketService
// 注意:此代理对象内部封装了所有通讯细节,对象较重,请缓存复用
TicketService ticketService = reference.get();
return ticketService;
}
}
- 创建 UserService 使用远程服务对象
由于远程服务对象已经被获取并加入到当前 IOC 中, 所以就可以通过
@Autowired
进行依赖注入.
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);
}
}
- 运行测试
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();
}
}
总结
至此, Dubbo 的 API 配置方式就介绍完了, 我们可以在 Spring/SpringBoot 环境中方便的使用和配合 Spring 的 Conditional 灵活的进行扩展式编程以是自己的项目/产品可以应对更多使用场景.
更多请关注我的项目 AngBoot
日常求赞: 欢迎大家点赞, 评论, 关注, 转发. 要是能给点赞赏就更好了, 哈哈哈.... https://blog.csdn.net/DreamLi1314