>  기사  >  Java  >  SpringBoot spring.factories 로딩 타이밍 소스 코드 분석

SpringBoot spring.factories 로딩 타이밍 소스 코드 분석

WBOY
WBOY앞으로
2023-05-17 21:31:041312검색

spring.factories의 역할

이는 Java의 SPI 기능과 유사합니다. SpringBoot가 시작되면 모든 jar 패키지 아래의 META-INF/spring.factories 파일을 읽습니다.META-INF/spring.factories文件;

并且将文件中的 接口/抽象类 对应的实现类都对应起来,并在需要的时候可以实例化对应的实现类

下面我们来分析一下源码看看spring.factories的使用场景

源码解析

启动SpringApplication,看看构造方法

	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
		setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
	}

其中方法getSpringFactoriesInstances( ApplicationContextInitializer.class) 是用于获取Spring中指定类实例用的;并且获取的时候是根据读取整个项目中文件路径为META-INF/spring.factories 中的内容实例化对应的实例类的;

例如这里的ApplicationContextInitializer 是一个接口,那么应该实例化哪些他的实现类呢?那就找META-INF/spring.factories文件 ; 那么我们在spring-boot:2.1.0jar包中找到了这个文件

SpringBoot spring.factories 로딩 타이밍 소스 코드 분석

读取到需要实例化的实现类为

org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer

并且还在spring-boot-autoconfigure-2.1.0.RELEASE.jar中找到了这个文件

SpringBoot spring.factories 로딩 타이밍 소스 코드 분석

那么文件中的两个实现类也会被实例化;加上上面4个总共有6个

org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

SpringBoot spring.factories 로딩 타이밍 소스 코드 분석

可以看到不仅仅只是把org.springframework.context.ApplicationContextInitializer 的实例类解析了出来;而是所有的都解析了出来并且保存下来了.下次其他的类需要被实例化的时候就可以直接从内存里面拿了;

上面过程拿到了实例类之后,接下来就是实例化的过程了

	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
			Class<?>[] parameterTypes, Object... args) {
		ClassLoader classLoader = getClassLoader();
		// Use names and ensure unique to protect against duplicates
		Set<String> names = new LinkedHashSet<>(
				SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
				classLoader, args, names);
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}

方法createSpringFactoriesInstances就是创建实例的过程;可以看到传入了对应的接口类org.springframework.context.ApplicationContextInitializer ;接下来就会实例化 上面找到了对应的实现类;

	private <T> List<T> createSpringFactoriesInstances(Class<T> type,
			Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
			Set<String> names) {
		List<T> instances = new ArrayList<>(names.size());
		for (String name : names) {
			try {
				Class<?> instanceClass = ClassUtils.forName(name, classLoader);
				Assert.isAssignable(type, instanceClass);
				Constructor<?> constructor = instanceClass
						.getDeclaredConstructor(parameterTypes);
				T instance = (T) BeanUtils.instantiateClass(constructor, args);
				instances.add(instance);
			}
			catch (Throwable ex) {
				throw new IllegalArgumentException(
						"Cannot instantiate " + type + " : " + name, ex);
			}
		}
		return instances;
	}

实例化的过程如果,没有什么特别需要讲解的;

上面有个方法 AnnotationAwareOrderComparator.sort(instances);是用来排序所有实例的; 实现类需要实现 接口Ordered ; getOrder返回的值越小,优先级更高

用法

知道spring.factories的用法之后, 那么我们就可以利用这个特性实现自己的目的;

例如我们也可以写一个接口类ApplicationContextInitializer

인터페이스/추상 클래스에 해당하는 구현 클래스를 함께 매핑하고, 필요할 때 해당 구현 클래스를 인스턴스화할 수 있습니다.🎜🎜소스 코드를 분석하고 spring.factories의 사용 시나리오를 살펴보겠습니다. >🎜🎜 소스 코드 분석🎜🎜SpringApplication을 시작하고 생성 방법을 살펴보세요🎜rrreee🎜getSpringFactoriesInstances(ApplicationContextInitializer.class) 메서드는 Spring에서 지정된 클래스 인스턴스를 가져오는 데 사용되며, 이를 가져올 때, 전체 읽기를 기반으로 합니다. 프로젝트의 파일 경로는 해당 인스턴스 클래스를 인스턴스화하는 META-INF/spring.factories의 콘텐츠입니다. 🎜🎜예를 들어, ApplicationContextInitializer 여기에 인터페이스가 있으므로 인스턴스화해야 합니다. 어떤 다른 구현 클래스를 변환해야 합니까? 그런 다음 META-INF/spring.factories 파일을 찾으세요. spring-boot:2.1.0jar package🎜🎜SpringBoot spring.factories loading timing source code analyze🎜🎜필요한 구현 클래스를 읽어보세요. 인스턴스화된 파일은 🎜rrreee🎜이며 spring-boot-autoconfigure-2.1.0.RELEASE.jar🎜🎜SpringBoot spring.factories loading timing source code analyze🎜🎜그러면 파일의 두 구현 클래스도 인스턴스화됩니다. 위의 4개에 더해 총 6개 🎜rrreee🎜SpringBoot spring.factories 로딩 타이밍 소스 코드 분석 🎜🎜예, org.springframework.context.ApplicationContextInitializer의 인스턴스 클래스가 구문 분석될 뿐만 아니라 다음 번에 다른 클래스도 인스턴스화되어야 함을 확인하세요. 🎜🎜위 프로세스에서 인스턴스 클래스를 가져온 후 다음 단계는 인스턴스화 프로세스입니다. 🎜rrreee🎜createSpringFactoriesInstances 메서드는 인스턴스를 생성하는 프로세스입니다. 전달 해당 인터페이스 클래스 org.springframework.context.ApplicationContextInitializer를 입력한 다음 위에서 찾은 해당 구현 클래스를 인스턴스화합니다. 🎜rrreee🎜인스턴스화 프로세스에 대해 특별히 설명할 것이 없으면 ;🎜🎜있습니다. 모든 인스턴스를 정렬하는 데 사용되는 위의 메소드 Ordered; 우선 순위가 더 높습니다🎜

사용

🎜spring.factories의 사용법을 알고 나면 이 기능을 사용하여 원하는 목적을 달성할 수 있습니다.🎜🎜예를 들어 다음과 같이 할 수도 있습니다. ApplicationContextInitializer 클래스의 인터페이스 구현 클래스를 작성합니다. 🎜

위 내용은 SpringBoot spring.factories 로딩 타이밍 소스 코드 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 yisu.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제