您当前的位置: 首页 >  eureka

七.SpringCloud源码剖析-Eureka Server的自动配置

发布时间:2020-09-09 22:49:06 ,浏览量:8

系列文章目录

一.SpringCloud源码剖析-Eureka核心API

二.SpringCloud源码剖析-Eureka Client 初始化过程

三.SpringCloud源码剖析-Eureka服务注册

四.SpringCloud源码剖析-Eureka服务发现

五.SpringCloud源码剖析-Eureka Client服务续约

六.SpringCloud源码剖析-Eureka Client取消注册

七.SpringCloud源码剖析-Eureka Server的自动配置

八.SpringCloud源码剖析-Eureka Server初始化流程

九.SpringCloud源码剖析-Eureka Server服务注册流程

十.SpringCloud源码剖析-Eureka Server服务续约

十一.SpringCloud源码剖析-Eureka Server服务注册表拉取

十二.SpringCloud源码剖析-Eureka Server服务剔除

十三.SpringCloud源码剖析-Eureka Server服务下线

前言 前面的章节我们针对于Eureak Client的初始化 ,服务注册 ,服务发现,服务续约,取消注册功能进行了分析,接下来我们围绕Eureka的核心功能对Server端进行分析,本章将会分析Eureka Server的启动过程。 1.EureakServerAutoConfiguration的注册

这里和EureakClientAutoConfiguration差不多,都是由主启动类上的@SpringBootApplication标签中的@EnableAutoConfiguration启动自动配置,通过AutoConfigurationImportSelector来扫描classpath下的starter包中的自动配置类

@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration @EnableAutoConfiguration //开启自动配置 @ComponentScan( excludeFilters = {@Filter( type = FilterType.CUSTOM, classes = {TypeExcludeFilter.class} ), @Filter( type = FilterType.CUSTOM, classes = {AutoConfigurationExcludeFilter.class} )} ) public @interface SpringBootApplication { 

@EnableAutoConfiguration标签的源码

@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import({AutoConfigurationImportSelector.class}) //自动配置选择器 public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; Class<?>[] exclude() default {}; String[] excludeName() default {}; } 

