引入依赖
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-spring-context</artifactId>
<version>${latest.version}</version>
</dependency>
本文使用的版本为:1.1.1(与Spring 中使用Nacos配置管理一章引用的依赖一样)
示例
package com.yyoo.nacos.spring.discovery;
import com.alibaba.nacos.api.annotation.NacosProperties;
import com.alibaba.nacos.spring.context.annotation.discovery.EnableNacosDiscovery;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableNacosDiscovery(globalProperties = @NacosProperties(serverAddr = "127.0.0.1:8848"))
public class DiscoveryConfiguration {
}
package com.yyoo.nacos.spring.discovery;
import com.alibaba.nacos.api.annotation.NacosInjected;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
@Controller
@RequestMapping("discovery")
public class DiscoveryController {
@NacosInjected
private NamingService namingService;
@RequestMapping(value = "/register", method = RequestMethod.GET)
@ResponseBody
public void register(@RequestParam String serviceName) throws NacosException {
namingService.registerInstance(serviceName,"111.111.1.1",8888);
}
@RequestMapping(value = "/get", method = RequestMethod.GET)
@ResponseBody
public List<Instance> get(@RequestParam String serviceName) throws NacosException {
return namingService.getAllInstances(serviceName);
}
}
@Test
public void testSpring3() throws NacosException {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.scan("com.yyoo");
context.refresh();
String serviceName = "testDiscovery";
DiscoveryController controller = context.getBean(DiscoveryController.class);
controller.register(serviceName);
System.out.println(controller.get(serviceName));
}
注:此处是为了方便,模拟请求Controller,其实效果是一样的。
目前还未注册服务,所以打印结果为:
[Instance{instanceId=‘111.111.1.1#8888#DEFAULT#DEFAULT_GROUP@@testDiscovery’, ip=‘111.111.1.1’, port=8888, weight=1.0, healthy=true, enabled=true, ephemeral=true, clusterName=‘DEFAULT’, serviceName=‘DEFAULT_GROUP@@testDiscovery’, metadata={}}]
此时可以查看Nacos服务管理界面
@NacosInjected注解详解
@NacosInjected 是一个核心注解,用于在Spring Beans 中注入 ConfigService 或 NamingService 实例,并使这些实例可缓存
package com.yyoo.nacos.spring.discovery;
import com.alibaba.nacos.api.annotation.NacosInjected;
import com.alibaba.nacos.api.annotation.NacosProperties;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.naming.NamingService;
import org.springframework.stereotype.Component;
@Component
public class InjectedBean {
@NacosInjected
private ConfigService configService;
@NacosInjected(properties = @NacosProperties(encode = "UTF-8"))
private ConfigService configService2;
@NacosInjected(properties = @NacosProperties(encode = "GBK"))
private ConfigService configService3;
@NacosInjected
private NamingService namingService;
@NacosInjected(properties = @NacosProperties(encode = "UTF-8"))
private NamingService namingService2;
@NacosInjected(properties = @NacosProperties(encode = "GBK"))
private NamingService namingService3;
public void testInjection() {
System.out.println("configService == configService2:" + (configService == configService2));
System.out.println("configService2 == configService3:" + (configService2 == configService3));
System.out.println("namingService == namingService2:" + (namingService == namingService2));
System.out.println("namingService2 == namingService3:" + (namingService2 == namingService3));
}
}
结果:
configService == configService2:true
configService2 == configService3:false
namingService == namingService2:true
namingService2 == namingService3:false结论: @NacosProperties 相等,则实例将是相同的,无论属性是来自全局还是自定义的 Nacos 属性。反之,如果@NacosProperties不相等,实例不是相同的,建议在同一个应用内使用相同的配置。
配置监听注解
package com.yyoo.nacos.spring.bean; import com.alibaba.nacos.api.annotation.NacosInjected; import com.alibaba.nacos.api.config.ConfigService; import com.alibaba.nacos.api.config.annotation.NacosConfigListener; import org.springframework.context.annotation.Configuration; @Configuration public class ConfigBean { @NacosInjected private ConfigService configService; @NacosConfigListener(dataId = "com.yyoo.nacos.sdk.CofingServiceTest",groupId = "Nacos:Test") public void onMessage(String config) { System.out.println("listener:"+config); } }
@NacosConfigListener(dataId = "com.yyoo.nacos.sdk.CofingServiceTest",groupId = "Nacos:Test") public void onMessage(String config) { System.out.println("listener:"+config); }
以上代码等价于:
configService.addListener("com.yyoo.nacos.sdk.CofingServiceTest", "Nacos:Test", new AbstractListener() { @Override public void receiveConfigInfo(String config) { System.out.println("listener:"+config); } });
为监听添加类型转换器
@NacosConfigListener 的类型转换包括内置和自定义实现。 默认情况下,内置类型转换基于 Spring DefaultFormattingConversionService来实现。常见的基本类型都可以自动转换。
比如我们上面示例的DataId:“com.yyoo.nacos.sdk.CofingServiceTest”,groupId:“Nacos:Test”
其是一个Json类型,我们监听示例中使用String类型是可以的。如果我们需要将其在监听中解析成对象呢?这个时候就需要类型转换器了,自定义实现NacosConfigConverter接口即可自己实现类型转换器,比如我们自定义实现上面JSON配置内容的类型转换器
package com.yyoo.nacos.spring.bean; import com.alibaba.nacos.api.config.convert.NacosConfigConverter; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; public class TestNacosConfigConverter implements NacosConfigConverter<TestNacosConfig> { @Override public boolean canConvert(Class<TestNacosConfig> targetType) { return true; } @Override public TestNacosConfig convert(String config) { ObjectMapper mapper = new ObjectMapper(); TestNacosConfig obj = null; try { obj = mapper.readValue(config,TestNacosConfig.class); } catch (JsonProcessingException e) { e.printStackTrace(); } return obj; } }
编写自定义对象
package com.yyoo.nacos.spring.bean; public class TestNacosConfig { private String conf1; private String conf2; public String getConf1() { return conf1; } public void setConf1(String conf1) { this.conf1 = conf1; } public String getConf2() { return conf2; } public void setConf2(String conf2) { this.conf2 = conf2; } @Override public String toString() { final StringBuilder sb = new StringBuilder("TestNacosConfig{"); sb.append("conf1='").append(conf1).append('\''); sb.append(", conf2='").append(conf2).append('\''); sb.append('}'); return sb.toString(); } }
修改添加监听的程序
@NacosConfigListener(dataId = "com.yyoo.nacos.sdk.CofingServiceTest",groupId = "Nacos:Test",converter = TestNacosConfigConverter.class) public void onMessage(TestNacosConfig config) { System.out.println("bean listener:"+config); }
测试代码:
@Test public void testSpring5() throws NacosException, InterruptedException { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.scan("com.yyoo"); context.refresh(); Thread.sleep(60000); // 休眠60秒,保证主程序不关闭 }
测试代码主程序没有停止前,在Nacos配置界面修改对应的配置conf2=‘test2’,监听程序打印结果:
bean listener:TestNacosConfig{conf1=‘test1’, conf2=‘test2’}
监听超时时间设置
由于运行自定义的 NacosConfigConverter 可能需要一些时间,因此您可以在 @NacosConfigListener.timeout() 属性中设置最大执行时间,以防止它阻塞其他侦听器。只需在@NacosConfigListener注解上加上timeout属性配置即可,timeout默认为1000L
@NacosConfigListener(dataId = "com.yyoo.nacos.sdk.CofingServiceTest",groupId = "Nacos:Test" ,converter = TestNacosConfigConverter.class,timeout = 1000L) public void onMessage(TestNacosConfig config) { System.out.println("bean listener:"+config); }