本系列为之前系列的整理重启版,随着项目的发展以及项目中的使用,之前系列里面很多东西发生了变化,并且还有一些东西之前系列并没有提到,所以重启这个系列重新整理下,欢迎各位留言交流,谢谢!~
spring-cloud-commons 中参考了 spring-cloud-netflix 的设计,引入了 NamedContextFactory 机制,一般用于对于不同微服务的客户端模块使用不同的 子 ApplicationContext 进行配置。
spring-cloud-commons 是 Spring Cloud 对于微服务基础组件的抽象。在一个微服务中,调用微服务 A 与调用微服务 B 的配置可能不同。比较简单的例子就是,A 微服务是一个简单的用户订单查询服务,接口返回速度很快,B 是一个报表微服务,接口返回速度比较慢。这样的话我们就不能对于调用微服务 A 和微服务 B 使用相同的超时时间配置。还有就是,我们可能对于服务 A 通过注册中心进行发现,对于服务 B 则是通过 DNS 解析进行服务发现,所以对于不同的微服务我们可能使用不同的组件,在 Spring 中就是使用不同类型的 Bean。
在这种需求下,不同微服务的客户端有不同的以及相同的配置,有不同的 Bean,也有相同的 Bean。所以,我们可以针对每一个微服务将他们的 Bean 所处于 ApplicationContext 独立开来,不同微服务客户端使用不同的 ApplicationContext。NamedContextFactory 就是用来实现这种机制的。
编写源码:
package com.github.hashjang.spring.cloud.iiford.service.common; import org.junit.Assert; import org.junit.Test; import org.springframework.cloud.context.named.NamedContextFactory; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; import java.util.List; import java.util.Objects; public class CommonNameContextTest { private static final String PROPERTY_NAME = "test.context.name"; @Test public void test() { //创建 parent context AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext(); //添加 BaseConfig 相关配置 parent.register(BaseConfig.class); //初始化 parent parent.refresh(); //创建 testClient1,默认配置使用 ClientCommonConfig TestClient testClient1 = new TestClient(ClientCommonConfig.class); //创建 service1 与 service2 以及指定对应额外的配置类 TestSpec testSpec1 = new TestSpec("service1", new Class[]{Service1Config1.class, Service1Config2.class}); TestSpec testSpec2 = new TestSpec("service2", new Class[]{Service2Config.class}); //设置 parent ApplicationContext 为 parent testClient1.setApplicationContext(parent); //将 service1 与 service2 的配置加入 testClient1 testClient1.setConfigurations(List.of(testSpec1, testSpec2)); BaseBean baseBean = testClient1.getInstance("service1", BaseBean.class); System.out.println(baseBean); //验证正常获取到了 baseBean Assert.assertNotNull(baseBean); ClientCommonBean commonBean = testClient1.getInstance("service1", ClientCommonBean.class); System.out.println(commonBean); //验证正常获取到了 commonBean Assert.assertNotNull(commonBean); Service1Bean1 service1Bean1 = testClient1.getInstance("service1", Service1Bean1.class); System.out.println(service1Bean1); //验证正常获取到了 service1Bean1 Assert.assertNotNull(service1Bean1); Service1Bean2 service1Bean2 = testClient1.getInstance("service1", Service1Bean2.class); System.out.println(service1Bean2); //验证正常获取到了 service1Bean2 Assert.assertNotNull(service1Bean2); BaseBean baseBean2 = testClient1.getInstance("service2", BaseBean.class); System.out.println(baseBean2); //验证正常获取到了 baseBean2 并且 baseBean2 就是 baseBean Assert.assertEquals(baseBean, baseBean2); ClientCommonBean commonBean2 = testClient1.getInstance("service2", ClientCommonBean.class); System.out.println(commonBean2); //验证正常获取到了 commonBean2 并且 commonBean 和 commonBean2 不是同一个 Assert.assertNotNull(commonBean2); Assert.assertNotEquals(commonBean, commonBean2); Service2Bean service2Bean = testClient1.getInstance("service2", Service2Bean.class); System.out.println(service2Bean); //验证正常获取到了 service2Bean Assert.assertNotNull(service2Bean); } @Configuration(proxyBeanMethods = false) static class BaseConfig { @Bean BaseBean baseBean() { return new BaseBean(); } } static class BaseBean {} @Configuration(proxyBeanMethods = false) static class ClientCommonConfig { @Bean ClientCommonBean clientCommonBean(Environment environment, BaseBean baseBean) { //在创建 NamedContextFactory 里面的子 ApplicationContext 的时候,会指定 name,这个 name 对应的属性 key 即 PROPERTY_NAME return new ClientCommonBean(environment.getProperty(PROPERTY_NAME), baseBean); } } static class ClientCommonBean { private final String name; private final BaseBean baseBean; ClientCommonBean(String name, BaseBean baseBean) { this.name = name; this.baseBean = baseBean; } @Override public String toString() { return "ClientCommonBean{" + "name='" + name + '\'' + ", baseBean=" + baseBean + '}'; } } @Configuration(proxyBeanMethods = false) static class Service1Config1 { @Bean Service1Bean1 service1Bean1(ClientCommonBean clientCommonBean) { return new Service1Bean1(clientCommonBean); } } static class Service1Bean1 { private final ClientCommonBean clientCommonBean; Service1Bean1(ClientCommonBean clientCommonBean) { this.clientCommonBean = clientCommonBean; } @Override public String toString() { return "Service1Bean1{" + "clientCommonBean=" + clientCommonBean + '}'; } } @Configuration(proxyBeanMethods = false) static class Service1Config2 { @Bean Service1Bean2 service1Bean2() { return new Service1Bean2(); } } static class Service1Bean2 { } @Configuration(proxyBeanMethods = false) static class Service2Config { @Bean Service2Bean service2Bean(ClientCommonBean clientCommonBean) { return new Service2Bean(clientCommonBean); } } static class Service2Bean { private final ClientCommonBean clientCommonBean; Service2Bean(ClientCommonBean clientCommonBean) { this.clientCommonBean = clientCommonBean; } @Override public String toString() { return "Service2Bean{" + "clientCommonBean=" + clientCommonBean + '}'; } } static class TestSpec implements NamedContextFactory.Specification { private final String name; private final Class<?>[] configurations; public TestSpec(String name, Class<?>[] configurations) { this.name = name; this.configurations = configurations; } @Override public String getName() { return name; } @Override public Class<?>[] getConfiguration() { return configurations; } } static class TestClient extends NamedContextFactory<TestSpec> { public TestClient(Class<?> defaultConfigType) { super(defaultConfigType, "testClient", PROPERTY_NAME); } } }