继上一篇文章阐述《Eureka在微服务架构中的重要性》之后,今天我们来探讨下基于springboot开发的微服务,在启动过程中是如何加载eureka的。
无论是启动类Main或者Application,通常都会带有@SpringbootCloudApplication或者@SpringBootApplication注解。
接下来,我们先来看下这两个注解的区别。
@SpringCloudApplication
@Target(ElementType.TYPE) // 指定此注解只能应用于类或接口上。
@Retention(RetentionPolicy.RUNTIME) // 表示此注解在运行时仍然有效
@Documented // 表明此注解会被包含在Javadoc文档中
@Inherited // 子类可以继承父类上的该注解
@SpringBootApplication
@EnableDiscoveryClient // 启用服务发现客户端功能,使应用能够注册到服务发现服务器中。
@EnableCircuitBreaker // 启用Hystrix断路器功能,用于处理服务间的依赖故障。
public @interface SpringCloudApplication {
}
@SpringBootApplication
@Target(ElementType.TYPE) // 指定此注解只能应用于类或接口上。
@Retention(RetentionPolicy.RUNTIME) // 表示此注解在运行时仍然有效
@Documented // 表明此注解会被包含在Javadoc文档中
@Inherited // 子类可以继承父类上的该注解
@SpringBootConfiguration // 标记该类为Spring Boot配置类
@EnableAutoConfiguration //
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) // 指定Spring扫描的包范围,同时派出一些特定的组件
public @interface SpringBootApplication {
……
}
@SpringbootCloudApplication引用了@SpringBootApplication,而@SpringBootApplication组合了@SpringBootConfiguration、@EnableAutoConfiguration和@ComponentScan,用于启动Spring Boot应用。
同时@SpringbootCloudApplication包含了@EnableDiscoveryClient,使得该应用能够注册到Eureka中。
总结下,@SpringbootCloudApplication = @SpringBootApplication + @EnableDiscoveryClient+@EnableCircuitBreaker(这个注解后续会单独出一篇文章聊聊,本次先忽略)
这两种方式都可以扫描到Eureka客户端的配置类,并且使该应用能够注册到Eureka服务端当中。
那么,Eureka客户端相关的配置类又是怎样被加载到IOC容器中的呢?@EnableAutoConfiguration注解承担了这项任务。
下面,我们来看看@EnableAutoConfiguration具体是如何找到Eureka客户端相关的配置类,并将其加载到Spring容器中的。
@EnableAutoConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage // 自动将当前类所在的包添加到自动配置组件的扫描范围内
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
……
}
该注解会导入AutoConfigurationImportSelector类,该类负责选择并导入自动配置类。
我们以Eureka客户端为例,来详细说明它是如何工作的。
核心方法:
1. selectImports(AnnotationMetadata annotationMetadata)方法:
- 作用: 根据类路径中的依赖选择并返回需要导入的自动配置类的全限定名列表。
- 实现: 在 AutoConfigurationImportSelector 中,该方法会通过getAutoConfigurationEntry(annotationMetadata)方法调用 getCandidateConfigurations 方法来获取候选配置类。
2. getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) 方法:
- 作用: 获取候选配置类的列表。
- 实现: 该方法会调用 SpringFactoriesLoader.loadFactoryNames 方法从 spring.factories 文件中加载自动配置类。
3. SpringFactoriesLoader.loadFactoryNames 方法:
- 作用: 从所有Jar包的META-INF/spring-factories文件中加载指定类型的工厂类名称。
- 实现: 遍历 spring.factories 文件中 org.springframework.boot.autoconfigure.EnableAutoConfiguration 下的所有项,找到与当前环境匹配的自动配置类。
以下是spring-cloud-netflix-eureka-client-2.2.6.RELEASE.jar的META-INF/spring-factories文件(key是能够自配配置的注解,value是逗号分隔的具体的实现类)。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.netflix.eureka.config.EurekaClientConfigServerAutoConfiguration,\
org.springframework.cloud.netflix.eureka.config.DiscoveryClientOptionalArgsConfiguration,\
org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration,\
org.springframework.cloud.netflix.ribbon.eureka.RibbonEurekaAutoConfiguration,\
org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration,\
org.springframework.cloud.netflix.eureka.reactive.EurekaReactiveDiscoveryClientConfiguration,\
org.springframework.cloud.netflix.eureka.loadbalancer.LoadBalancerEurekaAutoConfiguration
通过方法2拿到这些配置之后,会把重复的和exclude的配置项剔除,最后返回配置类的列表。
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
configurations = this.removeDuplicates(configurations);
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
通过这种方式,@EnableAutoConfiguration 和 AutoConfigurationImportSelector 一起工作,实现了Eureka客户端的自动配置功能。