微服务
微服务(Microservices)是一种软件架构风格,他区别与单体架构,将拆分为多个小型的、独立的服务,每个服务都可以独立开发、部署和维护。这些服务通过轻量级的API进行通信。
Nacos简述
Nacos 用于发现、配置和管理微服务。nacos有2个核心功能,一个是注册中心,一个是配置中心。这里Nacos学习就是围绕着注册中心和配置中心2个核心功能展开的。
-
注册中心的重点
服务的注册:将服务注册到Nacos上
服务的发现:找到相关的服务,使用RPC组件完成服务的调用 -
配置中心的重点
发现配置
获取配置
当前是以Naocs2.4.3版本学习总结的。
Spring Boot整合Nacos步骤
服务版本说明:
官网链接:https://github.com/alibaba/spring-cloud-alibaba/wiki/版本说明
添加依赖:
// nacos依赖引入implementation 'com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-discovery:2021.0.5.0'implementation 'com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-config:2021.0.5.0'
在resources目录下增加bootstrap.yml文件
spring:application:name: springboot_democloud:nacos:config:file-extension: ymlserver-addr: 127.0.0.1:8848enabled: truediscovery:server-addr: 127.0.0.1:8848enabled: true
启动服务后在浏览器访问http://127.0.0.1:8848/nacoss查看下
服务已经注册到Nacos上了
增加测试用例直接调用接口注册服务
@SpringBootTest
class SpringbootDemo2ApplicationTests {@Testvoid contextLoads() throws Exception {NamingService namingService = NamingFactory.createNamingService("127.0.0.1:8848");// 将服务注册到nacos上namingService.registerInstance("nacos.test.1", "11.11.11.11", 8888, "test");Thread.sleep(Integer.MAX_VALUE);}
客户端注册服务到Nacos上逻辑:
是使用这个方法
namingService.registerInstance("nacos.test.1", "11.11.11.11", 8888, "test");
将当前服务信息存到Map集合里,然后调用接口(/nacos/v1/ns/instance),将服务信息发给nacos
public class NacosNamingService implements NamingService {@Overridepublic void registerInstance(String serviceName, String groupName, String ip, int port, String clusterName) throws NacosException {// 生成实例对象,填充ip,端口,和服务名Instance instance = new Instance();instance.setIp(ip);instance.setPort(port);instance.setWeight(1.0);instance.setClusterName(clusterName);registerInstance(serviceName, groupName, instance);}@Overridepublic void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {// 判断是否是临时实例if (instance.isEphemeral()) {BeatInfo beatInfo = new BeatInfo();// 拼接服务名 groupName@@serviceNamebeatInfo.setServiceName(NamingUtils.getGroupedName(serviceName, groupName));beatInfo.setIp(instance.getIp());beatInfo.setPort(instance.getPort());beatInfo.setCluster(instance.getClusterName());beatInfo.setWeight(instance.getWeight());beatInfo.setMetadata(instance.getMetadata());beatInfo.setScheduled(false);beatInfo.setPeriod(instance.getInstanceHeartBeatInterval());// 心跳检测服务beatReactor.addBeatInfo(NamingUtils.getGroupedName(serviceName, groupName), beatInfo);}// 调用api注册服务信息serverProxy.registerService(NamingUtils.getGroupedName(serviceName, groupName), groupName, instance);}}
public class NamingProxy {public void registerService(String serviceName, String groupName, Instance instance) throws NacosException {NAMING_LOGGER.info("[REGISTER-SERVICE] {} registering service {} with instance: {}",namespaceId, serviceName, instance);final Map<String, String> params = new HashMap<String, String>(9);params.put(CommonParams.NAMESPACE_ID, namespaceId);params.put(CommonParams.SERVICE_NAME, serviceName);params.put(CommonParams.GROUP_NAME, groupName);params.put(CommonParams.CLUSTER_NAME, instance.getClusterName());params.put("ip", instance.getIp());params.put("port", String.valueOf(instance.getPort()));params.put("weight", String.valueOf(instance.getWeight()));params.put("enable", String.valueOf(instance.isEnabled()));params.put("healthy", String.valueOf(instance.isHealthy()));params.put("ephemeral", String.valueOf(instance.isEphemeral()));params.put("metadata", JSON.toJSONString(instance.getMetadata()));reqAPI(UtilAndComs.NACOS_URL_INSTANCE, params, HttpMethod.POST);}}
启动当前Springboot程序如何将服务注册到Nacos上呢?
首先nacos-discovery依赖包里面有个文件spring.factories,内容如下:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\com.alibaba.cloud.nacos.discovery.NacosDiscoveryAutoConfiguration,\com.alibaba.cloud.nacos.ribbon.RibbonNacosAutoConfiguration,\com.alibaba.cloud.nacos.endpoint.NacosDiscoveryEndpointAutoConfiguration,\com.alibaba.cloud.nacos.registry.NacosServiceRegistryAutoConfiguration,\com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientConfiguration,\com.alibaba.cloud.nacos.discovery.configclient.NacosConfigServerAutoConfiguration
org.springframework.cloud.bootstrap.BootstrapConfiguration=\com.alibaba.cloud.nacos.discovery.configclient.NacosDiscoveryClientConfigServiceBootstrapConfiguration
启动过程中会加载这些配置类,实例化需要的bean
查看NacosServiceRegistryAutoConfiguration配置类,注册流程是在NacosServiceRegistry里开始做的
@Configuration
@EnableConfigurationProperties
@ConditionalOnNacosDiscoveryEnabled
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
@AutoConfigureAfter({ AutoServiceRegistrationConfiguration.class,AutoServiceRegistrationAutoConfiguration.class,NacosDiscoveryAutoConfiguration.class })
public class NacosServiceRegistryAutoConfiguration {// 生成NacosServiceRegistry类型的bean,注入到容器中@Beanpublic NacosServiceRegistry nacosServiceRegistry(NacosDiscoveryProperties nacosDiscoveryProperties) {return new NacosServiceRegistry(nacosDiscoveryProperties);}......}
注册本地服务
在com.alibaba.cloud.nacos.registry.NacosServiceRegistry#register里调用namingService.registerInstance方法,最后调用http接口,将服务信息注册到nacos上。
这个入口怎么进来呢?
是在启动springboot项目时,在其中spring生命周期里,getLifecycleProcessor().onRefresh();做的。
NacosAutoServiceRegistration继承了AbstractAutoServiceRegistration抽象类,在执行listener监听器那里做的,去注册本地的服务。实现了AbstractAutoServiceRegistration的register接口(org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration#register)
public abstract class AbstractAutoServiceRegistration<R extends Registration>implements AutoServiceRegistration, ApplicationContextAware, ApplicationListener<WebServerInitializedEvent> {@Override@SuppressWarnings("deprecation")public void onApplicationEvent(WebServerInitializedEvent event) {bind(event);}@Deprecatedpublic void bind(WebServerInitializedEvent event) {ApplicationContext context = event.getApplicationContext();if (context instanceof ConfigurableWebServerApplicationContext) {if ("management".equals(((ConfigurableWebServerApplicationContext) context).getServerNamespace())) {return;}}this.port.compareAndSet(0, event.getWebServer().getPort());this.start();}public void start() {if (!isEnabled()) {if (logger.isDebugEnabled()) {logger.debug("Discovery Lifecycle disabled. Not starting");}return;}if (!this.running.get()) {this.context.publishEvent(new InstancePreRegisteredEvent(this, getRegistration()));register();if (shouldRegisterManagement()) {registerManagement();}this.context.publishEvent(new InstanceRegisteredEvent<>(this, getConfiguration()));this.running.compareAndSet(false, true);}}protected void register() {this.serviceRegistry.register(getRegistration());}
}
public class NacosServiceRegistry implements ServiceRegistry<Registration> {private static final Logger log = LoggerFactory.getLogger(NacosServiceRegistry.class);private final NacosDiscoveryProperties nacosDiscoveryProperties;private final NamingService namingService;public NacosServiceRegistry(NacosDiscoveryProperties nacosDiscoveryProperties) {this.nacosDiscoveryProperties = nacosDiscoveryProperties;this.namingService = nacosDiscoveryProperties.namingServiceInstance();}@Overridepublic void register(Registration registration) {if (StringUtils.isEmpty(registration.getServiceId())) {log.warn("No service to register for nacos client...");return;}String serviceId = registration.getServiceId();String group = nacosDiscoveryProperties.getGroup();Instance instance = getNacosInstanceFromRegistration(registration);try {// 这里将服务注册到nacos上namingService.registerInstance(serviceId, group, instance);log.info("nacos registry, {} {} {}:{} register finished", group, serviceId,instance.getIp(), instance.getPort());}catch (Exception e) {log.error("nacos registry, {} register failed...{},", serviceId,registration.toString(), e);// rethrow a RuntimeException if the registration is failed.// issue : https://github.com/alibaba/spring-cloud-alibaba/issues/1132rethrowRuntimeException(e);}}}