所有文章
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集群節點當中同步注冊信息。