spring-Cloud のサーキット ブレーカー メカニズムを使用すると、メソッド呼び出し時にエラーが報告されます。サーキット ブレーカー クラスは次のとおりです。
RemoteNettyServerServiceFallbackFactory.java
@Component
public class RemoteNettyServerServiceFallbackFactory implements FallbackFactory<RemoteNettyServerService> {
@Override
public RemoteNettyServerService create(Throwable throwable) {
RemoteNettyServerServiceFallbackImpl remoteNettyServerServiceFallback = new RemoteNettyServerServiceFallbackImpl();
remoteNettyServerServiceFallback.setCause(throwable);
return remoteNettyServerServiceFallback;
}
}
@component を追加するという解決策をインターネット上でたくさん見ましたが、それでも機能しません。
RemoteNettyServerServiceFallbackImpl.java
@Component
@Slf4j
public class RemoteNettyServerServiceFallbackImpl implements RemoteNettyServerService {
@Setter
private Throwable cause;
@Override
public Map<String, Object> startCharge(ChargeRemoteStartRequest chargeRemoteStartRequest , String from) {
log.error("feign 开始充电:{}", cause);
return null;
}
}
app-api-biz がモジュール間で netty-server-api モジュールを呼び出していることにもお気づきかと思いますが、app-api-biz のスタートアップ クラスを開始しただけでは、現在のアプリ モジュールの下にあるアノテーションのみをスキャンできますが、 netty-server-api の注釈。
これら 2 つのパッケージは異なります。したがって、@component アノテーションの追加はスキャンできません。では、どうすればよいでしょうか? springboot の自動読み込み設定のアノテーションは次のとおりであることがわかっています。
@EnableAutoConfiguration
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
最も重要なことは@Import(AutoConfigurationImportSelector.class)
、 SpringBoot の助けを借りてAutoConfigurationImportSelector
、@EnableAutoConfiguration
SpringBoot アプリケーションが@Configuration
現在作成され、SpringBoot によって使用されている IoC コンテナにすべての適格な構成をロードできるようになることです。
Springフレームワークの独自ツールクラスSpringFactoriesLoaderのサポートにより、@EnableAutoConfiguration
インテリジェントな自動設定機能がついに完成!
AutoConfigurationImportSelector クラスでは、 SpringFactoriesLoader.loadFactoryNames()
spring-boot-autoconfigure.jar/META-INF/spring.factories 内の各 xxxAutoConfiguration ファイルをコンテナーにロードすることによって、 spring.factories ファイル内の各 xxxAutoConfiguration ファイルには通常、次の条件アノテーションがあることがわかります。
- @ConditionalOnClass: クラスがクラスパスに存在する場合に有効になります。
- @ConditionalOnMissingClass: クラスがクラスパスに存在しない場合に有効になります。
- @ConditionalOnBean: このタイプの Bean が DI コンテナーに存在する場合に有効になります
- @ConditionalOnMissingBean: このタイプの Bean が DI コンテナーに存在しない場合に有効になります。
- @ConditionalOnSingleCandidate: DI コンテナ内にこのタイプの Bean が 1 つだけ、または @Primary が 1 つだけある場合に有効になります。
- @ConditionalOnExpression: SpEL 式の結果が true の場合
- @ConditionalOnProperty: パラメーターの設定または値が一致している場合に有効になります。
- @ConditionalOnResource: 指定されたファイルが存在する場合に有効になります
- @ConditionalOnJndi: 指定された JNDI が存在する場合に有効になります。
- @ConditionalOnJava: 指定された Java バージョンが存在する場合に有効になります
- @ConditionalOnWebApplication: Web アプリケーション環境で効果的
- @ConditionalOnNotWebApplication: 非 Web アプリケーション環境で効果的
AutoConfigurationImportSelector.java下的一段代码:
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
return configurations;
}
SpringFactoriesLoader は、Spring フレームワークのプライベート拡張スキームです (Java の SPI スキーム java.util.ServiceLoader に似ています)。その主な機能は、指定された構成ファイルから構成をロードすることです。spring-factories は典型的な Java プロパティ ファイルですが、KeyMETA-INF/spring-factories
と値は、Java 型の完全なクラス名です。
の場合@EnableAutoConfiguration
、SpringFactoriesLoader の目的は少し異なります。その本来の目的は SPI 拡張シナリオを提供することであり、この@EnableAutoConfiguration
シナリオでは、構成検索のためのより機能的なサポートを提供します。つまり、検索キーとして@EnableAutoConfiguration
完全なクラス名に基づいて、org.springframework.boot.autoconfig.EnableAutoConfiguration
対応するクラスのセット@Configuration
。
SpringFactoriesLoader は抽象クラスです。クラスで定義された静的プロパティは、リソースをロードするためのパスを定義しますpublic static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"
。さらに、次の 3 つの静的メソッドがあります。
- loadFactories: 指定されたfactoryClassをロードし、インスタンス化します。
- loadFactoryNames: 指定されたfactoryClassの名前コレクションをロードします。
- instantiateFactory: 指定されたfactoryClassをインスタンス化します。
loadFactoryNames メソッドと instantiateFactory メソッドは、loadFactories メソッドで呼び出されます。
public final class SpringFactoriesLoader {
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
private static final Log logger = LogFactory.getLog(SpringFactoriesLoader.class);
private static final Map<ClassLoader, MultiValueMap<String, String>> cache = new ConcurrentReferenceHashMap();
private SpringFactoriesLoader() {
}
public static <T> List<T> loadFactories(Class<T> factoryType, @Nullable ClassLoader classLoader) {
Assert.notNull(factoryType, "'factoryType' must not be null");
ClassLoader classLoaderToUse = classLoader;
if (classLoader == 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());
Iterator var5 = factoryImplementationNames.iterator();
while(var5.hasNext()) {
String factoryImplementationName = (String)var5.next();
result.add(instantiateFactory(factoryImplementationName, factoryType, classLoaderToUse));
}
AnnotationAwareOrderComparator.sort(result);
return result;
}
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
if (result != null) {
return result;
} else {
try {
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
LinkedMultiValueMap result = new LinkedMultiValueMap();
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
Iterator var6 = properties.entrySet().iterator();
while(var6.hasNext()) {
Entry<?, ?> entry = (Entry)var6.next();
String factoryTypeName = ((String)entry.getKey()).trim();
String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
int var10 = var9.length;
for(int var11 = 0; var11 < var10; ++var11) {
String factoryImplementationName = var9[var11];
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
cache.put(classLoader, result);
return result;
} catch (IOException var13) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
}
}
}
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() + "]");
} else {
return ReflectionUtils.accessibleConstructor(factoryImplementationClass, new Class[0]).newInstance();
}
} catch (Throwable var4) {
throw new IllegalArgumentException("Unable to instantiate factory class [" + factoryImplementationName + "] for factory type [" + factoryType.getName() + "]", var4);
}
}
}
loadFactories メソッドは、最初にクラス ローダーを取得し、次にloadFactoryNames
メソッドを呼び出して指定されたすべてのリソースの名前コレクションを取得し、次にinstantiateFactory
メソッドを呼び出してこれらのリソース クラスをインスタンス化し、結果コレクションに追加します。最後に、AnnotationAwareOrderComparator.sort
メソッドを呼び出してコレクションを並べ替えます。
これらの知識ポイントを理解したら、問題を振り返って解決することができます。
この場合、サービス間呼び出しが可能であり、nettyモジュールが起動していなくても、API呼び出し時にはフォールバックが使用され、このクラスが使用されます。
終わり