Nacos(Dynamic Naming and Configuration Service)是阿里巴巴开源的一款动态服务发现、配置管理和服务管理平台,旨在为微服务架构提供高可用、高性能的解决方案。其核心功能包括服务注册与发现、动态配置管理、服务健康监测、动态 DNS 服务等,广泛应用于云原生和分布式系统场景
https://nacos.io/zh-cn/docs/what-is-nacos.html
1.基于SDK
String serverAddr = "{serverAddr}";
String dataId = "{dataId}";
String group = "{group}";
Properties properties = new Properties();
properties.put("serverAddr", serverAddr);
ConfigService configService = NacosFactory.createConfigService(properties);
String content = configService.getConfig(dataId, group, 5000);
System.out.println(content);
configService.addListener(dataId, group, new Listener() {
@Override
public void receiveConfigInfo(String configInfo) {
System.out.println("recieve1:" + configInfo);
}
@Override
public Executor getExecutor() {
return null;
}
});
// 测试让主线程不退出,因为订阅配置是守护线程,主线程退出守护线程就会退出。 正式代码中无需下面代码
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
2.基于注解
@Controller
@RequestMapping("config")
public class ConfigController {
@NacosValue(value = "${useLocalCache:false}", autoRefreshed = true)
private boolean useLocalCache;
@RequestMapping(value = "/get", method = GET)
@ResponseBody
public boolean get() {
return useLocalCache;
}
}
sh startup.sh -m standalone
<dependency>
<groupId>com.alibaba.bootgroupId>
<artifactId>nacos-config-spring-boot-starterartifactId>
<version>0.2.12version>
dependency>
注意:版本 0.2.x.RELEASE 对应的是 Spring Boot 2.x 版本,版本 0.1.x.RELEASE 对应的是 Spring Boot 1.x 版本。
添加配置
# 配置中心
nacos:
config:
server-addr: 127.0.0.1:8848 # nacos 地址
bootstrap:
enable: true # 预加载
data-id: mianshiya # 控制台填写的 Data ID
group: DEFAULT_GROUP # 控制台填写的 group
type: yaml # 选择的文件格式
auto-refresh: true # 开启自动刷新
5.利用布隆过滤器创建黑名单过滤工具类
@Slf4j
public class BlackIpUtils {
private static BitMapBloomFilter bloomFilter;
// 判断 ip 是否在黑名单内
public static boolean isBlackIp(String ip) {
return bloomFilter.contains(ip);
}
// 重建 ip 黑名单
public static void rebuildBlackIp(String configInfo) {
if (StrUtil.isBlank(configInfo)) {
configInfo = "{}";
}
// 解析 yaml 文件
Yaml yaml = new Yaml();
Map map = yaml.loadAs(configInfo, Map.class);
// 获取 ip 黑名单
List<String> blackIpList = (List<String>) map.get("blackIpList");
// 加锁防止并发
synchronized (BlackIpUtils.class) {
if (CollectionUtil.isNotEmpty(blackIpList)) {
// 注意构造参数的设置
BitMapBloomFilter bitMapBloomFilter = new BitMapBloomFilter(958506);
for (String ip : blackIpList) {
bitMapBloomFilter.add(ip);
}
bloomFilter = bitMapBloomFilter;
} else {
bloomFilter = new BitMapBloomFilter(100);
}
}
}
}
6.创建 Nacos 配置监听类
@Slf4j
@Component
public class NacosListener implements InitializingBean {
@NacosInjected
private ConfigService configService;
@Value("${nacos.config.data-id}")
private String dataId;
@Value("${nacos.config.group}")
private String group;
@Override
public void afterPropertiesSet() throws Exception {
log.info("nacos 监听器启动");
String config = configService.getConfigAndSignListener(dataId, group, 3000L, new Listener() {
final ThreadFactory threadFactory = new ThreadFactory() {
private final AtomicInteger poolNumber = new AtomicInteger(1);
@Override
public Thread newThread(@NotNull Runnable r) {
Thread thread = new Thread(r);
thread.setName("refresh-ThreadPool" + poolNumber.getAndIncrement());
return thread;
}
};
final ExecutorService executorService = Executors.newFixedThreadPool(1, threadFactory);
// 通过线程池异步处理黑名单变化的逻辑
@Override
public Executor getExecutor() {
return executorService;
}
// 监听后续黑名单变化
@Override
public void receiveConfigInfo(String configInfo) {
log.info("监听到配置信息变化:{}", configInfo);
BlackIpUtils.rebuildBlackIp(configInfo);
}
});
// 初始化黑名单
BlackIpUtils.rebuildBlackIp(config);
}
}
7.利用过滤器创建黑名单过滤器
@WebFilter(urlPatterns = "/*", filterName = "blackIpFilter")
public class BlackIpFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
String ipAddress = NetUtils.getIpAddress((HttpServletRequest) servletRequest);
if (BlackIpUtils.isBlackIp(ipAddress)) {
servletResponse.setContentType("text/json;charset=UTF-8");
servletResponse.getWriter().write("{\"errorCode\":\"-1\",\"errorMsg\":\"黑名单IP,禁止访问\"}");
return;
}
filterChain.doFilter(servletRequest, servletResponse);
}
}
注意在启动类上加上 @ServletComponentScan