AutoConfigurationImportSelector导入选择器源码

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered { ...省略部分代码... @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader .loadMetadata(this.beanClassLoader); AnnotationAttributes attributes = getAttributes(annotationMetadata); //1.这里会扫描spring.factories文件中的配置 List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); configurations = removeDuplicates(configurations); Set<String> exclusions = getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); configurations = filter(configurations, autoConfigurationMetadata); fireAutoConfigurationImportEvents(configurations, exclusions); //2.加载一堆自动配置,其中就有 EureakServerAutoConfiguration  return StringUtils.toStringArray(configurations); } //获取候选的自动配置 protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { //通过SpringFactoriesLoader加载spring.spring.factories中的配置类 List<String> configurations = SpringFactoriesLoader.loadFactoryNames( getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()); Assert.notEmpty(configurations, //从错误日志就可以看得出在扫描 META-INF/spring.factories "No auto configuration classes found in META-INF/spring.factories. If you " + "are using a custom packaging, make sure that file is correct."); return configurations; } 

在这里插入图片描述

这里的selectImports方法会通过getCandidateConfigurations方法使用SpringFactoriesLoader去加载classpath下的jar中的META-INF/spring.factories文件,该文件中有很多的自动配置,其中EureakServerAutoConfiguration就在spring-cloud-netflix-eureka-server-2.0.1.RELEASE.jar中如下 在这里插入图片描述

2.EureakServerAutoConfiguration被加载的条件

在EureakServerAutoConfiguration自动配置类上有一个注册条件

/**
 * @author Gunnar Hillert
 * @author Biju Kunjummen
 * @author Fahim Farook
 */ @Configuration //导入 EurekaServerInitializerConfiguration 对Eureak进行初始化 @Import(EurekaServerInitializerConfiguration.class) //条件:EurekaServerMarkerConfiguration.Marker是通过@EnableEureakServer激活 @ConditionalOnBean(EurekaServerMarkerConfiguration.Marker.class) //Eureka仪表盘界面配置,以及实例注册的配置 @EnableConfigurationProperties({ EurekaDashboardProperties.class, InstanceRegistryProperties.class }) //加载server.properties 服务端配置文件 @PropertySource("classpath:/eureka/server.properties") public class EurekaServerAutoConfiguration extends WebMvcConfigurerAdapter { 

@ConditionalOnBean(EurekaServerMarkerConfiguration.Marker.class)这个条件是通过@EnableEureakServer开启,

/**
	激活 EurekaServerAutoConfiguration
 * Annotation to activate Eureka Server related configuration {@link EurekaServerAutoConfiguration}
 *
 * @author Dave Syer
 * @author Biju Kunjummen
 *
 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(EurekaServerMarkerConfiguration.class) public @interface EnableEurekaServer { } 

EnableEurekaServer的注释写的很清楚,该注解用来激活EureakServerAutoConfiguration配置,通过@Import(EurekaServerMarkerConfiguration.class)来激活的

/**
 * Responsible for adding in a marker bean to activate
 * {@link EurekaServerAutoConfiguration}
 *
 * @author Biju Kunjummen
 */ @Configuration public class EurekaServerMarkerConfiguration { @Bean public Marker eurekaServerMarkerBean() { return new Marker(); } class Marker { } } 

看到这里就清楚了,EnableEurekaServer通过@Import(EurekaServerMarkerConfiguration.class)导入EurekaServerMarkerConfiguration.Marker,而在EureakServerAutoConfiguration配置类上正好有一个条件 @ConditionalOnBean(EurekaServerMarkerConfiguration.Marker.class),满足这个条件,自动配置被加载,他们的加载关系如下:

在这里插入图片描述

3.EureakServerAutoConfiguration配置了什么?

EureakServerAutoConfiguration配置了那些东西?我们来看一下源码,哦~~~,特别说明一下,服务端的pom我用的是spring-cloud-starter-netflix-eureka-server,该依赖会把客户端的包spring-cloud-starter-netflix-eureka-client也导入进来(Eureka集群需要互相注册),所以你会看到下面的配置类中也会有eureka client的配置

/**
 * @author Gunnar Hillert
 * @author Biju Kunjummen
 * @author Fahim Farook
 */ @Configuration //导入 EurekaServerInitializerConfiguration 对Eureak进行初始化 @Import(EurekaServerInitializerConfiguration.class) //条件:EurekaServerMarkerConfiguration.Marker是通过@EnableEureakServer激活 @ConditionalOnBean(EurekaServerMarkerConfiguration.Marker.class) //Eureka仪表盘界面配置,以及实例注册的配置 @EnableConfigurationProperties({ EurekaDashboardProperties.class, InstanceRegistryProperties.class }) //加载server.properties 服务端配置文件 @PropertySource("classpath:/eureka/server.properties") public class EurekaServerAutoConfiguration extends WebMvcConfigurerAdapter { /**
	 * List of packages containing Jersey resources required by the Eureka server
	 */ private static final String[] EUREKA_PACKAGES = new String[] { "com.netflix.discovery", "com.netflix.eureka" }; @Autowired private ApplicationInfoManager applicationInfoManager; //eureka server服务端配置对象加载 eureka.server 开头的配置项 //里面记录了了EurekaServer所需要的配置 @Autowired private EurekaServerConfig eurekaServerConfig; //eureka client 客户端配置对象 加载eureka.client开头的配置项 @Autowired private EurekaClientConfig eurekaClientConfig; //Eureka客户端 @Autowired private EurekaClient eurekaClient; //实例注册表属性配置,加载eureka.instance.registry开头的配置 @Autowired private InstanceRegistryProperties instanceRegistryProperties; public static final CloudJacksonJson JACKSON_JSON = new CloudJacksonJson(); @Bean public HasFeatures eurekaServerFeature() { return HasFeatures.namedFeature("Eureka Server", EurekaServerAutoConfiguration.class); } //配置EurekaServerConfig ,Eureka服务器配置,加载eureka.server开头配置 @Configuration protected static class EurekaServerConfigBeanConfiguration { @Bean @ConditionalOnMissingBean public EurekaServerConfig eurekaServerConfig(EurekaClientConfig clientConfig) { EurekaServerConfigBean server = new EurekaServerConfigBean(); //如果开启了eureka.client.registerWithEureka=true 注册到Eureka if (clientConfig.shouldRegisterWithEureka()) { // Set a sensible default if we are supposed to replicate //当eureka服务器启动时尝试去获取集群里其他服务器上的注册信息的次数,默认为5 server.setRegistrySyncRetries(5); } return server; } } //定义Eureka Server dashboard仪表盘监控界面的端点,注册中心的监控界面就是在这里定义的默认是“/” @Bean @ConditionalOnProperty(prefix = "eureka.dashboard", name = "enabled", matchIfMissing = true) public EurekaController eurekaController() { return new EurekaController(this.applicationInfoManager); } static { CodecWrappers.registerWrapper(JACKSON_JSON); EurekaJacksonCodec.setInstance(JACKSON_JSON.getCodec()); } @Bean public ServerCodecs serverCodecs() { return new CloudServerCodecs(this.eurekaServerConfig); } private static CodecWrapper getFullJson(EurekaServerConfig serverConfig) { CodecWrapper codec = CodecWrappers.getCodec(serverConfig.getJsonCodecName()); return codec == null ? CodecWrappers.getCodec(JACKSON_JSON.codecName()) : codec; } private static CodecWrapper getFullXml(EurekaServerConfig serverConfig) { CodecWrapper codec = CodecWrappers.getCodec(serverConfig.getXmlCodecName()); return codec == null ? CodecWrappers.getCodec(CodecWrappers.XStreamXml.class) : codec; } class CloudServerCodecs extends DefaultServerCodecs { public CloudServerCodecs(EurekaServerConfig serverConfig) { super(getFullJson(serverConfig), CodecWrappers.getCodec(CodecWrappers.JacksonJsonMini.class), getFullXml(serverConfig), CodecWrappers.getCodec(CodecWrappers.JacksonXmlMini.class)); } } // 注册PeerAwareInstanceRegistry,应用对象注册表接口,提供了Eureka群内注册信息的同步功能。 @Bean public PeerAwareInstanceRegistry peerAwareInstanceRegistry( ServerCodecs serverCodecs) { //客户端获取注册列表,强制初始化EurekaClient this.eurekaClient.getApplications(); // force initialization //创建实例注册器InstanceRegistry,继承了PeerAwareInstanceRegistry,PeerAwareInstanceRegistryimpl的实现 return new InstanceRegistry(this.eurekaServerConfig, this.eurekaClientConfig, serverCodecs, this.eurekaClient, //期望最大每分钟续租次数 this.instanceRegistryProperties.getExpectedNumberOfRenewsPerMin(), this.instanceRegistryProperties.getDefaultOpenForTrafficCount()); } //PeerEurekaNode的工具类,用来管理PeerEurekaNode的生命周期,PeerEurekaNode表示集群中的一个节点 @Bean @ConditionalOnMissingBean public PeerEurekaNodes peerEurekaNodes(PeerAwareInstanceRegistry registry, ServerCodecs serverCodecs) { return new RefreshablePeerEurekaNodes(registry, this.eurekaServerConfig, this.eurekaClientConfig, serverCodecs, this.applicationInfoManager); } /**
	//可刷新的集群节点,通过监听EnvironmentChangeEvent环境改变事件,如果特点的配置改变如:
	//eureka.client.region,eureka.client.service-url配置改变就刷新集群中的节点信息
	 * {@link PeerEurekaNodes} which updates peers when /refresh is invoked.
	 * Peers are updated only if
	 *eureka.client.use-dns-for-fetching-service-urlsis
	 *falseand one of following properties have changed.
	 *
		

*
    *
  • eureka.client.availability-zones
  • *
  • eureka.client.region
  • *
  • eureka.client.service-url.<zone>
  • *
*/ static class RefreshablePeerEurekaNodes extends PeerEurekaNodes implements ApplicationListener<EnvironmentChangeEvent> { public RefreshablePeerEurekaNodes( final PeerAwareInstanceRegistry registry, final EurekaServerConfig serverConfig, final EurekaClientConfig clientConfig, final ServerCodecs serverCodecs, final ApplicationInfoManager applicationInfoManager) { super(registry, serverConfig, clientConfig, serverCodecs, applicationInfoManager); } //监听事件 @Override public void onApplicationEvent(final EnvironmentChangeEvent event) { //如果配置发生改变 if (shouldUpdate(event.getKeys())) { //更新集群中的节点,通过删除旧的不可用的PeerEurekaNode,创建新的副本 updatePeerEurekaNodes(resolvePeerUrls()); } } /* 检查是否需要更新节点,检查特点的配置是否有改变 * Check whether specific properties have changed. */ protected boolean shouldUpdate(final Set<String> changedKeys) { assert changedKeys != null; // if eureka.client.use-dns-for-fetching-service-urls is true, then // service-url will not be fetched from environment. if (clientConfig.shouldUseDnsForFetchingServiceUrls()) { return false; } if (changedKeys.contains("eureka.client.region")) { return true; } for (final String key : changedKeys) { // property keys are not expected to be null. if (key.startsWith("eureka.client.service-url.") || key.startsWith("eureka.client.availability-zones.")) { return true; } } return false; } } //EurekaServer的上下文对象 @Bean public EurekaServerContext eurekaServerContext(ServerCodecs serverCodecs, PeerAwareInstanceRegistry registry, PeerEurekaNodes peerEurekaNodes) { return new DefaultEurekaServerContext(this.eurekaServerConfig, serverCodecs, registry, peerEurekaNodes, this.applicationInfoManager); } //EurekaServerBootstrap :EurekaServer的启动引导 @Bean public EurekaServerBootstrap eurekaServerBootstrap(PeerAwareInstanceRegistry registry, EurekaServerContext serverContext) { return new EurekaServerBootstrap(this.applicationInfoManager, this.eurekaClientConfig, this.eurekaServerConfig, registry, serverContext); } /** 注册 Jersey filter ,通过ServletContainer处理/eureka/*请求 * Register the Jersey filter */ @Bean public FilterRegistrationBean jerseyFilterRegistration( javax.ws.rs.core.Application eurekaJerseyApp) { FilterRegistrationBean bean = new FilterRegistrationBean(); //使用ServletContainer处理 bean.setFilter(new ServletContainer(eurekaJerseyApp)); bean.setOrder(Ordered.LOWEST_PRECEDENCE); //filter的拦截url /eureka/* bean.setUrlPatterns( Collections.singletonList(EurekaConstants.DEFAULT_PREFIX + "/*")); return bean; } /** 创建用Eureka服务器所需的所有资源,构建Jersey {@link javax.ws.rs.core.Application}。 * Construct a Jersey {@link javax.ws.rs.core.Application} with all the resources * required by the Eureka server. */ @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; } @Bean public FilterRegistrationBean traceFilterRegistration( @Qualifier("httpTraceFilter") Filter filter) { FilterRegistrationBean bean = new FilterRegistrationBean(); bean.setFilter(filter); bean.setOrder(Ordered.LOWEST_PRECEDENCE - 10); return bean; } }

我们来归纳一下EurekaServerAutoConfiguration配置了那些东西

  • @Import(EurekaServerInitializerConfiguration.class):导入了EurekaServer初始化配置

  • @ConditionalOnBean(EurekaServerMarkerConfiguration.Marker.class):这个是配置起效的条件,通过@EnableEurekaServer开启该条件

  • EurekaDashboardProperties.class:仪表盘配置

  • InstanceRegistryProperties.class:以 eureka.instance.registry开头的服务注册配置

  • @PropertySource("classpath:/eureka/server.properties"):加载server.properties配置文件

  • 注册了EurekaServerConfig:Eureka服务端配置对象,eureka服务器运行所需的配置信息,实现由两个一个是EurekaServerConfigBean是netflix的实现,一个是DefaultEurekaServerConfig是Eureka的实现

  • 注册了EurekaController:仪表盘端点controller,默认的路径是“/”

  • 注册了PeerAwareInstanceRegistry应用对象注册接口,提供了eureka集群间的服务同步功能及相关操作

  • 注册了PeerEurekaNodes:集群节点PeerEurekaNode的管理类,

  • 注册了EurekaServerContext:EurekaServer的上下文对象默认实现DefaultEurekaServerContext,提供了initialize初始化和shutdown关闭方法。

  • 注册了EurekaServerBootstrap服务端启动引导,EurekaServer启动的关键

  • 注册了jersey Filter:使用ServletContainer实现功能,用来处理/eureka的请求

总结

在这里插入图片描述

  1. SpringBoot自动配置加载EurekaServerAutoConfiguration自动配置
  2. @EnableEurekaServer导入EurekaServerMarkerConfiguration.marker激活EurekaServerAutoConfiguration自动配置
  3. EurekaServerAutoConfiguration注册了一系列组件,比较重要的有EurekaServerInitializerConfiguration初始化EurekaServer配置,PeerAwareInstanceRegistry服务注册器,PeerEurekaNodes服务节PeerEurekaNode点生命周期管理工具,EurekaServerContext服务上下文,EurekaServerBootstrap EurekaServer的启动引导等等

在下一章节我们将来研究一下EurekaServer的初始化的详细过程

关注
打赏
1688896170
查看更多评论

暂无认证

  • 8浏览

    0关注

    105695博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文
立即登录/注册

微信扫码登录

0.2747s