Merge pull request #64 from huifer/master

源码分析
pull/65/head
Yang Libin 4 years ago committed by GitHub
commit fc1678e2f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -23,6 +23,7 @@
* [将 BeanDefinition 注册进 IoC 容器](/docs/Spring/IoC/3、将BeanDefinition注册进IoC容器.md)
* [依赖注入(DI)](/docs/Spring/IoC/4、依赖注入(DI).md)
* [BeanPostProcessor](/docs/Spring/IoC/BeanPostProcessor.md)
* [Spring BeanFactory源码解析](/docs/Spring/clazz/Spring-beanFactory.md)
### AOP
@ -67,6 +68,9 @@
* [Spring-import注解](/docs/Spring/clazz/Spring-Import.md)
* [Spring-定时任务](/docs/Spring/clazz/Spring-Scheduling.md)
* [Spring StopWatch](/docs/Spring/clazz/Spring-StopWatch.md)
* [Spring 元数据](/docs/Spring/clazz/Spring-Metadata.md)
* [Spring 条件接口](/docs/Spring/clazz/Spring-Conditional.md)
### Spring5 新特性
@ -89,6 +93,7 @@
* [SpringBoot 自动装配](/docs/SpringBoot/SpringBoot-自动装配.md)
* [SpringBoot ConfigurationProperties](/docs/SpringBoot/SpringBoot-ConfigurationProperties.md)
* [SpringBoot 日志系统](/docs/SpringBoot/SpringBoot-LogSystem.md)
* [SpringBoot ConditionalOnBean](/docs/SpringBoot/SpringBoot-ConditionalOnBean.md)
## MyBatis
@ -216,6 +221,12 @@
* [深挖 Redis 6.0 源码——SDS](docs/Redis/redis-sds.md)
## Nacos
* [nacos 服务注册](docs/nacos/nacos-discovery.md)
## 番外篇JDK 1.8
### 基础类库
* [String类 源码赏析](docs/JDK/basic/String.md)

