SpringBoot2源码分析-3SpringApplication对象初始化

上一次我们看到SpringApplication run方法中的第二行代码,这次从第三行代码开始月度

DefaultBootstrapContext bootstrapContext = createBootstrapContext();

这行代码很明显是创建一个Context,可以理解是一个容器,或者说是一个map吧

private DefaultBootstrapContext createBootstrapContext() {
		DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
		this.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext));
		return bootstrapContext;
	}

这个createBootstrapContext就是创建一个bootstrapContext ,并将注册器都注册到bootstrapContext 中
这里有一个bootstrapRegistryInitializers这个是我们在new 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();
	this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories();
	setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
	setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
	this.mainApplicationClass = deduceMainApplicationClass();
}

1-4行不做太多解读,接下看看第5行

this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories();

进一步涨到方法查看里面的内容

private List<BootstrapRegistryInitializer> getBootstrapRegistryInitializersFromSpringFactories() {
	ArrayList<BootstrapRegistryInitializer> initializers = new ArrayList<>();
	getSpringFactoriesInstances(Bootstrapper.class).stream()
			.map((bootstrapper) -> ((BootstrapRegistryInitializer) bootstrapper::initialize))
			.forEach(initializers::add);
	initializers.addAll(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
	return initializers;
}

这里面的想法比诡异,虽然不知道为什么这么写,但是这段代码的意思很明确,初始化ArrayList<BootstrapRegistryInitializer> initializers
2个地方都用到了getSpringFactoriesInstances方法,接下来我们重点的关注getSpringFactoriesInstances

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
	return getSpringFactoriesInstances(type, new Class<?>[] {});
}

这里还不能看出来什么名堂,继续看他下一个重载

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;
}

这个方法得看了许多,就是用来初始化SpringFactoriesInstances,我们要看初始化了多少SpringFactoriesInstances,首先需要看这个方法SpringFactoriesLoader.loadFactoryNames(type, classLoader)

public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
	ClassLoader classLoaderToUse = classLoader;
	if (classLoaderToUse == null) {
		classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
	}
	String factoryTypeName = factoryType.getName();
	return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}

这里首先是看看classloader是不是为空,为空则默认一个classloader,可能是与多版本加载有关,先不管
接下来主要的方法还是loadSpringFactories(classLoaderToUse)其他基本可以忽略不看

private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
	Map<String, List<String>> result = cache.get(classLoader);
	if (result != null) {
		return result;
	}

	result = new HashMap<>();
	try {
		Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
		while (urls.hasMoreElements()) {
			URL url = urls.nextElement();
			UrlResource resource = new UrlResource(url);
			Properties properties = PropertiesLoaderUtils.loadProperties(resource);
			for (Map.Entry<?, ?> entry : properties.entrySet()) {
				String factoryTypeName = ((String) entry.getKey()).trim();
				String[] factoryImplementationNames =
						StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
				for (String factoryImplementationName : factoryImplementationNames) {
					result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
							.add(factoryImplementationName.trim());
				}
			}
		}

		// Replace all lists with unmodifiable lists containing unique elements
		result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
				.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
		cache.put(classLoader, result);
	}
	catch (IOException ex) {
		throw new IllegalArgumentException("Unable to load factories from location [" +
				FACTORIES_RESOURCE_LOCATION + "]", ex);
	}
	return result;
}

读到了这里我才恍然大悟,原来,选择classloade是多么的重要,classloder会检查类加载目录下的路径

在这里插入图片描述

public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";

也就是jar包的META-INF/spring.factories路径,我们看到一个简单的类初始化居然扫描并加载了2个jar的配置文件
在这里插入图片描述
到了这里我才恍然发现,网上很多大牛的文章一上来就说加载路径的事情,搞得我一脸懵逼,现在总算是明白是怎么回事了

最后一步找到这么工厂信息之后也只是初始化这些工厂信息了

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;
}

这里也只能算是完成了SpringApplication的初始化工作,更多的功能仍旧在
SpringApplication的run方法

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot项目中,初始化JdbcTemplate对象也非常简单。Spring Boot提供了自动配置的特性,可以根据项目的依赖和配置文件自动初始化JdbcTemplate对象。 以下是在Spring Boot项目中初始化JdbcTemplate对象的步骤: 1. 确保你的项目中已经引入了Spring Boot JDBC的依赖。在`pom.xml`文件中添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> ``` 2. 在`application.properties`或`application.yml`配置文件中配置数据库连接信息,包括URL、用户名和密码。 ```properties spring.datasource.url=jdbc:mysql://localhost:3306/mydatabase spring.datasource.username=username spring.datasource.password=password spring.datasource.driver-class-name=com.mysql.jdbc.Driver ``` 3. 在需要使用JdbcTemplate的地方,通过构造函数或依赖注入的方式注入JdbcTemplate对象。例如,在DAO类中使用JdbcTemplate对象: ```java import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; @Repository public class MyDAO { private final JdbcTemplate jdbcTemplate; public MyDAO(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } // 使用jdbcTemplate执行数据库操作 } ``` 4. 现在,JdbcTemplate对象已经初始化并可以在需要的地方进行使用。你可以在DAO类中使用`jdbcTemplate`对象执行各种数据库操作,例如执行SQL语句、查询数据等。 通过以上步骤,Spring Boot会根据配置文件中的数据库信息自动初始化JdbcTemplate对象,并将其注入到需要使用的地方。你可以在项目中的任何地方使用`jdbcTemplate`对象进行数据库操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值