Open xinrong2019 opened 5 years ago
32G内存,搜狗输入法占了20多G,果断卸载了。也不想用原生的,于是下载了百度输入法,先用着,目前观察没有异常,内存消耗77兆
为了弄清楚如下几个问题:
[x] Spring Cloud Config Server是如何注册到Consul注册中心的?
[ ] Config Server是如何从git拉取配置的?
[ ] 基于MQ的事件驱动机制是如何实现配置自动刷新的?
1、关于环境的搭建不属于这次分析的内容,不会过多记录;
2、版本(安装包)声明:
consul:consul_1.4.4_darwin_amd64
Spring Cloud版本:Dalston.RELEASE
Spring Boot版本:1.5.14.RELEASE
3、由于Spring Cloud的使用是基于SpringBoot自动注解配置,所以入口都是全局搜索注解相关内容,下面会依次展开说明。
一个Config Server应用,需要在启动类上加三个注解:
@SpringBootApplication
@EnableDiscoveryClient
@EnableConfigServer//开启配置中心功能
关于如何注册到注册中心,看EnableDiscoveryClient这个注解,这个注解类属于spring-cloud-commons模块下。
看一下这个注解的源码及JavaDoc
/**
* Annotation to enable a DiscoveryClient implementation.
* @author Spencer Gibb
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(EnableDiscoveryClientImportSelector.class)
public @interface EnableDiscoveryClient {
/**
* If true, the ServiceRegistry will automatically register the local server.
*/
boolean autoRegister() default true;
}
注释上说了,这是一个启动DiscoveryClient实现的注解。
它有个autoRegister方法,默认是true,表示自动注册本地服务到注册中心。
有个import注解,导入了一个EnableDiscoveryClientImportSelector类,接下来看看这个类。
先看源码:
/**
* 这个类没有注释,差评!
* @author Spencer Gibb
*/
@Order(Ordered.LOWEST_PRECEDENCE - 100)//应该和什么顺序有关,先不管,感觉不是这次分析的重点。
public class EnableDiscoveryClientImportSelector
extends SpringFactoryImportSelector<EnableDiscoveryClient> {//继承自SpringFactoryImportSelector类,继承了父类,父类应该也很重要,知道父类的一些信息更容易了解子类。
@Override
public String[] selectImports(AnnotationMetadata metadata) {
String[] imports = super.selectImports(metadata);
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
metadata.getAnnotationAttributes(getAnnotationClass().getName(), true));
boolean autoRegister = attributes.getBoolean("autoRegister");
if (autoRegister) {
List<String> importsList = new ArrayList<>(Arrays.asList(imports));
importsList.add("org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration");
imports = importsList.toArray(new String[0]);
}
return imports;
}
@Override
protected boolean isEnabled() {
return new RelaxedPropertyResolver(getEnvironment()).getProperty(
"spring.cloud.discovery.enabled", Boolean.class, Boolean.TRUE);
}
@Override
protected boolean hasDefaultFactory() {
return true;
}
}
/**
* Selects configurations to load defined by the generic type T. Loads implementations
* using {@link SpringFactoriesLoader}.
* 选择泛型指定的需要加载的配置,使用SpringFactoriesLoader类加载实现
* @author Spencer Gibb
* @author Dave Syer
*/
@CommonsLog//lombok注解,和日志相关,忽略
public abstract class SpringFactoryImportSelector<T>
implements DeferredImportSelector, BeanClassLoaderAware, EnvironmentAware {
private ClassLoader beanClassLoader;
private Class<T> annotationClass;
private Environment environment;
@SuppressWarnings("unchecked")
protected SpringFactoryImportSelector() {
this.annotationClass = (Class<T>) GenericTypeResolver
.resolveTypeArgument(this.getClass(), SpringFactoryImportSelector.class);
}
@Override
public String[] selectImports(AnnotationMetadata metadata) {
if (!isEnabled()) {
return new String[0];
}
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
metadata.getAnnotationAttributes(this.annotationClass.getName(), true));
Assert.notNull(attributes, "No " + getSimpleName() + " attributes found. Is "
+ metadata.getClassName() + " annotated with @" + getSimpleName() + "?");
// Find all possible auto configuration classes, filtering duplicates
List<String> factories = new ArrayList<>(new LinkedHashSet<>(SpringFactoriesLoader
.loadFactoryNames(this.annotationClass, this.beanClassLoader)));
if (factories.isEmpty() && !hasDefaultFactory()) {
throw new IllegalStateException("Annotation @" + getSimpleName()
+ " found, but there are no implementations. Did you forget to include a starter?");
}
if (factories.size() > 1) {
// there should only ever be one DiscoveryClient, but there might be more than
// one factory
log.warn("More than one implementation " + "of @" + getSimpleName()
+ " (now relying on @Conditionals to pick one): " + factories);
}
return factories.toArray(new String[factories.size()]);
}
protected boolean hasDefaultFactory() {
return false;
}
protected abstract boolean isEnabled();
protected String getSimpleName() {
return this.annotationClass.getSimpleName();
}
protected Class<T> getAnnotationClass() {
return this.annotationClass;
}
protected Environment getEnvironment() {
return this.environment;
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.beanClassLoader = classLoader;
}
}
SpringFactoryImportSelector主要实现了DeferredImportSelector,这个类是在所有配置类处理完后运行。
/**
* A variation of {@link ImportSelector} that runs after all {@code @Configuration} beans
* have been processed. This type of selector can be particularly useful when the selected
* imports are {@code @Conditional}.
*
* <p>Implementations can also extend the {@link org.springframework.core.Ordered}
* interface or use the {@link org.springframework.core.annotation.Order} annotation to
* indicate a precedence against other {@link DeferredImportSelector}s.
*
* @author Phillip Webb
* @since 4.0
*/
public interface DeferredImportSelector extends ImportSelector {
}
DeferredImportSelector继承自ImportSelector接口:
/*
* Interface to be implemented by types that determine which @Configuration class(es) should be imported based on a given selection criteria, usually one or more annotation attributes.
An ImportSelector may implement any of the following Aware interfaces, and their respective methods will be called prior to selectImports(org.springframework.core.type.AnnotationMetadata):
EnvironmentAware
BeanFactoryAware
BeanClassLoaderAware
ResourceLoaderAware
ImportSelectors are usually processed in the same way as regular @Import annotations, however, it is also possible to defer selection of imports until all @Configuration classes have been processed (see DeferredImportSelector for details).
*
*/
public interface ImportSelector {
/**
* Select and return the names of which class(es) should be imported based on the AnnotationMetadata of the importing @Configuration class.
*/
String[] selectImports(AnnotationMetadata importingClassMetadata);
}
selectImports方法表示选择需要被导入的类。实现在SpringFactoryImportSelector中,所以回过头来看上面的SpringFactoryImportSelector的方法selectImports,选择需要导入哪些类。
@Override
public String[] selectImports(AnnotationMetadata metadata) {
if (!isEnabled()) {
return new String[0];
}
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
metadata.getAnnotationAttributes(this.annotationClass.getName(), true));
Assert.notNull(attributes, "No " + getSimpleName() + " attributes found. Is "
+ metadata.getClassName() + " annotated with @" + getSimpleName() + "?");
// Find all possible auto configuration classes, filtering duplicates <1>
List<String> factories = new ArrayList<>(new LinkedHashSet<>(SpringFactoriesLoader
.loadFactoryNames(this.annotationClass, this.beanClassLoader)));
if (factories.isEmpty() && !hasDefaultFactory()) {
throw new IllegalStateException("Annotation @" + getSimpleName()
+ " found, but there are no implementations. Did you forget to include a starter?");
}
if (factories.size() > 1) {
// there should only ever be one DiscoveryClient, but there might be more than
// one factory
log.warn("More than one implementation " + "of @" + getSimpleName()
+ " (now relying on @Conditionals to pick one): " + factories);
}
return factories.toArray(new String[factories.size()]);
}
<1> 看到这个地方,通过SpringFactoriesLoader加载一些工厂类,SpringFactoriesLoader类属于Spring-core模块下。SpringFactoriesLoader的loadFactoryNames方法干了什么?
```java
public static List总结:
1、学习了一个比较重要的接口,ImportSelector接口
这个接口的实现类,需要实现导入哪些注解配置
2、学到了一个重要配置加载的机制,通过SpringFactoriesLoader的loadFactoryNames加载META-INF/spring.factories文件中的实现类
3、使用Consul做服务发现,需要导入两个重要的配置,ConsulDiscoveryClientConfiguration和AutoServiceRegistrationConfiguration
github上star了一些项目学习,是http://www.youliao.com.cn/这个网站的,都是电商业务。
#