一、eureka服务端自动配置
所有文章
https://www.cnblogs.com/lay2017/p/11908715.html
正文
@EnableEurekaServer开关
eureka是一个c/s架构的服务治理框架,springcloud将其集成用作服务治理。springcloud使用eureka比较简单,只需要引入依赖以后添加一个@EnableEurekaServer注解即可,如
@SpringBootApplication @EnableEurekaServer public class EurekaApplication { public static void main(String[] args) { SpringApplication.run(EurekaApplication.class, args); } }
@EnableEurekaServer又有什么魔力呢?为什么它能够开关EurekaServer?为此,我们打开@EnableEurekaServer注解
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(EurekaServerMarkerConfiguration.class) public @interface EnableEurekaServer { }
可以看到,@EnableEurekaServer的@Import注解导入了一个EurekaServerMarkerConfiguration类。所以,开启@EnableEurekaServer注解也就是导入该类。
那么,EurekaServerMarkerConfiguration这个配置类又做了啥?
@Configuration public class EurekaServerMarkerConfiguration { @Bean public Marker eurekaServerMarkerBean() { return new Marker(); } class Marker { } }
可以看到,这里只是把一个空的Marker类变成了spring中的Bean。而Marker本身什么功能都没有实现。顾名思义,我们可以这样猜测一下:@EnableEurekaServer注解就是将Marker配置为Bean,而Marker作为Bean的存在,将会触发自动配置,从而达到了一个开关的效果。
EurekaServerAutoConfiguration自动配置类
我们再打开EurekaServerAutoConfiguration这个自动配置类
@Configuration @Import(EurekaServerInitializerConfiguration.class) @ConditionalOnBean(EurekaServerMarkerConfiguration.Marker.class) @EnableConfigurationProperties({ EurekaDashboardProperties.class, InstanceRegistryProperties.class }) @PropertySource("classpath:/eureka/server.properties") public class EurekaServerAutoConfiguration implements WebMvcConfigurer { // ...... }
首先值得注意的是@ConditionalOnBean这个注解,它将判断EurekaServerMarkerConfiguration.Marker这个Bean是否存在。如果存在才会解析这个自动配置类,从而呼应了@EnableEurekaServer这个注解的功能。
@EnableConfigurationProperties注解和@PropertySource注解都加载了一些键值对的属性。
@Import导入了一个初始化类EurekaServerInitializerConfiguration(后面再看它)
EurekaServerAutoConfiguration作为自动配置类,我们看看它主要配置了哪些东西(有所忽略)
看板
服务治理少不了需要一个DashBoard来可视化监控,EurekaController基于springmvc提供DashBoard相关的功能。
@Bean @ConditionalOnProperty(prefix = "eureka.dashboard", name = "enabled", matchIfMissing = true) public EurekaController eurekaController() { return new EurekaController(this.applicationInfoManager); }
发现注册
发现注册作为主要的核心功能,也是必不可少的
@Bean public PeerAwareInstanceRegistry peerAwareInstanceRegistry( ServerCodecs serverCodecs) { this.eurekaClient.getApplications(); // force initialization return new InstanceRegistry(this.eurekaServerConfig, this.eurekaClientConfig, serverCodecs, this.eurekaClient, this.instanceRegistryProperties.getExpectedNumberOfClientsSendingRenews(), this.instanceRegistryProperties.getDefaultOpenForTrafficCount()); }
启动引导
@Bean public EurekaServerBootstrap eurekaServerBootstrap(PeerAwareInstanceRegistry registry, EurekaServerContext serverContext) { return new EurekaServerBootstrap(this.applicationInfoManager, this.eurekaClientConfig, this.eurekaServerConfig, registry, serverContext); }
Jersey提供rpc调用
jersey是一个restful风格的基于http的rpc调用框架,eureka使用它来为客户端提供远程服务。
@Bean public javax.ws.rs.core.Application jerseyApplication(Environment environment, ResourceLoader resourceLoader) { ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider( false, environment); // Filter to include only classes that have a particular annotation. // provider.addIncludeFilter(new AnnotationTypeFilter(Path.class)); provider.addIncludeFilter(new AnnotationTypeFilter(Provider.class)); // Find classes in Eureka packages (or subpackages) // Set<Class<?>> classes = new HashSet<>(); for (String basePackage : EUREKA_PACKAGES) { Set<BeanDefinition> beans = provider.findCandidateComponents(basePackage); for (BeanDefinition bd : beans) { Class<?> cls = ClassUtils.resolveClassName(bd.getBeanClassName(), resourceLoader.getClassLoader()); classes.add(cls); } } // Construct the Jersey ResourceConfig Map<String, Object> propsAndFeatures = new HashMap<>(); propsAndFeatures.put( // Skip static content used by the webapp ServletContainer.PROPERTY_WEB_PAGE_CONTENT_REGEX, EurekaConstants.DEFAULT_PREFIX + "/(fonts|images|css|js)/.*"); DefaultResourceConfig rc = new DefaultResourceConfig(classes); rc.setPropertiesAndFeatures(propsAndFeatures); return rc; }
这里将会扫描Resource,并添加到ResourceConfig当中。
EurekaServerInitializerConfiguration初始化
再回过头来,看看@EnableEurekaServer注解导入的EurekaServerInitializerConfiguration类。
@Configuration public class EurekaServerInitializerConfiguration implements ServletContextAware, SmartLifecycle, Ordered { // ... @Override public void start() { new Thread(() -> { try { eurekaServerBootstrap.contextInitialized(EurekaServerInitializerConfiguration.this.servletContext); publish(new EurekaRegistryAvailableEvent(getEurekaServerConfig())); EurekaServerInitializerConfiguration.this.running = true; publish(new EurekaServerStartedEvent(getEurekaServerConfig())); } catch (Exception ex) { // } }).start(); } }
初始化过程调用了EurekaServerBootstrap的contextInitialized方法,我们跟进看看
public void contextInitialized(ServletContext context) { try { initEurekaEnvironment(); initEurekaServerContext(); context.setAttribute(EurekaServerContext.class.getName(), this.serverContext); } catch (Throwable e) { log.error("Cannot bootstrap eureka server :", e); throw new RuntimeException("Cannot bootstrap eureka server :", e); } }
这里初始化了EurekaEnvironment和EurekaServerContext,EurekaEnvironment无非就是设置了各种配置之类的东西。我们打开initEurekaServerContext看看
protected void initEurekaServerContext() throws Exception { // ...... // Copy registry from neighboring eureka node int registryCount = this.registry.syncUp(); this.registry.openForTraffic(this.applicationInfoManager, registryCount); // Register all monitoring statistics. EurekaMonitors.registerAllStats(); }
这里主要做了两件事:
1)从相邻的集群节点当中同步注册信息
2)注册一个统计器
总结
@EnableEurekaServer注解开启了EurekaServerAutoConfiguration这个配置类的解析,EurekaServerAutoConfiguration这个配置了主要准备了看板、注册发现、启动引导、Jersey等,EurekaServerInitializerConfigration将会触发启动引导,引导过程会从其它Eureka集群节点当中同步注册信息。