@ -0,0 +1,301 @@
# Spring Conditional
- Author: [HuiFer](https://github.com/huifer)
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
## Conditional
```java
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
/**
* 多个匹配器接口
*/
Class<? extends Condition>[] value();
}
```
## Condition
```
@FunctionalInterface
public interface Condition {
/**
* 匹配,如果匹配返回true进行初始化,返回false跳过初始化
*/
boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
```
- ConditionContext 上下文
- AnnotatedTypeMetadata 注解信息
### ConditionContext
```
public interface ConditionContext {
/**
* bean的定义
*/
BeanDefinitionRegistry getRegistry();
/**
* bean 工厂
*/
@Nullable
ConfigurableListableBeanFactory getBeanFactory();
/**
* 环境
*/
Environment getEnvironment();
/**
* 资源加载器
*/
ResourceLoader getResourceLoader();
/**
* 类加载器
*/
@Nullable
ClassLoader getClassLoader();
}
```
- 唯一实现 : `org.springframework.context.annotation.ConditionEvaluator.ConditionContextImpl`
- 构造方法
```java
public ConditionContextImpl(@Nullable BeanDefinitionRegistry registry,
@Nullable Environment environment, @Nullable ResourceLoader resourceLoader) {
this.registry = registry;
this.beanFactory = deduceBeanFactory(registry);
this.environment = (environment != null ? environment : deduceEnvironment(registry));
this.resourceLoader = (resourceLoader != null ? resourceLoader : deduceResourceLoader(registry));
this.classLoader = deduceClassLoader(resourceLoader, this.beanFactory);
}
```
- 在构造方法中加载了一些变量, 这些变量是根据一定规则转换后得到. 具体规则不展开.
### AnnotatedTypeMetadata
- 元数据接口
```java
public interface AnnotatedTypeMetadata {
/**
* 获取所有注解
*/
MergedAnnotations getAnnotations();
/**
* 是否有注解
*/
default boolean isAnnotated(String annotationName) {
return getAnnotations().isPresent(annotationName);
}
/**
* 获取注解的属性
*/
@Nullable
default Map<String, Object> getAnnotationAttributes(String annotationName) {
return getAnnotationAttributes(annotationName, false);
}
}
```
## 源码分析
- 对应测试类`org.springframework.context.annotation.ConfigurationClassWithConditionTests`
```java
@Test
public void conditionalOnMissingBeanMatch() throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(BeanOneConfiguration.class, BeanTwoConfiguration.class);
ctx.refresh();
assertThat(ctx.containsBean("bean1")).isTrue();
assertThat(ctx.containsBean("bean2")).isFalse();
assertThat(ctx.containsBean("configurationClassWithConditionTests.BeanTwoConfiguration")).isFalse();
}
@Configuration
static class BeanOneConfiguration {
@Bean
public ExampleBean bean1() {
return new ExampleBean();
}
}
@Configuration
@Conditional(NoBeanOneCondition.class)
static class BeanTwoConfiguration {
@Bean
public ExampleBean bean2() {
return new ExampleBean();
}
}
static class NoBeanOneCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return !context.getBeanFactory().containsBeanDefinition("bean1");
}
}
```
- `org.springframework.context.annotation.AnnotatedBeanDefinitionReader#doRegisterBean`
### shouldSkip
```java
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
return false;
}
if (phase == null) {
if (metadata instanceof AnnotationMetadata &&
ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
}
return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
}
List<Condition> conditions = new ArrayList<>();
// 获取注解 Conditional 的属性值
for (String[] conditionClasses : getConditionClasses(metadata)) {
for (String conditionClass : conditionClasses) {
// 序列化成注解
Condition condition = getCondition(conditionClass, this.context.getClassLoader());
// 插入注解列表
conditions.add(condition);
}
}
AnnotationAwareOrderComparator.sort(conditions);
for (Condition condition : conditions) {
ConfigurationPhase requiredPhase = null;
if (condition instanceof ConfigurationCondition) {
requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
}
// matches 进行验证
if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
return true;
}
}
return false;
}
```
- 读取注解信息, 并且执行注解对应的类的方法
用例如下. 实例化`BeanTwoConfiguration`对象的时候会去执行`NoBeanOneCondition`方法
```java
@Configuration
@Conditional(NoBeanOneCondition.class)
static class BeanTwoConfiguration {
@Bean
public ExampleBean bean2() {
return new ExampleBean();
}
}
static class NoBeanOneCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return !context.getBeanFactory().containsBeanDefinition("bean1");
}
}
```
在开发中可以自定义matches规则
这也是在注册的时候第一个方法
```java
private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
@Nullable BeanDefinitionCustomizer[] customizers) {
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
// 和条件注解相关的函数
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
// 省略其他
}
```

@ -0,0 +1,996 @@
# Spring 元信息
- Author: [HuiFer](https://github.com/huifer)
- 源码阅读仓库: [SourceHot-Spring](https://github.com/SourceHot/spring-framework-read)
## ClassMetadata
```java
public interface ClassMetadata {
/**
* 类名
*/
String getClassName();
/**
* 是否是接口
*/
boolean isInterface();
/**
* 是否是注解
*/
boolean isAnnotation();
/**
* 是否是超类
*/
boolean isAbstract();
/**
* 是否允许创建,实例化
*/
default boolean isConcrete() {
return !(isInterface() || isAbstract());
}
/**
* 是否有final修饰
*/
boolean isFinal();
/**
* 是否独立
*/
boolean isIndependent();
/**
* 是否有内部类
*/
default boolean hasEnclosingClass() {
return (getEnclosingClassName() != null);
}
/**
* 是否是基础类
*/
@Nullable
String getEnclosingClassName();
/**
* 是否有父类
*/
default boolean hasSuperClass() {
return (getSuperClassName() != null);
}
/**
* 父类名称
*/
@Nullable
String getSuperClassName();
/**
* 实现类名称列表
*/
String[] getInterfaceNames();
/**
* 成员列表
* @since 3.1
*/
String[] getMemberClassNames();
}
```
![image-20200824094154847](/images/spring/image-20200824094154847.png)
## AnnotatedTypeMetadata
```java
public interface AnnotatedTypeMetadata {
/**
* 获取所有注解
*/
MergedAnnotations getAnnotations();
/**
* 是否有注解
*/
default boolean isAnnotated(String annotationName) {
return getAnnotations().isPresent(annotationName);
}
/**
* 获取注解的属性
*/
@Nullable
default Map<String, Object> getAnnotationAttributes(String annotationName) {
return getAnnotationAttributes(annotationName, false);
}
// 省略其他
}
```
## AnnotationMetadata
```java
public interface AnnotationMetadata extends ClassMetadata, AnnotatedTypeMetadata {
/**
* 获取注解名称,全类名
*/
default Set<String> getAnnotationTypes() {
return getAnnotations().stream()
.filter(MergedAnnotation::isDirectlyPresent)
.map(annotation -> annotation.getType().getName())
.collect(Collectors.toCollection(LinkedHashSet::new));
}
/**
* 注解全类名
*/
default Set<String> getMetaAnnotationTypes(String annotationName) {
MergedAnnotation<?> annotation = getAnnotations().get(annotationName, MergedAnnotation::isDirectlyPresent);
if (!annotation.isPresent()) {
return Collections.emptySet();
}
return MergedAnnotations.from(annotation.getType(), SearchStrategy.INHERITED_ANNOTATIONS).stream()
.map(mergedAnnotation -> mergedAnnotation.getType().getName())
.collect(Collectors.toCollection(LinkedHashSet::new));
}
/**
* 是否包含某个注解
*/
default boolean hasAnnotation(String annotationName) {
return getAnnotations().isDirectlyPresent(annotationName);
}
/**
* 是否被某个注解标记过
*/
default boolean hasMetaAnnotation(String metaAnnotationName) {
return getAnnotations().get(metaAnnotationName,
MergedAnnotation::isMetaPresent).isPresent();
}
/**
* 是否有注解,类里面有一个注解就返回true
*/
default boolean hasAnnotatedMethods(String annotationName) {
return !getAnnotatedMethods(annotationName).isEmpty();
}
/**
* 获取包含注解的方法
*/
Set<MethodMetadata> getAnnotatedMethods(String annotationName);
/**
* 通过反射创建一个注解的元信息
*/
static AnnotationMetadata introspect(Class<?> type) {
return StandardAnnotationMetadata.from(type);
}
}
```
## MethodMetadata
```java
public interface MethodMetadata extends AnnotatedTypeMetadata {
/**
* 方法名称
*/
String getMethodName();
/**
* 方法全路径
*/
String getDeclaringClassName();
/**
* 返回值类型
*/
String getReturnTypeName();
/**
* 是不是abstrac修饰
*/
boolean isAbstract();
/**
* 是否 static 修饰
*/
boolean isStatic();
/**
* 是否 final 修饰
*/
boolean isFinal();
/**
* 是否重载
*/
boolean isOverridable();
}
```
## MetadataReader
```java
public interface MetadataReader {
/**
* Return the resource reference for the class file.
*
* 获取资源
*/
Resource getResource();
/**
* Read basic class metadata for the underlying class.
* 获取类的元信息
*/
ClassMetadata getClassMetadata();
/**
* Read full annotation metadata for the underlying class,
* including metadata for annotated methods.
*
* 获取注解的元信息
*/
AnnotationMetadata getAnnotationMetadata();
}
```
## MetadataReaderFactory
- 用来创建 MetadataReader
```java
public interface MetadataReaderFactory {
/**
* Obtain a MetadataReader for the given class name.
* @param className the class name (to be resolved to a ".class" file)
* @return a holder for the ClassReader instance (never {@code null})
* @throws IOException in case of I/O failure
*/
MetadataReader getMetadataReader(String className) throws IOException;
/**
* Obtain a MetadataReader for the given resource.
* @param resource the resource (pointing to a ".class" file)
* @return a holder for the ClassReader instance (never {@code null})
* @throws IOException in case of I/O failure
*/
MetadataReader getMetadataReader(Resource resource) throws IOException;
}
```
- 接口解释的差不多了.接下来看一些实现
## StandardClassMetadata
- 通过JAVA 反射来获取类的元信息
- 这个类采用的方式是Java class的方法,通过构造方法来填写一个Class对象. 之后使用这个对象的方法
```java
public class StandardClassMetadata implements ClassMetadata {
private final Class<?> introspectedClass;
@Deprecated
public StandardClassMetadata(Class<?> introspectedClass) {
Assert.notNull(introspectedClass, "Class must not be null");
this.introspectedClass = introspectedClass;
}
/**
* Return the underlying Class.
*/
public final Class<?> getIntrospectedClass() {
return this.introspectedClass;
}
@Override
public String getClassName() {
return this.introspectedClass.getName();
}
@Override
public boolean isInterface() {
return this.introspectedClass.isInterface();
}
@Override
public boolean isAnnotation() {
return this.introspectedClass.isAnnotation();
}
@Override
public boolean isAbstract() {
return Modifier.isAbstract(this.introspectedClass.getModifiers());
}
@Override
public boolean isFinal() {
return Modifier.isFinal(this.introspectedClass.getModifiers());
}
@Override
public boolean isIndependent() {
return (!hasEnclosingClass() ||
(this.introspectedClass.getDeclaringClass() != null &&
Modifier.isStatic(this.introspectedClass.getModifiers())));
}
@Override
@Nullable
public String getEnclosingClassName() {
Class<?> enclosingClass = this.introspectedClass.getEnclosingClass();
return (enclosingClass != null ? enclosingClass.getName() : null);
}
@Override
@Nullable
public String getSuperClassName() {
Class<?> superClass = this.introspectedClass.getSuperclass();
return (superClass != null ? superClass.getName() : null);
}
@Override
public String[] getInterfaceNames() {
Class<?>[] ifcs = this.introspectedClass.getInterfaces();
String[] ifcNames = new String[ifcs.length];
for (int i = 0; i < ifcs.length; i++) {
ifcNames[i] = ifcs[i].getName();
}
return ifcNames;
}
@Override
public String[] getMemberClassNames() {
LinkedHashSet<String> memberClassNames = new LinkedHashSet<>(4);
for (Class<?> nestedClass : this.introspectedClass.getDeclaredClasses()) {
memberClassNames.add(nestedClass.getName());
}
return StringUtils.toStringArray(memberClassNames);
}
}
```
## StandardMethodMetadata
- 通过java反射获取方法的元信息
- 构造方法传递一个method
- 如果这个方法有注解,会进行注解的解析
```java
public class StandardMethodMetadata implements MethodMetadata {
private final Method introspectedMethod;
private final boolean nestedAnnotationsAsMap;
private final MergedAnnotations mergedAnnotations;
@Deprecated
public StandardMethodMetadata(Method introspectedMethod) {
this(introspectedMethod, false);
}
@Deprecated
public StandardMethodMetadata(Method introspectedMethod, boolean nestedAnnotationsAsMap) {
Assert.notNull(introspectedMethod, "Method must not be null");
this.introspectedMethod = introspectedMethod;
this.nestedAnnotationsAsMap = nestedAnnotationsAsMap;
this.mergedAnnotations = MergedAnnotations.from(
introspectedMethod, SearchStrategy.DIRECT, RepeatableContainers.none());
}
@Override
public MergedAnnotations getAnnotations() {
return this.mergedAnnotations;
}
/**
* Return the underlying Method.
*/
public final Method getIntrospectedMethod() {
return this.introspectedMethod;
}
@Override
public String getMethodName() {
return this.introspectedMethod.getName();
}
@Override
public String getDeclaringClassName() {
return this.introspectedMethod.getDeclaringClass().getName();
}
@Override
public String getReturnTypeName() {
return this.introspectedMethod.getReturnType().getName();
}
@Override
public boolean isAbstract() {
return Modifier.isAbstract(this.introspectedMethod.getModifiers());
}
@Override
public boolean isStatic() {
return Modifier.isStatic(this.introspectedMethod.getModifiers());
}
@Override
public boolean isFinal() {
return Modifier.isFinal(this.introspectedMethod.getModifiers());
}
@Override
public boolean isOverridable() {
return !isStatic() && !isFinal() && !isPrivate();
}
private boolean isPrivate() {
return Modifier.isPrivate(this.introspectedMethod.getModifiers());
}
@Override
@Nullable
public Map<String, Object> getAnnotationAttributes(String annotationName, boolean classValuesAsString) {
if (this.nestedAnnotationsAsMap) {
return MethodMetadata.super.getAnnotationAttributes(annotationName, classValuesAsString);
}
return AnnotatedElementUtils.getMergedAnnotationAttributes(this.introspectedMethod,
annotationName, classValuesAsString, false);
}
/**
* 获取所有注解的信息
*/
@Override
@Nullable
public MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationName, boolean classValuesAsString) {
if (this.nestedAnnotationsAsMap) {
return MethodMetadata.super.getAllAnnotationAttributes(annotationName, classValuesAsString);
}
return AnnotatedElementUtils.getAllAnnotationAttributes(this.introspectedMethod,
annotationName, classValuesAsString, false);
}
}
```
## StandardAnnotationMetadata
- StandardAnnotationMetadata是StandardClassMetadata的子类
- 还是一个基于JAVA 反射做的一个类
- 获取注解属性map
```java
@Override
@Nullable
public Map<String, Object> getAnnotationAttributes(String annotationName, boolean classValuesAsString) {
if (this.nestedAnnotationsAsMap) {
return AnnotationMetadata.super.getAnnotationAttributes(annotationName, classValuesAsString);
}
return AnnotatedElementUtils.getMergedAnnotationAttributes(
getIntrospectedClass(), annotationName, classValuesAsString, false);
}
```
- `org.springframework.core.annotation.AnnotatedElementUtils#getMergedAnnotationAttributes(java.lang.reflect.AnnotatedElement, java.lang.String, boolean, boolean)`
- `org.springframework.core.annotation.AnnotatedElementUtils#getAnnotationAttributes`
- `org.springframework.core.annotation.MergedAnnotation#asAnnotationAttributes`
```java
@Nullable
public static AnnotationAttributes getMergedAnnotationAttributes(AnnotatedElement element,
String annotationName, boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
MergedAnnotation<?> mergedAnnotation = getAnnotations(element)
.get(annotationName, null, MergedAnnotationSelectors.firstDirectlyDeclared());
return getAnnotationAttributes(mergedAnnotation, classValuesAsString, nestedAnnotationsAsMap);
}
```
- 查看这个方法的源码借助测试类`org.springframework.core.annotation.AnnotatedElementUtilsTests#getMergedAnnotationAttributesOnClassWithLocalAnnotation`
- getAnnotations() 方法
### getAnnotations
- `org.springframework.core.annotation.MergedAnnotations#from(java.lang.reflect.AnnotatedElement, org.springframework.core.annotation.MergedAnnotations.SearchStrategy, org.springframework.core.annotation.RepeatableContainers)`
- `org.springframework.core.annotation.TypeMappedAnnotations#from(java.lang.reflect.AnnotatedElement, org.springframework.core.annotation.MergedAnnotations.SearchStrategy, org.springframework.core.annotation.RepeatableContainers, org.springframework.core.annotation.AnnotationFilter)`
- 最终我们找到的代码如下
```java
static MergedAnnotations from(AnnotatedElement element, SearchStrategy searchStrategy,
RepeatableContainers repeatableContainers, AnnotationFilter annotationFilter) {
if (AnnotationsScanner.isKnownEmpty(element, searchStrategy)) {
return NONE;
}
return new TypeMappedAnnotations(element, searchStrategy, repeatableContainers, annotationFilter);
}
```
- 判断是否为空. 为空返回None不会为空构造出一个对象org.springframework.core.annotation.TypeMappedAnnotations
### MergedAnnotations
```java
public interface MergedAnnotations extends Iterable<MergedAnnotation<Annotation>> {
//确定注解是否存在
<A extends Annotation> boolean isPresent(Class<A> annotationType);
//注解是否直接存在
<A extends Annotation> boolean isDirectlyPresent(Class<A> annotationType);
// 获取匹配的注解
<A extends Annotation> MergedAnnotation<A> get(Class<A> annotationType);
// 省略其他
}
```
- 这个接口中还有两个方法
1. `of`
将多个`MergedAnnotations`合并
2. `from`
将多个注解合并
### SearchStrategy
```java
enum SearchStrategy {
/**
* Find only directly declared annotations, without considering
* {@link Inherited @Inherited} annotations and without searching
* superclasses or implemented interfaces.
*
* 直接查找
*/
DIRECT,
/**
* Find all directly declared annotations as well as any
* {@link Inherited @Inherited} superclass annotations. This strategy
* is only really useful when used with {@link Class} types since the
* {@link Inherited @Inherited} annotation is ignored for all other
* {@linkplain AnnotatedElement annotated elements}. This strategy does
* not search implemented interfaces.
*
* 继承查找
*/
INHERITED_ANNOTATIONS,
/**
* Find all directly declared and superclass annotations. This strategy
* is similar to {@link #INHERITED_ANNOTATIONS} except the annotations
* do not need to be meta-annotated with {@link Inherited @Inherited}.
* This strategy does not search implemented interfaces.
* 查找当前类和父类的注解
*/
SUPERCLASS,
/**
* Perform a full search of the entire type hierarchy, including
* superclasses and implemented interfaces. Superclass annotations do
* not need to be meta-annotated with {@link Inherited @Inherited}.
*/
TYPE_HIERARCHY,
/**
* Perform a full search of the entire type hierarchy on the source
* <em>and</em> any enclosing classes. This strategy is similar to
* {@link #TYPE_HIERARCHY} except that {@linkplain Class#getEnclosingClass()
* enclosing classes} are also searched. Superclass annotations do not
* need to be meta-annotated with {@link Inherited @Inherited}. When
* searching a {@link Method} source, this strategy is identical to
* {@link #TYPE_HIERARCHY}.
*/
TYPE_HIERARCHY_AND_ENCLOSING_CLASSES
}
```
- `org.springframework.core.annotation.TypeMappedAnnotations#get(java.lang.String, java.util.function.Predicate<? super org.springframework.core.annotation.MergedAnnotation<A>>, org.springframework.core.annotation.MergedAnnotationSelector<A>)`
```java
@Override
public <A extends Annotation> MergedAnnotation<A> get(String annotationType,
@Nullable Predicate<? super MergedAnnotation<A>> predicate,
@Nullable MergedAnnotationSelector<A> selector) {
// 匹配校验
if (this.annotationFilter.matches(annotationType)) {
return MergedAnnotation.missing();
}
MergedAnnotation<A> result = scan(annotationType,
new MergedAnnotationFinder<>(annotationType, predicate, selector));
return (result != null ? result : MergedAnnotation.missing());
}
```
#### Scan
`org.springframework.core.annotation.AnnotationsScanner#scan(C, java.lang.reflect.AnnotatedElement, org.springframework.core.annotation.MergedAnnotations.SearchStrategy, org.springframework.core.annotation.AnnotationsProcessor<C,R>, java.util.function.BiPredicate<C,java.lang.Class<?>>)`
```java
@Nullable
static <C, R> R scan(C context, AnnotatedElement source, SearchStrategy searchStrategy,
AnnotationsProcessor<C, R> processor, @Nullable BiPredicate<C, Class<?>> classFilter) {
R result = process(context, source, searchStrategy, processor, classFilter);
return processor.finish(result);
}
```
在这个里面重点关注`PROCESS`方法
```java
@Nullable
private static <C, R> R process(C context, AnnotatedElement source,
SearchStrategy searchStrategy, AnnotationsProcessor<C, R> processor,
@Nullable BiPredicate<C, Class<?>> classFilter) {
if (source instanceof Class) {
return processClass(context, (Class<?>) source, searchStrategy, processor, classFilter);
}
if (source instanceof Method) {
return processMethod(context, (Method) source, searchStrategy, processor, classFilter);
}
return processElement(context, source, processor, classFilter);
}
```
测试类
```java
@Transactional("TxConfig")
static class TxConfig {
}
```
显然这是一个类他会走`processClass`方法
- 根据扫描方式进行扫描
```java
@Nullable
private static <C, R> R processClass(C context, Class<?> source,
SearchStrategy searchStrategy, AnnotationsProcessor<C, R> processor,
@Nullable BiPredicate<C, Class<?>> classFilter) {
switch (searchStrategy) {
case DIRECT:
return processElement(context, source, processor, classFilter);
case INHERITED_ANNOTATIONS:
return processClassInheritedAnnotations(context, source, searchStrategy, processor, classFilter);
case SUPERCLASS:
return processClassHierarchy(context, source, processor, classFilter, false, false);
case TYPE_HIERARCHY:
return processClassHierarchy(context, source, processor, classFilter, true, false);
case TYPE_HIERARCHY_AND_ENCLOSING_CLASSES:
return processClassHierarchy(context, source, processor, classFilter, true, true);
}
throw new IllegalStateException("Unsupported search strategy " + searchStrategy);
}
```
- 扫描的形式就不贴出完整代码了
`finish`就包装一下返回.
- 此时`org.springframework.core.annotation.AnnotatedElementUtils#getMergedAnnotationAttributes(java.lang.reflect.AnnotatedElement, java.lang.String, boolean, boolean)`这个方法走到了最后一步`org.springframework.core.annotation.AnnotatedElementUtils#getAnnotationAttributes`
- 最后的组装map方法
`org.springframework.core.annotation.TypeMappedAnnotation#asMap(java.util.function.Function<org.springframework.core.annotation.MergedAnnotation<?>,T>, org.springframework.core.annotation.MergedAnnotation.Adapt...)`
```java
@Override
public AnnotationAttributes asAnnotationAttributes(Adapt... adaptations) {
return asMap(mergedAnnotation -> new AnnotationAttributes(mergedAnnotation.getType()), adaptations);
}
```
```java
@Override
public <T extends Map<String, Object>> T asMap(Function<MergedAnnotation<?>, T> factory, Adapt... adaptations) {
T map = factory.apply(this);
Assert.state(map != null, "Factory used to create MergedAnnotation Map must not return null");
AttributeMethods attributes = this.mapping.getAttributes();
for (int i = 0; i < attributes.size(); i++) {
Method attribute = attributes.get(i);
Object value = (isFiltered(attribute.getName()) ? null :
getValue(i, getTypeForMapOptions(attribute, adaptations)));
if (value != null) {
map.put(attribute.getName(),
adaptValueForMapOptions(attribute, value, map.getClass(), factory, adaptations));
}
}
return map;
}
```
- 获取属性列表,循环, 放入map 返回.
map
key: 注解的函数
value: 函数对应的值
```java
@Transactional("TxConfig")
```
```java
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Inherited
@interface Transactional {
String value() default "";
String qualifier() default "transactionManager";
boolean readOnly() default false;
}
```
如果是上面这样的结构那么返回值为
```json
value:TxConfig
qulifiter:transactionManager
readOnlay:false
```
![image-20200824104529315](/images/spring/image-20200824104529315.png)
## SimpleMetadataReader
- 构造方法传递三个参数直接使用
```java
final class SimpleMetadataReader implements MetadataReader {
private static final int PARSING_OPTIONS = ClassReader.SKIP_DEBUG
| ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES;
private final Resource resource;
private final AnnotationMetadata annotationMetadata;
SimpleMetadataReader(Resource resource, @Nullable ClassLoader classLoader) throws IOException {
SimpleAnnotationMetadataReadingVisitor visitor = new SimpleAnnotationMetadataReadingVisitor(classLoader);
getClassReader(resource).accept(visitor, PARSING_OPTIONS);
this.resource = resource;
this.annotationMetadata = visitor.getMetadata();
}
private static ClassReader getClassReader(Resource resource) throws IOException {
try (InputStream is = new BufferedInputStream(resource.getInputStream())) {
try {
return new ClassReader(is);
}
catch (IllegalArgumentException ex) {
throw new NestedIOException("ASM ClassReader failed to parse class file - " +
"probably due to a new Java class file version that isn't supported yet: " + resource, ex);
}
}
}
@Override
public Resource getResource() {
return this.resource;
}
@Override
public ClassMetadata getClassMetadata() {
return this.annotationMetadata;
}
@Override
public AnnotationMetadata getAnnotationMetadata() {
return this.annotationMetadata;
}
}
```
## SimpleMetadataReaderFactory
- 关注点为如何获取`MetadataReader`
1. 通过资源直接new出来
2. 通过className转换成资源地址,
3. 将资源地址转换成`Resource`对象
4. new出来
```java
@Override
public MetadataReader getMetadataReader(String className) throws IOException {
try {
String resourcePath = ResourceLoader.CLASSPATH_URL_PREFIX +
ClassUtils.convertClassNameToResourcePath(className) + ClassUtils.CLASS_FILE_SUFFIX;
Resource resource = this.resourceLoader.getResource(resourcePath);
return getMetadataReader(resource);
}
catch (FileNotFoundException ex) {
// Maybe an inner class name using the dot name syntax? Need to use the dollar syntax here...
// ClassUtils.forName has an equivalent check for resolution into Class references later on.
int lastDotIndex = className.lastIndexOf('.');
if (lastDotIndex != -1) {
String innerClassName =
className.substring(0, lastDotIndex) + '$' + className.substring(lastDotIndex + 1);
String innerClassResourcePath = ResourceLoader.CLASSPATH_URL_PREFIX +
ClassUtils.convertClassNameToResourcePath(innerClassName) + ClassUtils.CLASS_FILE_SUFFIX;
Resource innerClassResource = this.resourceLoader.getResource(innerClassResourcePath);
if (innerClassResource.exists()) {
return getMetadataReader(innerClassResource);
}
}
throw ex;
}
}
@Override
public MetadataReader getMetadataReader(Resource resource) throws IOException {
return new SimpleMetadataReader(resource, this.resourceLoader.getClassLoader());
}
```

@ -0,0 +1,139 @@
# SpringFactoriesLoader
- Author: [HuiFer](https://github.com/huifer)
- 源码阅读仓库: [SourceHot-spring-boot](https://github.com/SourceHot/spring-boot-read)
- 全路径 : `org.springframework.core.io.support.SpringFactoriesLoader`
- 测试类 : `org.springframework.core.io.support.SpringFactoriesLoaderTests`
## loadFactories
- **加载并实例化工厂**
```java
public static <T> List<T> loadFactories(Class<T> factoryType, @Nullable ClassLoader classLoader) {
Assert.notNull(factoryType, "'factoryType' must not be null");
ClassLoader classLoaderToUse = classLoader;
if (classLoaderToUse == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
// 工厂实现类名称
List<String> factoryImplementationNames = loadFactoryNames(factoryType, classLoaderToUse);
if (logger.isTraceEnabled()) {
logger.trace("Loaded [" + factoryType.getName() + "] names: " + factoryImplementationNames);
}
List<T> result = new ArrayList<>(factoryImplementationNames.size());
for (String factoryImplementationName : factoryImplementationNames) {
// 将实例化的工厂放入结果集合
result.add(instantiateFactory(factoryImplementationName, factoryType, classLoaderToUse));
}
// 排序
AnnotationAwareOrderComparator.sort(result);
return result;
}
```
## loadSpringFactories
- 获取接口的实现类名
```java
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}
try {
// 找 META-INF/spring.factories
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
while (urls.hasMoreElements()) {
// 获取 路由地址
URL url = urls.nextElement();
// url 解析
UrlResource resource = new UrlResource(url);
// Properties 解析
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
// 循环解析结果
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim();
for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
// 放入list
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
// 放入缓存
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
```
- 存放在 测试目录下的`META-INF/spring.factories`
```properties
org.springframework.core.io.support.DummyFactory =\
org.springframework.core.io.support.MyDummyFactory2, \
org.springframework.core.io.support.MyDummyFactory1
java.lang.String=\
org.springframework.core.io.support.MyDummyFactory1
org.springframework.core.io.support.DummyPackagePrivateFactory=\
org.springframework.core.io.support.DummyPackagePrivateFactory
```
- `Enumeration<URL> urls ` 变量存放的是 扫描到的`META-INF/spring.factories` 路径
- while 代码简单描述
1. 获取文件路径
2. 文件路径解析
3. 读取文件 Properties 解析
4. 放入返回结果
5. 放入缓存
## instantiateFactory
```java
@SuppressWarnings("unchecked")
private static <T> T instantiateFactory(String factoryImplementationName, Class<T> factoryType, ClassLoader classLoader) {
try {
Class<?> factoryImplementationClass = ClassUtils.forName(factoryImplementationName, classLoader);
if (!factoryType.isAssignableFrom(factoryImplementationClass)) {
throw new IllegalArgumentException(
"Class [" + factoryImplementationName + "] is not assignable to factory type [" + factoryType.getName() + "]");
}
return (T) ReflectionUtils.accessibleConstructor(factoryImplementationClass).newInstance();
}
catch (Throwable ex) {
throw new IllegalArgumentException(
"Unable to instantiate factory class [" + factoryImplementationName + "] for factory type [" + factoryType.getName() + "]",
ex
);
}
}
```
- 反射创建

File diff suppressed because it is too large Load Diff

@ -0,0 +1,721 @@
# SpringBoot ConditionalOnBean
- Author: [HuiFer](https://github.com/huifer)
- 源码阅读仓库: [SourceHot-spring-boot](https://github.com/SourceHot/spring-boot-read)
- 在 SpringBoot 中有下列当XXX存在或不存的时候执行初始化
- ConditionalOnBean
ConditionalOnClass
ConditionalOnCloudPlatform
ConditionalOnExpression
ConditionalOnJava
ConditionalOnJndi
ConditionalOnMissingBean
ConditionalOnMissingClass
ConditionalOnNotWebApplication
ConditionalOnProperty
ConditionalOnResource
ConditionalOnSingleCandidate
ConditionalOnWebApplication
## ConditionalOnBean
```java
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnBeanCondition.class)
public @interface ConditionalOnBean {
/**
* 需要匹配的 bean 类型
*/
Class<?>[] value() default {};
/**
* 需要匹配的 bean 类型
*/
String[] type() default {};
/**
* 匹配的 bean 注解
*/
Class<? extends Annotation>[] annotation() default {};
/**
* 需要匹配的 beanName
*/
String[] name() default {};
/**
* 搜索策略
*/
SearchStrategy search() default SearchStrategy.ALL;
/**
*/
Class<?>[] parameterizedContainer() default {};
}
```
## SearchStrategy
```java
public enum SearchStrategy {
/**
* 当前 上下文
*/
CURRENT,
/**
* 找所有的父容器
*/
ANCESTORS,
/**
* 当前上下文+父容器
*/
ALL
}
```
## OnBeanCondition
- org.springframework.boot.autoconfigure.condition.OnBeanCondition
- 这个类是一个条件类,相关的还有
```properties
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
org.springframework.boot.autoconfigure.condition.OnClassCondition,\
org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition
```
- 类图
![image-20200824085726621](//images/SpringBoot//SpringBoot/image-20200824085726621.png)
在看这部分源码之前需要先了解 `Conditional`和`Condition`的源码
- 简单描述
通过实现`Condition` 来确认是否初始化bean
- 从类图上我们可以看到 `condition` 的继承关系. 在这里需要去找到`SpringBootCondition`
- `org.springframework.boot.autoconfigure.condition.SpringBootCondition#matches(org.springframework.context.annotation.ConditionContext, org.springframework.core.type.AnnotatedTypeMetadata)`
```java
@Override
public final boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 类名或者方法名标记
String classOrMethodName = getClassOrMethodName(metadata);
try {
// 比较类,子类实现
ConditionOutcome outcome = getMatchOutcome(context, metadata);
// 日志输出
logOutcome(classOrMethodName, outcome);
// 报告记录
recordEvaluation(context, classOrMethodName, outcome);
// 返回匹配结果
return outcome.isMatch();
}
catch (NoClassDefFoundError ex) {
throw new IllegalStateException("Could not evaluate condition on " + classOrMethodName + " due to "
+ ex.getMessage() + " not found. Make sure your own configuration does not rely on "
+ "that class. This can also happen if you are "
+ "@ComponentScanning a springframework package (e.g. if you "
+ "put a @ComponentScan in the default package by mistake)", ex);
}
catch (RuntimeException ex) {
throw new IllegalStateException("Error processing condition on " + getName(metadata), ex);
}
}
```
- `getOutcomes` 子类实现
`org.springframework.boot.autoconfigure.condition.OnBeanCondition#getOutcomes`
```java
String[] autoConfigurationClasses,
AutoConfigurationMetadata autoConfigurationMetadata
```
- 第一个参数: 需要自动配置的类
- 配置注解信息
### ConditionOutcome 和 ConditionMessage
```java
public class ConditionOutcome {
/**
* 是否匹配
*/
private final boolean match;
/**
* 条件信息
*/
private final ConditionMessage message;
}
public final class ConditionMessage {
private String message;
}
```
- 造一个对象用来进行debug
```java
@Component
public class Beans {
@Bean
public A a() {
return new A();
}
@Bean
@ConditionalOnBean(value = A.class)
public B b() {
return new B();
}
}
```
## getMatchOutcome
```java
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 条件信息
ConditionMessage matchMessage = ConditionMessage.empty();
// 获取注解求和
MergedAnnotations annotations = metadata.getAnnotations();
// 注解是否匹配
if (annotations.isPresent(ConditionalOnBean.class)) {
// 搜索 ConditionalOnBean 注解
Spec<ConditionalOnBean> spec = new Spec<>(context, metadata, annotations,
ConditionalOnBean.class);
// 匹配结果
MatchResult matchResult = getMatchingBeans(context, spec);
if (!matchResult.isAllMatched()) {
String reason = createOnBeanNoMatchReason(matchResult);
return ConditionOutcome.noMatch(spec.message().because(reason));
}
// 把注解解析出来获得文本
matchMessage = spec.message(matchMessage).found("bean", "beans").items(Style.QUOTE,
matchResult.getNamesOfAllMatches());
}
if (metadata.isAnnotated(ConditionalOnSingleCandidate.class.getName())) {
Spec<ConditionalOnSingleCandidate> spec = new SingleCandidateSpec(context, metadata, annotations);
MatchResult matchResult = getMatchingBeans(context, spec);
if (!matchResult.isAllMatched()) {
return ConditionOutcome.noMatch(spec.message().didNotFind("any beans").atAll());
}
else if (!hasSingleAutowireCandidate(context.getBeanFactory(), matchResult.getNamesOfAllMatches(),
spec.getStrategy() == SearchStrategy.ALL)) {
return ConditionOutcome.noMatch(spec.message().didNotFind("a primary bean from beans")
.items(Style.QUOTE, matchResult.getNamesOfAllMatches()));
}
matchMessage = spec.message(matchMessage).found("a primary bean from beans").items(Style.QUOTE,
matchResult.getNamesOfAllMatches());
}
if (metadata.isAnnotated(ConditionalOnMissingBean.class.getName())) {
Spec<ConditionalOnMissingBean> spec = new Spec<>(context, metadata, annotations,
ConditionalOnMissingBean.class);
MatchResult matchResult = getMatchingBeans(context, spec);
if (matchResult.isAnyMatched()) {
String reason = createOnMissingBeanNoMatchReason(matchResult);
return ConditionOutcome.noMatch(spec.message().because(reason));
}
matchMessage = spec.message(matchMessage).didNotFind("any beans").atAll();
}
return ConditionOutcome.match(matchMessage);
}
```
- 开始方法分析
### getMatchingBeans
- `org.springframework.boot.autoconfigure.condition.OnBeanCondition#getMatchingBeans`
```java
protected final MatchResult getMatchingBeans(ConditionContext context, Spec<?> spec) {
// 获取上下文
ClassLoader classLoader = context.getClassLoader();
// 获取 IOC 容器
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 扫描方式比较是否为当前上下文
boolean considerHierarchy = spec.getStrategy() != SearchStrategy.CURRENT;
Set<Class<?>> parameterizedContainers = spec.getParameterizedContainers();
if (spec.getStrategy() == SearchStrategy.ANCESTORS) {
BeanFactory parent = beanFactory.getParentBeanFactory();
Assert.isInstanceOf(ConfigurableListableBeanFactory.class, parent,
"Unable to use SearchStrategy.ANCESTORS");
beanFactory = (ConfigurableListableBeanFactory) parent;
}
// 结果对象初始化
MatchResult result = new MatchResult();
Set<String> beansIgnoredByType = getNamesOfBeansIgnoredByType(classLoader, beanFactory, considerHierarchy,
spec.getIgnoredTypes(), parameterizedContainers);
for (String type : spec.getTypes()) {
// 通过类型获取 beanName
Collection<String> typeMatches = getBeanNamesForType(classLoader, considerHierarchy, beanFactory, type,
parameterizedContainers);
typeMatches.removeAll(beansIgnoredByType);
if (typeMatches.isEmpty()) {
result.recordUnmatchedType(type);
}
else {
result.recordMatchedType(type, typeMatches);
}
}
for (String annotation : spec.getAnnotations()) {
Set<String> annotationMatches = getBeanNamesForAnnotation(classLoader, beanFactory, annotation,
considerHierarchy);
annotationMatches.removeAll(beansIgnoredByType);
if (annotationMatches.isEmpty()) {
result.recordUnmatchedAnnotation(annotation);
}
else {
result.recordMatchedAnnotation(annotation, annotationMatches);
}
}
for (String beanName : spec.getNames()) {
if (!beansIgnoredByType.contains(beanName) && containsBean(beanFactory, beanName, considerHierarchy)) {
result.recordMatchedName(beanName);
}
else {
result.recordUnmatchedName(beanName);
}
}
return result;
}
```
- 在`MatchResult result = new MatchResult()` 之前的代码作用是确认ioc容器
#### getNamesOfBeansIgnoredByType
```java
/**
* 获取忽略的beans(返回对象是 beanName)
* 循环,忽略的类型, 将类型从 beanFactory 获取,返回
*/
private Set<String> getNamesOfBeansIgnoredByType(ClassLoader classLoader, ListableBeanFactory beanFactory,
boolean considerHierarchy, Set<String> ignoredTypes, Set<Class<?>> parameterizedContainers) {
Set<String> result = null;
for (String ignoredType : ignoredTypes) {
// 从 beanFactory 中获取忽略的beanNames
Collection<String> ignoredNames = getBeanNamesForType(classLoader, considerHierarchy, beanFactory,
ignoredType, parameterizedContainers);
result = addAll(result, ignoredNames);
}
return (result != null) ? result : Collections.emptySet();
}
```
#### getBeanNamesForType
```java
/**
* 通过类型获取 beanName
*/
private Set<String> getBeanNamesForType(ClassLoader classLoader, boolean considerHierarchy,
ListableBeanFactory beanFactory, String type, Set<Class<?>> parameterizedContainers) throws LinkageError {
try {
// 从beanFactory 中获取忽略的类 返回beanNanme
return getBeanNamesForType(beanFactory, considerHierarchy, resolve(type, classLoader),
parameterizedContainers);
}
catch (ClassNotFoundException | NoClassDefFoundError ex) {
return Collections.emptySet();
}
}
```
#### getBeanNamesForType
```java
/**
* 通过类型获取 beanName
*/
private Set<String> getBeanNamesForType(ListableBeanFactory beanFactory, boolean considerHierarchy, Class<?> type,
Set<Class<?>> parameterizedContainers) {
// 获取beanName
Set<String> result = collectBeanNamesForType(beanFactory, considerHierarchy, type, parameterizedContainers,
null);
return (result != null) ? result : Collections.emptySet();
}
```
#### collectBeanNamesForType
- 这里最终回到了spring beanFactory 的方法 getBeanNamesForType
```java
private Set<String> collectBeanNamesForType(ListableBeanFactory beanFactory, boolean considerHierarchy,
Class<?> type, Set<Class<?>> parameterizedContainers, Set<String> result) {
result = addAll(result, beanFactory.getBeanNamesForType(type, true, false));
for (Class<?> container : parameterizedContainers) {
ResolvableType generic = ResolvableType.forClassWithGenerics(container, type);
result = addAll(result, beanFactory.getBeanNamesForType(generic, true, false));
}
if (considerHierarchy && beanFactory instanceof HierarchicalBeanFactory) {
BeanFactory parent = ((HierarchicalBeanFactory) beanFactory).getParentBeanFactory();
if (parent instanceof ListableBeanFactory) {
result = collectBeanNamesForType((ListableBeanFactory) parent, considerHierarchy, type,
parameterizedContainers, result);
}
}
return result;
}
```
到这里需要忽略的beanName 就全部找出来了
```java
// 匹配类型在移除
for (String type : spec.getTypes()) {
// 通过类型获取 beanName
Collection<String> typeMatches = getBeanNamesForType(classLoader, considerHierarchy, beanFactory, type,
parameterizedContainers);
typeMatches.removeAll(beansIgnoredByType);
if (typeMatches.isEmpty()) {
result.recordUnmatchedType(type);
}
else {
result.recordMatchedType(type, typeMatches);
}
}
// 注解匹配删除忽略的beanname
for (String annotation : spec.getAnnotations()) {
Set<String> annotationMatches = getBeanNamesForAnnotation(classLoader, beanFactory, annotation,
considerHierarchy);
annotationMatches.removeAll(beansIgnoredByType);
if (annotationMatches.isEmpty()) {
result.recordUnmatchedAnnotation(annotation);
}
else {
result.recordMatchedAnnotation(annotation, annotationMatches);
}
}
```
- 在忽略bean找到之后做一个类型移除的操作.
![image-20200825140750035](/images/SpringBoot//image-20200825140750035.png)
### 返回值
- 在返回之前做一堆判断条件. 一旦符合条件这个地方会做一个noMatch的一个对象(`ConditionOutcome`) 通过返回match对象`ConditionOutcome`
```java
public static ConditionOutcome noMatch(ConditionMessage message) {
return new ConditionOutcome(false, message);
}
```
```java
if (!matchResult.isAllMatched()) {
String reason = createOnBeanNoMatchReason(matchResult);
return ConditionOutcome.noMatch(spec.message().because(reason));
}
// 把注解解析出来获得文本
matchMessage = spec.message(matchMessage).found("bean", "beans").items(Style.QUOTE,
matchResult.getNamesOfAllMatches());
}
if (metadata.isAnnotated(ConditionalOnSingleCandidate.class.getName())) {
Spec<ConditionalOnSingleCandidate> spec = new SingleCandidateSpec(context, metadata, annotations);
MatchResult matchResult = getMatchingBeans(context, spec);
if (!matchResult.isAllMatched()) {
return ConditionOutcome.noMatch(spec.message().didNotFind("any beans").atAll());
}
else if (!hasSingleAutowireCandidate(context.getBeanFactory(), matchResult.getNamesOfAllMatches(),
spec.getStrategy() == SearchStrategy.ALL)) {
return ConditionOutcome.noMatch(spec.message().didNotFind("a primary bean from beans")
.items(Style.QUOTE, matchResult.getNamesOfAllMatches()));
}
matchMessage = spec.message(matchMessage).found("a primary bean from beans").items(Style.QUOTE,
matchResult.getNamesOfAllMatches());
}
if (metadata.isAnnotated(ConditionalOnMissingBean.class.getName())) {
Spec<ConditionalOnMissingBean> spec = new Spec<>(context, metadata, annotations,
ConditionalOnMissingBean.class);
MatchResult matchResult = getMatchingBeans(context, spec);
if (matchResult.isAnyMatched()) {
String reason = createOnMissingBeanNoMatchReason(matchResult);
return ConditionOutcome.noMatch(spec.message().because(reason));
}
matchMessage = spec.message(matchMessage).didNotFind("any beans").atAll();
}
return ConditionOutcome.match(matchMessage);
```
![image-20200825141506531](/images/SpringBoot//image-20200825141506531.png)
- 到此结果封装完毕.回到方法`org.springframework.boot.autoconfigure.condition.SpringBootCondition#matches(org.springframework.context.annotation.ConditionContext, org.springframework.core.type.AnnotatedTypeMetadata)` 继续进行
- 再往后就继续执行spring的bean初始化咯
## MessageSourceAutoConfiguration
- 启动阶段的一个类运行解读
- `org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration`
```java
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(name = AbstractApplicationContext.MESSAGE_SOURCE_BEAN_NAME, search = SearchStrategy.CURRENT)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Conditional(ResourceBundleCondition.class)
@EnableConfigurationProperties
public class MessageSourceAutoConfiguration {}
```
- 根据类的注解信息我们可以找到有`ResourceBundleCondition`
![image-20200825092343271](/images/SpringBoot//image-20200825092343271.png)
- 获取类名或者方法名的结果是`MessageSourceAutoConfiguration`全路径
- 继续往下是一个比较的方法(是否符合match)
`org.springframework.boot.autoconfigure.condition.SpringBootCondition#getMatchOutcome`这个方法是一个抽象方法子类实现
- 上图中红框内标注的类为`org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration.ResourceBundleCondition`
同时继承`org.springframework.boot.autoconfigure.condition.SpringBootCondition`
并且重写了方法`getMatchOutcome`
```java
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 从 容器中获取
String basename = context.getEnvironment().getProperty("spring.messages.basename", "messages");
// 从缓存中获取条件信息
ConditionOutcome outcome = cache.get(basename);
if (outcome == null) {
// 生成条件信息对象
outcome = getMatchOutcomeForBasename(context, basename);
// 放入缓存
cache.put(basename, outcome);
}
return outcome;
}
```
这个方法主要将比较信息放入,
- 后续的行为依然是判断是否匹配,匹配就创建.
## Spring Boot 启动阶段的自动注入
```java
org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#filter
```
```java
private List<String> filter(List<String> configurations, AutoConfigurationMetadata autoConfigurationMetadata) {
long startTime = System.nanoTime();
String[] candidates = StringUtils.toStringArray(configurations);
boolean[] skip = new boolean[candidates.length];
boolean skipped = false;
// 获取 AutoConfigurationImportFilter 相关配置
for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
// 执行 aware 相关接口
invokeAwareMethods(filter);
// 是否可以初始化的结果
boolean[] match = filter.match(candidates, autoConfigurationMetadata);
for (int i = 0; i < match.length; i++) {
if (!match[i]) {
// 是否跳过
skip[i] = true;
candidates[i] = null;
skipped = true;
}
}
}
if (!skipped) {
return configurations;
}
List<String> result = new ArrayList<>(candidates.length);
// 处理最终需要的类
for (int i = 0; i < candidates.length; i++) {
if (!skip[i]) {
result.add(candidates[i]);
}
}
if (logger.isTraceEnabled()) {
int numberFiltered = configurations.size() - result.size();
logger.trace("Filtered " + numberFiltered + " auto configuration class in "
+ TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + " ms");
}
return new ArrayList<>(result);
}
```
- 在这里有一个关注点 循环方法`getAutoConfigurationImportFilters()`
```JAVA
protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {
return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader);
}
```
在`spring.factories`文件中找到`AutoConfigurationImportFilter`后面的值
```properties
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
org.springframework.boot.autoconfigure.condition.OnClassCondition,\
org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition
```
- 此时我们可以和前文的源码分析连接起来有一个完整的认识了
![image-20200825142332485](/images/SpringBoot//image-20200825142332485.png)
- 最后来看整体类图
![image-20200825142418115](/images/SpringBoot//image-20200825142418115.png)

@ -0,0 +1,859 @@
# Nacos 服务注册
- nacos-spring-boot-project 中有关服务注册的几个项目
- nacos-discovery-spring-boot-actuator
nacos-discovery-spring-boot-autoconfigure
nacos-discovery-spring-boot-starter
```properties
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.alibaba.boot.nacos.discovery.autoconfigure.NacosDiscoveryAutoConfiguration
```
找到注解`NacosDiscoveryAutoConfiguration`
```java
@ConditionalOnProperty(name = NacosDiscoveryConstants.ENABLED, matchIfMissing = true)
@ConditionalOnMissingBean(name = DISCOVERY_GLOBAL_NACOS_PROPERTIES_BEAN_NAME)
@EnableNacosDiscovery
@EnableConfigurationProperties(value = NacosDiscoveryProperties.class)
@ConditionalOnClass(name = "org.springframework.boot.context.properties.bind.Binder")
public class NacosDiscoveryAutoConfiguration {
@Bean
public NacosDiscoveryAutoRegister discoveryAutoRegister() {
return new NacosDiscoveryAutoRegister();
}
}
```
- 注解:`EnableNacosDiscovery`
```java
@Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(NacosDiscoveryBeanDefinitionRegistrar.class)
public @interface EnableNacosDiscovery {}
```
- import 类 :`NacosDiscoveryBeanDefinitionRegistrar`
```java
public class NacosDiscoveryBeanDefinitionRegistrar
implements ImportBeanDefinitionRegistrar, EnvironmentAware {
private Environment environment;
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
AnnotationAttributes attributes = AnnotationAttributes
.fromMap(importingClassMetadata
.getAnnotationAttributes(EnableNacosDiscovery.class.getName()));
// Register Global Nacos Properties Bean
registerGlobalNacosProperties(attributes, registry, environment,
DISCOVERY_GLOBAL_NACOS_PROPERTIES_BEAN_NAME);
registerGlobalNacosProperties(attributes, registry, environment,
MAINTAIN_GLOBAL_NACOS_PROPERTIES_BEAN_NAME);
// Register Nacos Common Beans
registerNacosCommonBeans(registry);
// Register Nacos Discovery Beans
registerNacosDiscoveryBeans(registry);
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
}
```
- 两个流程
1. 将注解`EnableNacosDiscovery`的属性读取,放入到 nacos 的全局属性配置中
2. bean 注入
## nacos 全局配置属性
- `com.alibaba.nacos.spring.context.annotation.discovery.NacosDiscoveryBeanDefinitionRegistrar#registerBeanDefinitions`
- `com.alibaba.nacos.spring.util.NacosBeanUtils#registerGlobalNacosProperties(org.springframework.core.annotation.AnnotationAttributes, org.springframework.beans.factory.support.BeanDefinitionRegistry, org.springframework.core.env.PropertyResolver, java.lang.String)`
```java
public static void registerGlobalNacosProperties(AnnotationAttributes attributes,
BeanDefinitionRegistry registry, PropertyResolver propertyResolver,
String beanName) {
if (attributes == null) {
return; // Compatible with null
}
AnnotationAttributes globalPropertiesAttributes = attributes
.getAnnotation("globalProperties");
registerGlobalNacosProperties((Map<?, ?>) globalPropertiesAttributes, registry,
propertyResolver, beanName);
}
```
- 贴出注解上的信息
```JAVA
NacosProperties globalProperties() default @NacosProperties(username = USERNAME_PLACEHOLDER, password = PASSWORD_PLACEHOLDER, endpoint = ENDPOINT_PLACEHOLDER, namespace = NAMESPACE_PLACEHOLDER, accessKey = ACCESS_KEY_PLACEHOLDER, secretKey = SECRET_KEY_PLACEHOLDER, serverAddr = SERVER_ADDR_PLACEHOLDER, contextPath = CONTEXT_PATH_PLACEHOLDER, clusterName = CLUSTER_NAME_PLACEHOLDER, encode = ENCODE_PLACEHOLDER);
```
- 通过下面这段代码会将注解信息获取到对象`AnnotationAttributes globalPropertiesAttributes`中
```java
AnnotationAttributes globalPropertiesAttributes = attributes
.getAnnotation("globalProperties");
```
- 下一段代码是将属性换算出来
```java
registerGlobalNacosProperties((Map<?, ?>) globalPropertiesAttributes, registry,
propertyResolver, beanName)
public static void registerGlobalNacosProperties(Map<?, ?> globalPropertiesAttributes,
BeanDefinitionRegistry registry, PropertyResolver propertyResolver,
String beanName) {
// 占位符解析成具体的配置信息
Properties globalProperties = resolveProperties(globalPropertiesAttributes,
propertyResolver);
// 单例注册
registerSingleton(registry, beanName, globalProperties);
}
```
![image-20200821111938485](/images/nacos/image-20200821111938485.png)
## registerNacosCommonBeans
```
public static void registerNacosCommonBeans(BeanDefinitionRegistry registry) {
// Register NacosApplicationContextHolder Bean
registerNacosApplicationContextHolder(registry);
// Register AnnotationNacosInjectedBeanPostProcessor Bean
registerAnnotationNacosInjectedBeanPostProcessor(registry);
}
```
- 主要方法: registerInfrastructureBean
1. 定义出bean
2. 设置构造参数
3. 注册对象
```java
public static void registerInfrastructureBean(BeanDefinitionRegistry registry,
String beanName, Class<?> beanClass, Object... constructorArgs) {
// Build a BeanDefinition for NacosServiceFactory class
// 定义出 bean 根据类型
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder
.rootBeanDefinition(beanClass);
for (Object constructorArg : constructorArgs) {
beanDefinitionBuilder.addConstructorArgValue(constructorArg);
}
// ROLE_INFRASTRUCTURE
beanDefinitionBuilder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// Register
registry.registerBeanDefinition(beanName,
beanDefinitionBuilder.getBeanDefinition());
}
```
## @EnableConfigurationProperties(value = NacosDiscoveryProperties.class)
属性读取从application配置文件中读取数据转换成java对象。
![image-20200821132413628](/images/nacos/image-20200821132413628.png)
## NacosDiscoveryAutoRegister
```java
public class NacosDiscoveryAutoRegister
implements ApplicationListener<WebServerInitializedEvent> {}
```
- 处理一个`WebServerInitializedEvent` 事件的方法
- 重写方法如下,主要工作内容
1. 把服务发现配置读取出来
2. 设置一些数据值
3. 调用服务注册接口
```java
@Override
public void onApplicationEvent(WebServerInitializedEvent event) {
if (!discoveryProperties.isAutoRegister()) {
return;
}
Register register = discoveryProperties.getRegister();
if (StringUtils.isEmpty(register.getIp())) {
register.setIp(NetUtils.localIP());
}
if (register.getPort() == 0) {
register.setPort(event.getWebServer().getPort());
}
register.getMetadata().put("preserved.register.source", "SPRING_BOOT");
register.setInstanceId("");
String serviceName = register.getServiceName();
if (StringUtils.isEmpty(serviceName)){
if (StringUtils.isEmpty(applicationName)){
throw new AutoRegisterException("serviceName notNull");
}
serviceName = applicationName;
}
try {
namingService.registerInstance(serviceName, register.getGroupName(),
register);
logger.info("Finished auto register service : {}, ip : {}, port : {}",
serviceName, register.getIp(), register.getPort());
} catch (NacosException e) {
throw new AutoRegisterException(e);
}
}
```
- 注册的参数
![image-20200821133350982](/images/nacos/image-20200821133350982.png)
## 服务注册
![image-20200821133445090](/images/nacos/image-20200821133445090.png)
- 注册一个实例
1. 将 instance 对象转换成 BeatInfo 对象
2. 注册实例
```java
@Override
public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {
if (instance.isEphemeral()) {
// 实例信息转换
BeatInfo beatInfo = new BeatInfo();
beatInfo.setServiceName(NamingUtils.getGroupedName(serviceName, groupName));
beatInfo.setIp(instance.getIp());
beatInfo.setPort(instance.getPort());
beatInfo.setCluster(instance.getClusterName());
beatInfo.setWeight(instance.getWeight());
beatInfo.setMetadata(instance.getMetadata());
beatInfo.setScheduled(false);
beatInfo.setPeriod(instance.getInstanceHeartBeatInterval());
// 插入这条实例的信息
beatReactor.addBeatInfo(NamingUtils.getGroupedName(serviceName, groupName),
beatInfo);
}
serverProxy.registerService(NamingUtils.getGroupedName(serviceName, groupName), groupName, instance);
}
```
- addBeatInfo
- 创建了一个定时任务 BeatTask
```java
public void addBeatInfo(String serviceName, BeatInfo beatInfo) {
NAMING_LOGGER.info("[BEAT] adding beat: {} to beat map.", beatInfo);
String key = buildKey(serviceName, beatInfo.getIp(), beatInfo.getPort());
BeatInfo existBeat = null;
//fix #1733
if ((existBeat = dom2Beat.remove(key)) != null) {
existBeat.setStopped(true);
}
dom2Beat.put(key, beatInfo);
executorService.schedule(new BeatTask(beatInfo), beatInfo.getPeriod(), TimeUnit.MILLISECONDS);
MetricsMonitor.getDom2BeatSizeMonitor().set(dom2Beat.size());
}
```
### BeatTask
```
class BeatTask implements Runnable {
BeatInfo beatInfo;
public BeatTask(BeatInfo beatInfo) {
this.beatInfo = beatInfo;
}
@Override
public void run() {
if (beatInfo.isStopped()) {
return;
}
long nextTime = beatInfo.getPeriod();
try {
// 与nacos进行一次rest请求交互
JSONObject result = serverProxy.sendBeat(beatInfo, BeatReactor.this.lightBeatEnabled);
long interval = result.getIntValue("clientBeatInterval");
boolean lightBeatEnabled = false;
if (result.containsKey(CommonParams.LIGHT_BEAT_ENABLED)) {
lightBeatEnabled = result.getBooleanValue(CommonParams.LIGHT_BEAT_ENABLED);
}
BeatReactor.this.lightBeatEnabled = lightBeatEnabled;
if (interval > 0) {
nextTime = interval;
}
int code = NamingResponseCode.OK;
if (result.containsKey(CommonParams.CODE)) {
code = result.getIntValue(CommonParams.CODE);
}
// 如果nacos找不到当前实例,
if (code == NamingResponseCode.RESOURCE_NOT_FOUND) {
Instance instance = new Instance();
instance.setPort(beatInfo.getPort());
instance.setIp(beatInfo.getIp());
instance.setWeight(beatInfo.getWeight());
instance.setMetadata(beatInfo.getMetadata());
instance.setClusterName(beatInfo.getCluster());
instance.setServiceName(beatInfo.getServiceName());
instance.setInstanceId(instance.getInstanceId());
instance.setEphemeral(true);
try {
// 执行注册服务
serverProxy.registerService(beatInfo.getServiceName(),
NamingUtils.getGroupName(beatInfo.getServiceName()), instance);
} catch (Exception ignore) {
}
}
} catch (NacosException ne) {
NAMING_LOGGER.error("[CLIENT-BEAT] failed to send beat: {}, code: {}, msg: {}",
JSON.toJSONString(beatInfo), ne.getErrCode(), ne.getErrMsg());
}
executorService.schedule(new BeatTask(beatInfo), nextTime, TimeUnit.MILLISECONDS);
}
}
```
- 定时任务说明
1. 和nacos进行一次交互根据交互结果的code判断,如果不在nacos会执行注册.
- 发送请求的方法
```java
public String reqAPI(String api, Map<String, String> params, String body, List<String> servers, String method) throws NacosException {
params.put(CommonParams.NAMESPACE_ID, getNamespaceId());
if (CollectionUtils.isEmpty(servers) && StringUtils.isEmpty(nacosDomain)) {
throw new NacosException(NacosException.INVALID_PARAM, "no server available");
}
NacosException exception = new NacosException();
if (servers != null && !servers.isEmpty()) {
Random random = new Random(System.currentTimeMillis());
int index = random.nextInt(servers.size());
for (int i = 0; i < servers.size(); i++) {
// 获取nacos所在的ip+port地址
String server = servers.get(index);
try {
// 进行请求
return callServer(api, params, body, server, method);
} catch (NacosException e) {
exception = e;
if (NAMING_LOGGER.isDebugEnabled()) {
NAMING_LOGGER.debug("request {} failed.", server, e);
}
}
index = (index + 1) % servers.size();
}
}
if (StringUtils.isNotBlank(nacosDomain)) {
for (int i = 0; i < UtilAndComs.REQUEST_DOMAIN_RETRY_COUNT; i++) {
try {
return callServer(api, params, body, nacosDomain, method);
} catch (NacosException e) {
exception = e;
if (NAMING_LOGGER.isDebugEnabled()) {
NAMING_LOGGER.debug("request {} failed.", nacosDomain, e);
}
}
}
}
NAMING_LOGGER.error("request: {} failed, servers: {}, code: {}, msg: {}",
api, servers, exception.getErrCode(), exception.getErrMsg());
throw new NacosException(exception.getErrCode(), "failed to req API:/api/" + api + " after all servers(" + servers + ") tried: "
+ exception.getMessage());
}
```
**学习点**
- 这里采用随机值作为第一个server的获取主要目的是为了将请求随机分配给不同的nacos服务
如果直接使用for循环的索引那第一台nacos服务会收到所有的请求直到这台服务坏了才会请求第二台
Random random = new Random(System.currentTimeMillis());
int index = random.nextInt(servers.size());
for (int i = 0; i < servers.size(); i++) {
// 获取nacos所在的ip+port地址
String server = servers.get(index);
try {
// 进行请求
return callServer(api, params, body, server, method);
} catch (NacosException e) {
exception = e;
if (NAMING_LOGGER.isDebugEnabled()) {
NAMING_LOGGER.debug("request {} failed.", server, e);
}
}
index = (index + 1) % servers.size();
}
}
### registerService
- 注册方法就是请求一次接口将数据发送给nacos就完成了
```java
public void registerService(String serviceName, String groupName, Instance instance) throws NacosException {
NAMING_LOGGER.info("[REGISTER-SERVICE] {} registering service {} with instance: {}",
namespaceId, serviceName, instance);
final Map<String, String> params = new HashMap<String, String>(9);
params.put(CommonParams.NAMESPACE_ID, namespaceId);
params.put(CommonParams.SERVICE_NAME, serviceName);
params.put(CommonParams.GROUP_NAME, groupName);
params.put(CommonParams.CLUSTER_NAME, instance.getClusterName());
params.put("ip", instance.getIp());
params.put("port", String.valueOf(instance.getPort()));
params.put("weight", String.valueOf(instance.getWeight()));
params.put("enable", String.valueOf(instance.isEnabled()));
params.put("healthy", String.valueOf(instance.isHealthy()));
params.put("ephemeral", String.valueOf(instance.isEphemeral()));
params.put("metadata", JSON.toJSONString(instance.getMetadata()));
reqAPI(UtilAndComs.NACOS_URL_INSTANCE, params, HttpMethod.POST);
}
```
- 服务注册的接口
- `/nacos/v1/ns/instance`
- `/nacos/v1/ns/instance/beat`
- 接下来去寻找这两个接口的实现
`com.alibaba.nacos.naming.controllers.InstanceController`
## nacos 服务端
### 实例注册
```java
public void registerInstance(String namespaceId, String serviceName, Instance instance) throws NacosException {
// 创建空服务
createEmptyService(namespaceId, serviceName, instance.isEphemeral());
Service service = getService(namespaceId, serviceName);
if (service == null) {
throw new NacosException(NacosException.INVALID_PARAM,
"service not found, namespace: " + namespaceId + ", service: " + serviceName);
}
addInstance(namespaceId, serviceName, instance.isEphemeral(), instance);
}
```
- 创建空服务的流程
- 获取服务对象
nacos 的服务信息存储在
`com.alibaba.nacos.naming.core.ServiceManager#serviceMap`
```java
private Map<String, Map<String, Service>> serviceMap = new ConcurrentHashMap<>();
```
```java
public void createServiceIfAbsent(String namespaceId, String serviceName, boolean local, Cluster cluster) throws NacosException {
// 获取服务信息
Service service = getService(namespaceId, serviceName);
if (service == null) {
Loggers.SRV_LOG.info("creating empty service {}:{}", namespaceId, serviceName);
service = new Service();
service.setName(serviceName);
service.setNamespaceId(namespaceId);
service.setGroupName(NamingUtils.getGroupName(serviceName));
// now validate the service. if failed, exception will be thrown
service.setLastModifiedMillis(System.currentTimeMillis());
service.recalculateChecksum();
if (cluster != null) {
cluster.setService(service);
service.getClusterMap().put(cluster.getName(), cluster);
}
service.validate();
putServiceAndInit(service);
if (!local) {
addOrReplaceService(service);
}
}
}
```
- 在了解map结构后不难理解下面这个获取Service的方法了
```JAVA
public Service getService(String namespaceId, String serviceName) {
if (serviceMap.get(namespaceId) == null) {
return null;
}
return chooseServiceMap(namespaceId).get(serviceName);
}
```
```java
private void putServiceAndInit(Service service) throws NacosException {
putService(service);
service.init();
consistencyService.listen(KeyBuilder.buildInstanceListKey(service.getNamespaceId(), service.getName(), true), service);
consistencyService.listen(KeyBuilder.buildInstanceListKey(service.getNamespaceId(), service.getName(), false), service);
Loggers.SRV_LOG.info("[NEW-SERVICE] {}", service.toJSON());
}
```
- 把服务加入map对象
```java
public void putService(Service service) {
if (!serviceMap.containsKey(service.getNamespaceId())) {
synchronized (putServiceLock) {
if (!serviceMap.containsKey(service.getNamespaceId())) {
serviceMap.put(service.getNamespaceId(), new ConcurrentHashMap<>(16));
}
}
}
serviceMap.get(service.getNamespaceId()).put(service.getName(), service);
}
```
- init 方法设置了一个数据验证的任务 并且在集群中设置service信息
```java
public void init() {
HealthCheckReactor.scheduleCheck(clientBeatCheckTask);
for (Map.Entry<String, Cluster> entry : clusterMap.entrySet()) {
entry.getValue().setService(this);
entry.getValue().init();
}
}
```
- 再往后添加两个key的监听
- addInstance 方法
```java
public void addInstance(String namespaceId, String serviceName, boolean ephemeral, Instance... ips) throws NacosException {
String key = KeyBuilder.buildInstanceListKey(namespaceId, serviceName, ephemeral);
Service service = getService(namespaceId, serviceName);
synchronized (service) {
List<Instance> instanceList = addIpAddresses(service, ephemeral, ips);
Instances instances = new Instances();
instances.setInstanceList(instanceList);
consistencyService.put(key, instances);
}
}
```
- 简单理解 consistencyService 结构信息
- key 定义的一个名字
- value : 实例的列表
### 实例健康检查
- 获取实例独享, 从 service 中根据集群名称获取实例列表 再根据ip + 端口 返回实例对象
```java
Instance instance = serviceManager.getInstance(namespaceId, serviceName, clusterName, ip, port);
```
```java
public Instance getInstance(String namespaceId, String serviceName, String cluster, String ip, int port) {
Service service = getService(namespaceId, serviceName);
if (service == null) {
return null;
}
List<String> clusters = new ArrayList<>();
clusters.add(cluster);
List<Instance> ips = service.allIPs(clusters);
if (ips == null || ips.isEmpty()) {
return null;
}
for (Instance instance : ips) {
if (instance.getIp().equals(ip) && instance.getPort() == port) {
return instance;
}
}
return null;
}
```
- 实例健康检查接口做的事件
1. 获取实例
1. 实例不存在注册实例
2. 获取服务
1. 服务不存在抛出异常
2. 服务存在执行一个心跳方法
3. 组装结果返回
```java
@CanDistro
@PutMapping("/beat")
@Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE)
public JSONObject beat(HttpServletRequest request) throws Exception {
JSONObject result = new JSONObject();
result.put("clientBeatInterval", switchDomain.getClientBeatInterval());
String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID,
Constants.DEFAULT_NAMESPACE_ID);
String clusterName = WebUtils.optional(request, CommonParams.CLUSTER_NAME,
UtilsAndCommons.DEFAULT_CLUSTER_NAME);
String ip = WebUtils.optional(request, "ip", StringUtils.EMPTY);
int port = Integer.parseInt(WebUtils.optional(request, "port", "0"));
String beat = WebUtils.optional(request, "beat", StringUtils.EMPTY);
RsInfo clientBeat = null;
if (StringUtils.isNotBlank(beat)) {
clientBeat = JSON.parseObject(beat, RsInfo.class);
}
if (clientBeat != null) {
if (StringUtils.isNotBlank(clientBeat.getCluster())) {
clusterName = clientBeat.getCluster();
}
ip = clientBeat.getIp();
port = clientBeat.getPort();
}
if (Loggers.SRV_LOG.isDebugEnabled()) {
Loggers.SRV_LOG.debug("[CLIENT-BEAT] full arguments: beat: {}, serviceName: {}", clientBeat, serviceName);
}
// 获取实例
Instance instance = serviceManager.getInstance(namespaceId, serviceName, clusterName, ip, port);
if (instance == null) {
if (clientBeat == null) {
result.put(CommonParams.CODE, NamingResponseCode.RESOURCE_NOT_FOUND);
return result;
}
instance = new Instance();
instance.setPort(clientBeat.getPort());
instance.setIp(clientBeat.getIp());
instance.setWeight(clientBeat.getWeight());
instance.setMetadata(clientBeat.getMetadata());
instance.setClusterName(clusterName);
instance.setServiceName(serviceName);
instance.setInstanceId(instance.getInstanceId());
instance.setEphemeral(clientBeat.isEphemeral());
serviceManager.registerInstance(namespaceId, serviceName, instance);
}
Service service = serviceManager.getService(namespaceId, serviceName);
if (service == null) {
throw new NacosException(NacosException.SERVER_ERROR,
"service not found: " + serviceName + "@" + namespaceId);
}
if (clientBeat == null) {
clientBeat = new RsInfo();
clientBeat.setIp(ip);
clientBeat.setPort(port);
clientBeat.setCluster(clusterName);
}
// 处理心跳方法
service.processClientBeat(clientBeat);
result.put(CommonParams.CODE, NamingResponseCode.OK);
result.put("clientBeatInterval", instance.getInstanceHeartBeatInterval());
result.put(SwitchEntry.LIGHT_BEAT_ENABLED, switchDomain.isLightBeatEnabled());
return result;
}
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Loading…
Cancel
Save