@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)
这个类中,向容器注入了一个类,作用就是激活配置类。源代码是这样的:
@Configuration
public class EurekaServerMarkerConfiguration {
@Bean
public Marker eurekaServerMarkerBean() {
return new Marker();
}
class Marker {
}
}
1.4 下面来看配置类EurekaServerAutoConfiguration。这个类上面有三个比较重要的注释:
@Configuration
@Import()
@ConditionalOnBean()
@EnableConfigurationProperties({ ,
})
@Configuration注解表示这是一个配置类,通过@Bean注解声明一些注入到Spring IOC容器中的Bean。
@Import()注解表示它导入了EurekaServerInitializerConfiguration这个类。
@ConditionalOnBean()注解表示只要Spring容器中有类的实例存在,那么就会将这个EurekaServerAutoConfiguration也注入到Spring容器中。
@EnableConfigurationProperties注解 将EurekaDashboardProperties和InstanceRegistryProperties对应的配置属性类注入容器中
查看EurekaServerAutoConfiguration的源代码,可以发现它向Spring容器中注入了一些bean。举几个例子:
这个bean中保存了这个实例的一些信息,名称为"Eureka Server"
@Bean
public HasFeatures eurekaServerFeature() {
return ("Eureka Server",
);
}
//matchIfMissing属性表示缺少该property时是否可以加载。如果为true,没有该property也会正常加载;反之报错
//这个是仪表盘相关的Bean
@Bean
@ConditionalOnProperty(prefix = "", name = "enabled", matchIfMissing = true)
public EurekaController eurekaController() {
return new EurekaController();
}
这两个实例来自,将相应的处理逻辑交到中,它们接手了真正的EurekaServer的启动逻
辑,SpringCloud 只是在容器中将这些Bean初始化。
//
@Bean
public EurekaServerContext eurekaServerContext(ServerCodecs serverCodecs,
PeerAwareInstanceRegistry registry, PeerEurekaNodes peerEurekaNodes) {
return new DefaultEurekaServerContext(, serverCodecs,
registry, peerEurekaNodes, );
}
@Bean
public EurekaServerBootstrap eurekaServerBootstrap(PeerAwareInstanceRegistry registry,
EurekaServerContext serverContext) {
return new EurekaServerBootstrap(,
, , registry,
serverContext);
}
向容器中初始化一个Jersey 过滤器。
tips:使用FilterRegistrationBean向Spring中注册过滤器十分方便。
@Bean
public FilterRegistrationBean jerseyFilterRegistration(
eurekaJerseyApp) {
FilterRegistrationBean bean = new FilterRegistrationBean();
(new ServletContainer(eurekaJerseyApp));
(Ordered.LOWEST_PRECEDENCE);
(
(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?
();
("Started Eureka Server");
publish(new EurekaRegistryAvailableEvent(getEurekaServerConfig()));
= true;
publish(new EurekaServerStartedEvent(getEurekaServerConfig()));
}
catch (Exception ex) {
// Help!
("Could not initialize Eureka servlet context", ex);
}
}
}).start();
}
private EurekaServerConfig getEurekaServerConfig() {
return ;
}
private void publish(ApplicationEvent event) {
(event);
}
@Override
public void stop() {
= false;
();
}
上面代码主要实现了start() 和 stop()方法。这两个方法的主要作用是初始化servlet相关上下文,在start的时候调用,在stop的时候调用,都是借助eurekaServerBootstrap类来实现,而eurekaServerBootstrap里头部分调用了EurekaServerContext。再来看EurekaServerBootstrap中contextInitialized()方法的代码:
public void contextInitialized(ServletContext context) {
try {
initEurekaEnvironment();
initEurekaServerContext();
((), );
}
catch (Throwable e) {
("Cannot bootstrap eureka server :", e);
throw new RuntimeException("Cannot bootstrap eureka server :", e);
}
}
protected void initEurekaEnvironment() throws Exception {
("Setting the eureka configuration..");
String dataCenter = ()
.getString(EUREKA_DATACENTER);
if (dataCenter == null) {
(
"Eureka data center value is not set, defaulting to default");
()
.setProperty(ARCHAIUS_DEPLOYMENT_DATACENTER, DEFAULT);
}
else {
()
.setProperty(ARCHAIUS_DEPLOYMENT_DATACENTER, dataCenter);
}
String environment = ()
.getString(EUREKA_ENVIRONMENT);
if (environment == null) {
()
.setProperty(ARCHAIUS_DEPLOYMENT_ENVIRONMENT, TEST);
(
"Eureka environment value is not set, defaulting to test");
}
else {
()
.setProperty(ARCHAIUS_DEPLOYMENT_ENVIRONMENT, environment);
}
}
protected void initEurekaServerContext() throws Exception {
// For backward compatibility
().registerConverter(new V1AwareInstanceInfoConverter(),
XStream.PRIORITY_VERY_HIGH);
().registerConverter(new V1AwareInstanceInfoConverter(),
XStream.PRIORITY_VERY_HIGH);
if (isAws(())) {
= new AwsBinderDelegate(,
, , );
();
}
();
("Initialized server context");
// Copy registry from neighboring eureka node
int registryCount = ();
(, registryCount);
// Register all monitoring statistics.
();
}
主要是调用了initEurekaEnvironment()和initEurekaServerContext()方法,来初始化环境配置和初始化上下文。可以看到
initEurekaEnvironment()是设置了一些属性值,在initEurekaServerContext()方法中主要调用了 (),(),
(, registryCount),这三个方法。(),()主要是给非IOC容器引用EurekaServerContext,()从其他eureka server获取实例信息,然后注册到本server,然后复制到其他server节点上。()标识自身server的状态为UP,表示可以开始接收请求。