• Eureka服务端启动源码分析


    一、引言

      在我们使用Spring Cloud微服务开发的时候,一般采用Springboot框架,然后eureka服务端需要加一个注解@EnableEurekaServer,就从这个注解来解析eureka的源码。

    二、@EnableEurekaServer

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Import(EurekaServerMarkerConfiguration.class)
    public @interface EnableEurekaServer {
    
    }

    引入了一个配置类EurekaServerMarkerConfiguration

    @Configuration(proxyBeanMethods = false)
    public class EurekaServerMarkerConfiguration {
    
        @Bean
        public Marker eurekaServerMarkerBean() {
            return new Marker();
        }
    
        class Marker {
    
        }
    
    }

    注册了一个null的bean!!!

    三、自动装配

      注解上没有看出什么,接着看一下Springboot的自动装配的配置文件spring.factories

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
      org.springframework.cloud.netflix.eureka.server.EurekaServerAutoConfiguration

    在springboot启动的时候会自动加载这个配置类

    @Configuration(proxyBeanMethods = false)
    @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.class)只有Marker类存在的时候,才会自动装配。这里还引入了一个配置类EurekaServerInitializerConfiguration

    @Configuration(proxyBeanMethods = false)
    public class EurekaServerInitializerConfiguration implements ServletContextAware, SmartLifecycle, Ordered {
    
        private static final Log log = LogFactory
                .getLog(EurekaServerInitializerConfiguration.class);
    
        @Autowired
        private EurekaServerConfig eurekaServerConfig;
    
        private ServletContext servletContext;
    
        @Autowired
        private ApplicationContext applicationContext;
    
        @Autowired
        private EurekaServerBootstrap eurekaServerBootstrap;
    
        private boolean running;
    
        private int order = 1;
    
        @Override
        public void setServletContext(ServletContext servletContext) {
            this.servletContext = servletContext;
        }
    
        @Override
        public void start() {
            new Thread(() -> {
                try {
                    //启动EurekaServer
                    eurekaServerBootstrap.contextInitialized(
                            EurekaServerInitializerConfiguration.this.servletContext);
                    log.info("Started Eureka Server");
                    //发布可注册事件
                    publish(new EurekaRegistryAvailableEvent(getEurekaServerConfig()));
                    EurekaServerInitializerConfiguration.this.running = true;
                    //发布已启动事件
                    publish(new EurekaServerStartedEvent(getEurekaServerConfig()));
                }
                catch (Exception ex) {
                    // Help!
                    log.error("Could not initialize Eureka servlet context", ex);
                }
            }).start();
        }
    
        private EurekaServerConfig getEurekaServerConfig() {
            return this.eurekaServerConfig;
        }
    
        private void publish(ApplicationEvent event) {
            this.applicationContext.publishEvent(event);
        }
    
        @Override
        public void stop() {
            this.running = false;
            eurekaServerBootstrap.contextDestroyed(this.servletContext);
        }
    
        @Override
        public boolean isRunning() {
            return this.running;
        }
        
        //调用顺序,越小越靠前
        @Override
        public int getPhase() {
            return 0;
        }
    
        @Override
        public boolean isAutoStartup() {
            return true;
        }
    
        @Override
        public void stop(Runnable callback) {
            callback.run();
        }
    
        @Override
        public int getOrder() {
            return this.order;
        }
    
    }

    实现了SmartLifecycle类,那么在spring启动的时候,会调用start方法,关闭时会调用stop方法

    1、启动eureka

        public void contextInitialized(ServletContext context) {
            try {
                //初始化执行环境
                initEurekaEnvironment();
                //初始化上下文
                initEurekaServerContext();
                
                context.setAttribute(EurekaServerContext.class.getName(), this.serverContext);
            }
            catch (Throwable e) {
                ···
            }
        }

    看一下核心方法初始化上下文

        protected void initEurekaServerContext() throws Exception {
            // 设置json与xml序列化工具
            JsonXStream.getInstance().registerConverter(new V1AwareInstanceInfoConverter(),
                    XStream.PRIORITY_VERY_HIGH);
            XmlXStream.getInstance().registerConverter(new V1AwareInstanceInfoConverter(),
                    XStream.PRIORITY_VERY_HIGH);
    
            if (isAws(this.applicationInfoManager.getInfo())) {
                this.awsBinder = new AwsBinderDelegate(this.eurekaServerConfig,
                        this.eurekaClientConfig, this.registry, this.applicationInfoManager);
                this.awsBinder.start();
            }
            //初始化eureka上下文包装类
            EurekaServerContextHolder.initialize(this.serverContext);
    
            log.info("Initialized server context");
    
            // 同步Eureka集群数据,每一个eureka服务端对于其他服务端来说,都是客户端
            int registryCount = this.registry.syncUp();
         // 更改实例状态,对外提供服务,开启一个定时器,每60秒进行一次服务检测(判断是否剔除)
    this.registry.openForTraffic(this.applicationInfoManager, registryCount); // 注册监控统计信息 EurekaMonitors.registerAllStats(); }

    同步集群注册信息

     public int syncUp() {
    
            int count = 0;
            //serverConfig.getRegistrySyncRetries()获取重试次数
            for (int i = 0; ((i < serverConfig.getRegistrySyncRetries()) && (count == 0)); i++) {
                if (i > 0) {
                    try {
                        Thread.sleep(serverConfig.getRegistrySyncRetryWaitMs());
                    } catch (InterruptedException e) {
                        logger.warn("Interrupted during registry transfer..");
                        break;
                    }
                }
                //获取其他server的注册表信息
                Applications apps = eurekaClient.getApplications();
                for (Application app : apps.getRegisteredApplications()) {
                    for (InstanceInfo instance : app.getInstances()) {
                        try {
                            if (isRegisterable(instance)) {
                                //把从远程获取到的注册信息,注册到自己的注册表中(map)
                                register(instance, instance.getLeaseInfo().getDurationInSecs(), true);
                                count++;
                            }
                        } catch (Throwable t) {
                            logger.error("During DS init copy", t);
                        }
                    }
                }
            }
            return count;
        }

    2、发布EurekaRegistryAvailableEvent事件

      我们可以自己实现一个监听器,监听eureka的可注册事件,并且可以获得EurekaServerConfig对象,然后写自己的逻辑

    3、发布EurekaServerStartedEvent事件

      我们可以自己实现一个监听器,监听eureka的已启动事件,并且可以获得EurekaServerConfig对象,然后写自己的逻辑

    四、导入的配置

    1、@EnableConfigurationProperties({EurekaDashboardProperties.class, InstanceRegistryProperties.class})

    EurekaDashboardProperties这个类比较简单,主要是Eureka的控制台的相关配置

    //控制台默认路径
    private String path = "/";
    //是否开启控制台
    private boolean enabled = true;

    InstanceRegistryProperties,这个类是控制Eureka的注册时的配置信息

       //每分钟续约次数
        @Value("${eureka.server.expectedNumberOfRenewsPerMin:1}") 
        private int expectedNumberOfRenewsPerMin = 1;
        //默认打开的通信数量
        @Value("${eureka.server.defaultOpenForTrafficCount:1}")
        private int defaultOpenForTrafficCount = 1;

    @PropertySource("classpath:/eureka/server.properties")

    加载配置文件

    spring.http.encoding.force=false

    五、配置类EurekaServerAutoConfiguration的@Bean

    eureka监控面板的controller,可以添加配置eureka.dashboard.enabled = false,去除管理界面

        @Bean
        @ConditionalOnProperty(prefix = "eureka.dashboard", name = "enabled",
                matchIfMissing = true)
        public EurekaController eurekaController() {
            return new EurekaController(this.applicationInfoManager);
        }

    设置eureka的序列化工具

        @Bean
        public ServerCodecs serverCodecs() {
            return new CloudServerCodecs(this.eurekaServerConfig);
        }

    实例化服务注册核心类

        @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());
        }

    实例化PeerEurekaNodes节点的子类RefreshablePeerEurekaNodes,封装对等节点的相关信息和操作,实现了ApplicationListener<EnvironmentChangeEvent> 监听器,监听EnvironmentChangeEvent事件,比如:更新集群中的节点

        @Bean
        @ConditionalOnMissingBean
        public PeerEurekaNodes peerEurekaNodes(PeerAwareInstanceRegistry registry,
                ServerCodecs serverCodecs,
                ReplicationClientAdditionalFilters replicationClientAdditionalFilters) {
            return new RefreshablePeerEurekaNodes(registry, this.eurekaServerConfig,
                    this.eurekaClientConfig, serverCodecs, this.applicationInfoManager,
                    replicationClientAdditionalFilters);
        }

    注入EurekaServer上下文DefaultEurekaServerContext

        @Bean
        @ConditionalOnMissingBean
        public EurekaServerContext eurekaServerContext(ServerCodecs serverCodecs,
                PeerAwareInstanceRegistry registry, PeerEurekaNodes peerEurekaNodes) {
            return new DefaultEurekaServerContext(this.eurekaServerConfig, serverCodecs,
                    registry, peerEurekaNodes, this.applicationInfoManager);
        }
    public class DefaultEurekaServerContext implements EurekaServerContext {
        @PostConstruct
        @Override
        public void initialize() {
            //启动一个定时线程
            peerEurekaNodes.start();
            try {
                registry.init(peerEurekaNodes);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            logger.info("Initialized");
        }
    }
    
    //PeerEurekaNodes
    public void start() {
            taskExecutor = Executors.newSingleThreadScheduledExecutor(
                    new ThreadFactory() {
                        @Override
                        public Thread newThread(Runnable r) {
                            Thread thread = new Thread(r, "Eureka-PeerNodesUpdater");
                            thread.setDaemon(true);
                            return thread;
                        }
                    }
            );
            try {
                //更新集群节点信息
                updatePeerEurekaNodes(resolvePeerUrls());
                Runnable peersUpdateTask = new Runnable() {
                    @Override
                    public void run() {
                        try {
                            updatePeerEurekaNodes(resolvePeerUrls());
                        } catch (Throwable e) {
                            logger.error("Cannot update the replica Nodes", e);
                        }
    
                    }
                };
                taskExecutor.scheduleWithFixedDelay(
                        peersUpdateTask,
                        serverConfig.getPeerEurekaNodesUpdateIntervalMs(),
                        serverConfig.getPeerEurekaNodesUpdateIntervalMs(),
                        TimeUnit.MILLISECONDS
                );
            } catch (Exception e) {
                throw new IllegalStateException(e);
            }
            for (PeerEurekaNode node : peerEurekaNodes) {
                logger.info("Replica node URL:  {}", node.getServiceUrl());
            }
        }

    注入EurekaServerBootstrap,后续启动需要使用该对象

        @Bean
        public EurekaServerBootstrap eurekaServerBootstrap(PeerAwareInstanceRegistry registry,
                EurekaServerContext serverContext) {
            return new EurekaServerBootstrap(this.applicationInfoManager,
                    this.eurekaClientConfig, this.eurekaServerConfig, registry,
                    serverContext);
        }

    注册了jerseyFilter,拦截客户端的注册请求,Jersey是一个rest框架帮助我们发布restful服务接口(类似于SpringMVC)

        @Bean
        public FilterRegistrationBean<?> jerseyFilterRegistration(
                javax.ws.rs.core.Application eurekaJerseyApp) {
            FilterRegistrationBean<Filter> bean = new FilterRegistrationBean<Filter>();
            bean.setFilter(new ServletContainer(eurekaJerseyApp));
            bean.setOrder(Ordered.LOWEST_PRECEDENCE);
            bean.setUrlPatterns(
                    Collections.singletonList(EurekaConstants.DEFAULT_PREFIX + "/*"));
    
            return bean;
        }
  • 相关阅读:
    HDU 1800 Flying to the Mars 字典树,STL中的map ,哈希树
    字典树 HDU 1075 What Are You Talking About
    字典树 HDU 1251 统计难题
    最小生成树prim算法 POJ2031
    POJ 1287 Networking 最小生成树
    次小生成树 POJ 2728
    最短路N题Tram SPFA
    poj2236 并查集
    POJ 1611并查集
    Number Sequence
  • 原文地址:https://www.cnblogs.com/sglx/p/15702318.html
Copyright © 2020-2023  润新知