欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

@EnableEurekaServer注解

程序员文章站 2022-04-24 18:48:59
...

@EnableEurekaServer

1.1 在项目启动类上使用@EnableEurekaServer,可以将项目作为SpringCloud中的注册中心。那么这个注解做了哪些事呢?

1.2 点进去@EnableEurekaServer 这个注解,可以看到介绍时是这样的:
Annotation to activate Eureka Server related configuration {@link EurekaServerAutoConfiguration}(**Eureka服务器相关配置EurekaServerAutoConfiguration的注释)
可以将@EnableEurekaServer 这个注解看作是一个开关,开启时,会**相关配置,会作为注册中心。同时,他又引入了EurekaServerMarkerConfiguration类。

1.3 点进去EurekaServerMarkerConfiguration这个类,可以看到介绍是这样的:
Responsible for adding in a marker bean to activate {@link EurekaServerAutoConfiguration}。(负责添加一个标记来**配置类EurekaServerAutoConfiguration)
这个类中,向容器注入了一个类EurekaServerMarkerConfiguration.Marker,作用就是**配置类。源代码是这样的:


@Configuration
public class EurekaServerMarkerConfiguration {

	@Bean
	public Marker eurekaServerMarkerBean() {
		return new Marker();
	}

	class Marker {
	}
}


1.4 下面来看配置类EurekaServerAutoConfiguration。这个类上面有三个比较重要的注释:


@Configuration
@Import(EurekaServerInitializerConfiguration.class)
@ConditionalOnBean(EurekaServerMarkerConfiguration.Marker.class)
@EnableConfigurationProperties({ EurekaDashboardProperties.class,
		InstanceRegistryProperties.class })

@Configuration注解表示这是一个配置类,通过@Bean注解声明一些注入到Spring IOC容器中的Bean。

@Import(EurekaServerInitializerConfiguration.class)注解表示它导入了EurekaServerInitializerConfiguration这个类。

@ConditionalOnBean(EurekaServerMarkerConfiguration.Marker.class)注解表示只要Spring容器中有EurekaServerMarkerConfiguration.Marker.class类的实例存在,那么就会将这个EurekaServerAutoConfiguration也注入到Spring容器中。

@EnableConfigurationProperties注解 将EurekaDashboardProperties和InstanceRegistryProperties对应的配置属性类注入容器中

查看EurekaServerAutoConfiguration的源代码,可以发现它向Spring容器中注入了一些bean。举几个例子:

    
    这个bean中保存了这个实例的一些信息,名称为"Eureka Server"
	@Bean
	public HasFeatures eurekaServerFeature() {
		return HasFeatures.namedFeature("Eureka Server",
				EurekaServerAutoConfiguration.class);
	}

    
        //matchIfMissing属性表示缺少该property时是否可以加载。如果为true,没有该property也会正常加载;反之报错 
	//这个是仪表盘相关的Bean
	@Bean
	@ConditionalOnProperty(prefix = "eureka.dashboard", name = "enabled", matchIfMissing = true)
	public EurekaController eurekaController() {
		return new EurekaController(this.applicationInfoManager);
	}
    

这两个实例来自com.netflix.eureka,将相应的处理逻辑交到com.netflix.eureka中,它们接手了真正的EurekaServer的启动逻
辑,SpringCloud 只是在容器中将这些Bean初始化。


        // 
        @Bean
	public EurekaServerContext eurekaServerContext(ServerCodecs serverCodecs,
			PeerAwareInstanceRegistry registry, PeerEurekaNodes peerEurekaNodes) {
		return new DefaultEurekaServerContext(this.eurekaServerConfig, serverCodecs,
				registry, peerEurekaNodes, this.applicationInfoManager);
	}

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

向容器中初始化一个Jersey 过滤器。
tips:使用FilterRegistrationBean向Spring中注册过滤器十分方便。


        @Bean
	public FilterRegistrationBean jerseyFilterRegistration(
			javax.ws.rs.core.Application eurekaJerseyApp) {
		FilterRegistrationBean bean = new FilterRegistrationBean();
		bean.setFilter(new ServletContainer(eurekaJerseyApp));
		bean.setOrder(Ordered.LOWEST_PRECEDENCE);
		bean.setUrlPatterns(
				Collections.singletonList(EurekaConstants.DEFAULT_PREFIX + "/*"));

		return bean;
	}

1.5 现在,在回过头来看一下配置类EurekaServerAutoConfiguration导入的EurekaServerInitializerConfiguration
这个类。

首先可以发现它使用了@Configuration注解。然后实现了ServletContextAware, SmartLifecycle, Ordered三个接口,实现了这些接口的方法。


	@Override
	public void start() {
		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					//TODO: is this class even needed now?
					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);
	}

上面代码主要实现了start() 和 stop()方法。这两个方法的主要作用是初始化servlet相关上下文,在start的时候调用EurekaServerBootstrap.contextInitialized,在stop的时候调用eurekaServerBootstrap.contextDestroyed,都是借助eurekaServerBootstrap类来实现,而eurekaServerBootstrap里头部分调用了EurekaServerContext。再来看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);
		}
	}
	
	
    protected void initEurekaEnvironment() throws Exception {
        log.info("Setting the eureka configuration..");

        String dataCenter = ConfigurationManager.getConfigInstance()
                .getString(EUREKA_DATACENTER);
        if (dataCenter == null) {
            log.info(
                    "Eureka data center value eureka.datacenter is not set, defaulting to default");
            ConfigurationManager.getConfigInstance()
                    .setProperty(ARCHAIUS_DEPLOYMENT_DATACENTER, DEFAULT);
        }
        else {
            ConfigurationManager.getConfigInstance()
                    .setProperty(ARCHAIUS_DEPLOYMENT_DATACENTER, dataCenter);
        }
        String environment = ConfigurationManager.getConfigInstance()
                .getString(EUREKA_ENVIRONMENT);
        if (environment == null) {
            ConfigurationManager.getConfigInstance()
                    .setProperty(ARCHAIUS_DEPLOYMENT_ENVIRONMENT, TEST);
            log.info(
                    "Eureka environment value eureka.environment is not set, defaulting to test");
        }
        else {
            ConfigurationManager.getConfigInstance()
                    .setProperty(ARCHAIUS_DEPLOYMENT_ENVIRONMENT, environment);
        }
    }

    protected void initEurekaServerContext() throws Exception {
        // For backward compatibility
        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();
        }

        EurekaServerContextHolder.initialize(this.serverContext);

        log.info("Initialized server context");

        // Copy registry from neighboring eureka node
        int registryCount = this.registry.syncUp();
        this.registry.openForTraffic(this.applicationInfoManager, registryCount);

        // Register all monitoring statistics.
        EurekaMonitors.registerAllStats();
    }

主要是调用了initEurekaEnvironment()和initEurekaServerContext()方法,来初始化环境配置和初始化上下文。可以看到
initEurekaEnvironment()是设置了一些属性值,在initEurekaServerContext()方法中主要调用了 EurekaServerContextHolder.initialize(this.serverContext),this.registry.syncUp(),
this.registry.openForTraffic(this.applicationInfoManager, registryCount),这三个方法。EurekaServerContextHolder.initialize(this.serverContext),this.registry.syncUp()主要是给非IOC容器引用EurekaServerContext,registry.syncUp()从其他eureka server获取实例信息,然后注册到本server,然后复制到其他server节点上。registry.openForTraffic()标识自身server的状态为UP,表示可以开始接收请求。

相关标签: @EnableEurekaServer