diff --git a/kenaito-common/src/main/java/cn/odboy/infra/context/CallBack.java b/kenaito-common/src/main/java/cn/odboy/infra/context/CallBack.java index 2a258bd..d062614 100644 --- a/kenaito-common/src/main/java/cn/odboy/infra/context/CallBack.java +++ b/kenaito-common/src/main/java/cn/odboy/infra/context/CallBack.java @@ -1,18 +1,4 @@ -/* - * Copyright 2019-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ + package cn.odboy.infra.context; diff --git a/kenaito-config-common/src/main/java/cn/odboy/config/context/CallBack.java b/kenaito-config-common/src/main/java/cn/odboy/config/context/CallBack.java new file mode 100644 index 0000000..b60ffda --- /dev/null +++ b/kenaito-config-common/src/main/java/cn/odboy/config/context/CallBack.java @@ -0,0 +1,27 @@ +package cn.odboy.config.context; + +/** + * @date: 2020/6/9 17:02 + * @since: 1.0 + * @see {@link SpringContextHolder} + * 针对某些初始化方法,在SpringContextHolder 初始化前时,
+ * 可提交一个 提交回调任务。
+ * 在SpringContextHolder 初始化后,进行回调使用 + */ + +public interface CallBack { + /** + * 回调执行方法 + */ + void executor(); + + /** + * 本回调任务名称 + * + * @return / + */ + default String getCallBackName() { + return Thread.currentThread().getId() + ":" + this.getClass().getName(); + } +} + diff --git a/kenaito-config-common/src/main/java/cn/odboy/config/context/SpringContextHolder.java b/kenaito-config-common/src/main/java/cn/odboy/config/context/SpringContextHolder.java new file mode 100644 index 0000000..1379562 --- /dev/null +++ b/kenaito-config-common/src/main/java/cn/odboy/config/context/SpringContextHolder.java @@ -0,0 +1,140 @@ +package cn.odboy.config.context; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +@Slf4j +public class SpringContextHolder implements ApplicationContextAware, DisposableBean { + + private static ApplicationContext applicationContext = null; + private static final List CALL_BACKS = new ArrayList<>(); + private static boolean addCallback = true; + + /** + * 针对 某些初始化方法,在SpringContextHolder 未初始化时 提交回调方法。 + * 在SpringContextHolder 初始化后,进行回调使用 + * + * @param callBack 回调函数 + */ + public synchronized static void addCallBacks(CallBack callBack) { + if (addCallback) { + SpringContextHolder.CALL_BACKS.add(callBack); + } else { + log.warn("CallBack:{} 已无法添加!立即执行", callBack.getCallBackName()); + callBack.executor(); + } + } + + /** + * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型. + */ + @SuppressWarnings("unchecked") + public static T getBean(String name) { + assertContextInjected(); + return (T) applicationContext.getBean(name); + } + + /** + * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型. + */ + public static T getBean(Class requiredType) { + assertContextInjected(); + return applicationContext.getBean(requiredType); + } + + /** + * 获取SpringBoot 配置信息 + * + * @param property 属性key + * @param defaultValue 默认值 + * @param requiredType 返回类型 + * @return / + */ + public static T getProperties(String property, T defaultValue, Class requiredType) { + T result = defaultValue; + try { + result = getBean(Environment.class).getProperty(property, requiredType); + } catch (Exception ignored) { + } + return result; + } + + /** + * 获取SpringBoot 配置信息 + * + * @param property 属性key + * @return / + */ + public static String getProperties(String property) { + return getProperties(property, null, String.class); + } + + /** + * 获取SpringBoot 配置信息 + * + * @param property 属性key + * @param requiredType 返回类型 + * @return / + */ + public static T getProperties(String property, Class requiredType) { + return getProperties(property, null, requiredType); + } + + /** + * 检查ApplicationContext不为空. + */ + private static void assertContextInjected() { + if (applicationContext == null) { + throw new IllegalStateException("applicaitonContext属性未注入, 请在applicationContext" + + ".xml中定义SpringContextHolder或在SpringBoot启动类中注册SpringContextHolder."); + } + } + + /** + * 清除SpringContextHolder中的ApplicationContext为Null. + */ + private static void clearHolder() { + log.debug("清除SpringContextHolder中的ApplicationContext:" + + applicationContext); + applicationContext = null; + } + + @Override + public void destroy() { + SpringContextHolder.clearHolder(); + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + if (SpringContextHolder.applicationContext != null) { + log.warn("SpringContextHolder中的ApplicationContext被覆盖, 原有ApplicationContext为:" + SpringContextHolder.applicationContext); + } + SpringContextHolder.applicationContext = applicationContext; + if (addCallback) { + for (CallBack callBack : SpringContextHolder.CALL_BACKS) { + callBack.executor(); + } + CALL_BACKS.clear(); + } + SpringContextHolder.addCallback = false; + } + + /** + * 获取 @Service 的所有 bean 名称 + * + * @return / + */ + public static List getAllServiceBeanName() { + return new ArrayList<>(Arrays.asList(applicationContext + .getBeanNamesForAnnotation(Service.class))); + } +} diff --git a/kenaito-config-common/src/main/java/cn/odboy/config/model/Message.java b/kenaito-config-common/src/main/java/cn/odboy/config/model/Message.java new file mode 100644 index 0000000..7ca1983 --- /dev/null +++ b/kenaito-config-common/src/main/java/cn/odboy/config/model/Message.java @@ -0,0 +1,21 @@ +package cn.odboy.config.model; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class Message implements Serializable { + /** + * 消息类型:
+ * register 注册
+ * pullConfig 拉取配置
+ * updateConfig 更新配置
+ */ + private String type; + +} diff --git a/kenaito-config-core/src/main/java/cn/odboy/config/ConfigCenterProperties.java b/kenaito-config-core/src/main/java/cn/odboy/config/ConfigClientProperties.java similarity index 91% rename from kenaito-config-core/src/main/java/cn/odboy/config/ConfigCenterProperties.java rename to kenaito-config-core/src/main/java/cn/odboy/config/ConfigClientProperties.java index ea3547f..e05185e 100644 --- a/kenaito-config-core/src/main/java/cn/odboy/config/ConfigCenterProperties.java +++ b/kenaito-config-core/src/main/java/cn/odboy/config/ConfigClientProperties.java @@ -9,7 +9,7 @@ import org.springframework.stereotype.Component; @Setter @Component @ConfigurationProperties(prefix = "kenaito.config-center") -public class ConfigCenterProperties { +public class ConfigClientProperties { private String server; private Integer port; private String dataId; diff --git a/kenaito-config-core/src/main/java/cn/odboy/config/context/ConfigCenterConfigLoader.java b/kenaito-config-core/src/main/java/cn/odboy/config/context/ClientConfigLoader.java similarity index 78% rename from kenaito-config-core/src/main/java/cn/odboy/config/context/ConfigCenterConfigLoader.java rename to kenaito-config-core/src/main/java/cn/odboy/config/context/ClientConfigLoader.java index f8edbab..f4f7b98 100644 --- a/kenaito-config-core/src/main/java/cn/odboy/config/context/ConfigCenterConfigLoader.java +++ b/kenaito-config-core/src/main/java/cn/odboy/config/context/ClientConfigLoader.java @@ -1,11 +1,9 @@ package cn.odboy.config.context; import cn.hutool.core.io.FileUtil; -import cn.odboy.config.ConfigCenterProperties; -import cn.odboy.config.netty.ConfigCenterClient; +import cn.odboy.config.netty.ConfigClient; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeansException; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.context.annotation.Bean; @@ -25,7 +23,7 @@ import java.nio.file.Paths; */ @Slf4j @Configuration -public class ConfigCenterConfigLoader { +public class ClientConfigLoader { private static final String OS_TYPE_WIN = "win"; private static final String OS_TYPE_MAC = "mac"; private static final String DEFAULT_PATH_WIN = "c:\\data"; @@ -55,21 +53,22 @@ public class ConfigCenterConfigLoader { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { String defaultCacheDir = getDefaultCacheDir(); - String server = environment.getProperty(DEFAULT_CONFIG_NAME_SERVER, String.class, DEFAULT_CONFIG_SERVER); - Integer port = environment.getProperty(DEFAULT_CONFIG_NAME_PORT, Integer.class, DEFAULT_CONFIG_PORT); - String env = environment.getProperty(DEFAULT_CONFIG_NAME_ENV, String.class, DEFAULT_CONFIG_ENV); - String dataId = environment.getProperty(DEFAULT_CONFIG_NAME_DATA_ID, String.class, DEFAULT_CONFIG_DATA_ID); - String cacheDir = environment.getProperty(DEFAULT_CONFIG_NAME_CACHE_DIR, String.class, defaultCacheDir); - validateCacheDirPath(defaultCacheDir, cacheDir); - createCacheDir(cacheDir); - ConfigCenterClient client = new ConfigCenterClient(); + ClientProp.server = environment.getProperty(DEFAULT_CONFIG_NAME_SERVER, String.class, DEFAULT_CONFIG_SERVER); + ClientProp.port = environment.getProperty(DEFAULT_CONFIG_NAME_PORT, Integer.class, DEFAULT_CONFIG_PORT); + ClientProp.env = environment.getProperty(DEFAULT_CONFIG_NAME_ENV, String.class, DEFAULT_CONFIG_ENV); + ClientProp.dataId = environment.getProperty(DEFAULT_CONFIG_NAME_DATA_ID, String.class, DEFAULT_CONFIG_DATA_ID); + ClientProp.cacheDir = environment.getProperty(DEFAULT_CONFIG_NAME_CACHE_DIR, String.class, defaultCacheDir); + log.info("客户端属性: {}", ClientProp.toPrint()); + validateCacheDirPath(defaultCacheDir, ClientProp.cacheDir); + createCacheDir(ClientProp.cacheDir); try { - client.start(server, port); + ConfigClient client = new ConfigClient(); + client.start(ClientProp.server, ClientProp.port); } catch (InterruptedException e) { log.error("Netty Client Start Error", e); throw new RuntimeException(e); } -// ConfigCenterClient client = new ConfigCenterClient("http://your-config-center-url/config"); +// ConfigClient client = new ConfigClient("http://your-config-center-url/config"); // Map configKv = client.fetchConfig(); // MapPropertySource propertySource = new MapPropertySource("configCenter", configKv); // environment.getPropertySources().addFirst(propertySource); diff --git a/kenaito-config-core/src/main/java/cn/odboy/config/context/ClientProp.java b/kenaito-config-core/src/main/java/cn/odboy/config/context/ClientProp.java new file mode 100644 index 0000000..780a440 --- /dev/null +++ b/kenaito-config-core/src/main/java/cn/odboy/config/context/ClientProp.java @@ -0,0 +1,25 @@ +package cn.odboy.config.context; + +/** + * 客户端属性 + * + * @author odboy + * @date 2024-12-03 + */ +public class ClientProp { + public static String server; + public static Integer port; + public static String env; + public static String dataId; + public static String cacheDir; + + public static String toPrint() { + return String.format("server: %s, port: %s, env: %s, dataId: %s, cacheDir: %s", + server, + port, + env, + dataId, + cacheDir + ); + } +} diff --git a/kenaito-config-core/src/main/java/cn/odboy/config/netty/ConfigCenterClientHandler.java b/kenaito-config-core/src/main/java/cn/odboy/config/netty/ConfigCenterClientHandler.java deleted file mode 100644 index 121a05d..0000000 --- a/kenaito-config-core/src/main/java/cn/odboy/config/netty/ConfigCenterClientHandler.java +++ /dev/null @@ -1,25 +0,0 @@ -package cn.odboy.config.netty; - -import cn.odboy.config.model.ConfigKv; -import cn.odboy.config.util.ProtostuffUtil; -import io.netty.channel.ChannelInboundHandlerAdapter; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.ChannelHandlerContext; -public class ConfigCenterClientHandler extends ChannelInboundHandlerAdapter { - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { - System.out.println("收到服务器消息:" + msg); - } - - @Override - public void channelActive(ChannelHandlerContext ctx) throws Exception { - System.out.println("MyClientHandler发送数据"); - //ctx.writeAndFlush("测试String编解码"); - //测试对象编解码 - //ctx.writeAndFlush(new User(1,"zhuge")); - //测试用protostuff对对象编解码 - ByteBuf buf = Unpooled.copiedBuffer(ProtostuffUtil.serializer(new ConfigKv("app.config", "张三"))); - ctx.writeAndFlush(buf); - } -} diff --git a/kenaito-config-core/src/main/java/cn/odboy/config/netty/ConfigCenterClient.java b/kenaito-config-core/src/main/java/cn/odboy/config/netty/ConfigClient.java similarity index 88% rename from kenaito-config-core/src/main/java/cn/odboy/config/netty/ConfigCenterClient.java rename to kenaito-config-core/src/main/java/cn/odboy/config/netty/ConfigClient.java index 8dac3a3..a66b8df 100644 --- a/kenaito-config-core/src/main/java/cn/odboy/config/netty/ConfigCenterClient.java +++ b/kenaito-config-core/src/main/java/cn/odboy/config/netty/ConfigClient.java @@ -1,5 +1,4 @@ package cn.odboy.config.netty; -import cn.odboy.config.ConfigCenterProperties; import io.netty.bootstrap.Bootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; @@ -11,7 +10,7 @@ import io.netty.channel.socket.nio.NioSocketChannel; import lombok.extern.slf4j.Slf4j; @Slf4j -public class ConfigCenterClient { +public class ConfigClient { public void start(String server, Integer port) throws InterruptedException { EventLoopGroup group = new NioEventLoopGroup(); try { @@ -21,7 +20,7 @@ public class ConfigCenterClient { @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); - pipeline.addLast(new ConfigCenterClientHandler()); + pipeline.addLast(new ConfigClientHandler()); } }); log.info("Netty Client Start..."); diff --git a/kenaito-config-core/src/main/java/cn/odboy/config/netty/ConfigClientHandler.java b/kenaito-config-core/src/main/java/cn/odboy/config/netty/ConfigClientHandler.java new file mode 100644 index 0000000..0e43130 --- /dev/null +++ b/kenaito-config-core/src/main/java/cn/odboy/config/netty/ConfigClientHandler.java @@ -0,0 +1,41 @@ +package cn.odboy.config.netty; + +import cn.odboy.config.model.ConfigKv; +import cn.odboy.config.util.ProtostuffUtil; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +public class ConfigClientHandler extends ChannelInboundHandlerAdapter { + @Override + public void channelRegistered(ChannelHandlerContext ctx) throws Exception { + System.err.println("当Channel已经注册到它的EventLoop并且能够处理I/O时被调用"); + } + + @Override + public void channelUnregistered(ChannelHandlerContext ctx) throws Exception { + System.err.println("当Channel从它的EventLoop注销并且无法处理任何I/O时被调用"); + } + + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + System.err.println("当Channel处于活动状态(已经连接到它的远程节点)时被调用"); + System.err.println("MyClientHandler发送数据"); + //ctx.writeAndFlush("测试String编解码"); + // 测试对象编解码 + //ctx.writeAndFlush(new ConfigKv("app.config", "张三")); + // 测试用protostuff对对象编解码 + ByteBuf buf = Unpooled.copiedBuffer(ProtostuffUtil.serializer(new ConfigKv("app.config", "张三"))); + ctx.writeAndFlush(buf); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + System.err.println("当Channel离开活动状态并且不再连接到它的远程节点时被调用"); + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + System.err.println("收到服务器消息:" + msg); + } +} diff --git a/kenaito-config-demo/src/main/resources/config/application-daily.yml b/kenaito-config-demo/src/main/resources/config/application-daily.yml index 0116afc..e06a223 100644 --- a/kenaito-config-demo/src/main/resources/config/application-daily.yml +++ b/kenaito-config-demo/src/main/resources/config/application-daily.yml @@ -2,6 +2,6 @@ kenaito: config-center: server: 127.0.0.1 port: 28002 - data-id: kenaito-config-service + data-id: kenaito-config-demo cache-dir: c:\\data env: daily \ No newline at end of file diff --git a/kenaito-config-demo/src/main/resources/config/application-production.yml b/kenaito-config-demo/src/main/resources/config/application-production.yml index f287a61..a76488e 100644 --- a/kenaito-config-demo/src/main/resources/config/application-production.yml +++ b/kenaito-config-demo/src/main/resources/config/application-production.yml @@ -2,6 +2,6 @@ kenaito: config-center: server: 127.0.0.1 port: 28002 - data-id: kenaito-config-service + data-id: kenaito-config-demo cache-dir: /home/admin/data env: production \ No newline at end of file diff --git a/kenaito-config-demo/src/main/resources/config/application-stage.yml b/kenaito-config-demo/src/main/resources/config/application-stage.yml index 27d1273..f8954ea 100644 --- a/kenaito-config-demo/src/main/resources/config/application-stage.yml +++ b/kenaito-config-demo/src/main/resources/config/application-stage.yml @@ -2,6 +2,6 @@ kenaito: config-center: server: 127.0.0.1 port: 28002 - data-id: kenaito-config-service + data-id: kenaito-config-demo cache-dir: /home/admin/data env: stage \ No newline at end of file diff --git a/kenaito-config-service/src/main/java/cn/odboy/infra/netty/ConfigServerHandler.java b/kenaito-config-service/src/main/java/cn/odboy/infra/netty/ConfigServerHandler.java index 8c5ec83..489809e 100644 --- a/kenaito-config-service/src/main/java/cn/odboy/infra/netty/ConfigServerHandler.java +++ b/kenaito-config-service/src/main/java/cn/odboy/infra/netty/ConfigServerHandler.java @@ -7,15 +7,17 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; public class ConfigServerHandler extends ChannelInboundHandlerAdapter { + @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + System.err.println("当从Channel读取数据时被调用"); //System.out.println("从客户端读取到String:" + msg.toString()); //System.out.println("从客户端读取到Object:" + ((User)msg).toString()); //测试用protostuff对对象编解码 ByteBuf buf = (ByteBuf) msg; byte[] bytes = new byte[buf.readableBytes()]; buf.readBytes(bytes); - System.out.println("从客户端读取到Object:" + ProtostuffUtil.deserializer(bytes, ConfigKv.class)); + System.err.println("从客户端读取到Object:" + ProtostuffUtil.deserializer(bytes, ConfigKv.class)); } @Override