IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 深入SpringBoot源码(十一)SpringApplication与Environment的绑定(下) -> 正文阅读

[Java知识库]深入SpringBoot源码(十一)SpringApplication与Environment的绑定(下)

上一章讲到了SpringApplication的bindToSpringApplication的Binder.get(environment)方法, 这章接着讲Binder的bind方法。
在这里插入图片描述
bindToSpringApplication方法通过Binder.get(environment)方法得到了Binder实例,再调用bind(String name, Bindable target)方法使用此 binder的property sources绑定指定的目标Bindable。

	public <T> BindResult<T> bind(String name, Bindable<T> target) {
		return bind(ConfigurationPropertyName.of(name), target, null);
	}

	public <T> BindResult<T> bind(ConfigurationPropertyName name, Bindable<T> target, BindHandler handler) {
		T bound = bind(name, target, handler, false);
		return BindResult.of(bound);
	}
	
	private <T> T bind(ConfigurationPropertyName name, Bindable<T> target, BindHandler handler, boolean create) {
		Assert.notNull(name, "Name must not be null");
		Assert.notNull(target, "Target must not be null");
		handler = (handler != null) ? handler : this.defaultBindHandler;
		Context context = new Context();
		return bind(name, target, handler, context, false, create);
	}

	private <T> T bind(ConfigurationPropertyName name, Bindable<T> target, BindHandler handler, Context context,
			boolean allowRecursiveBinding, boolean create) {
		try {
			Bindable<T> replacementTarget = handler.onStart(name, target, context);
			if (replacementTarget == null) {
				return handleBindResult(name, target, handler, context, null, create);
			}
			target = replacementTarget;
			Object bound = bindObject(name, target, handler, context, allowRecursiveBinding);
			return handleBindResult(name, target, handler, context, bound, create);
		}
		catch (Exception ex) {
			return handleBindError(name, target, handler, context, ex);
		}
	}

Bindable是可以由Binder绑定的源,其ofInstance方法使用与该实例相等的现有值创建指定实例类型的新Bindable。

	public static <T> Bindable<T> ofInstance(T instance) {
		Assert.notNull(instance, "Instance must not be null");
		Class<T> type = (Class<T>) instance.getClass();
		return of(type).withExistingValue(instance);
	}
	
	/**
	 * 创建指定类型的新Bindable。
	 */
	public static <T> Bindable<T> of(Class<T> type) {
		Assert.notNull(type, "Type must not be null");
		return of(ResolvableType.forClass(type));
	}

	public static <T> Bindable<T> of(ResolvableType type) {
		Assert.notNull(type, "Type must not be null");
		ResolvableType boxedType = box(type);
		return new Bindable<>(type, boxedType, null, NO_ANNOTATIONS, NO_BIND_RESTRICTIONS);
	}

	private static ResolvableType box(ResolvableType type) {
		Class<?> resolved = type.resolve();
		if (resolved != null && resolved.isPrimitive()) {
			Object array = Array.newInstance(resolved, 1);
			Class<?> wrapperType = Array.get(array, 0).getClass();
			return ResolvableType.forClass(wrapperType);
		}
		if (resolved != null && resolved.isArray()) {
			return ResolvableType.forArrayComponent(box(type.getComponentType()));
		}
		return type;
	}

调用Bindable类的构造方法时,传入的参数如下:
在这里插入图片描述
在调用bind(ConfigurationPropertyName name, Bindable target, BindHandler handler, Context context, boolean allowRecursiveBinding, boolean create)方法时,传入的参数如下:
在这里插入图片描述
handleBindResult方法的源码:

	private <T> T handleBindResult(ConfigurationPropertyName name, Bindable<T> target, BindHandler handler,
			Context context, Object result, boolean create) throws Exception {
		if (result != null) {
			result = handler.onSuccess(name, target, context, result);
			result = context.getConverter().convert(result, target);
		}
		if (result == null && create) {
			result = create(target, context);
			result = handler.onCreate(name, target, context, result);
			result = context.getConverter().convert(result, target);
			Assert.state(result != null, () -> "Unable to create instance for " + target.getType());
		}
		handler.onFinish(name, target, context, result);
		return context.getConverter().convert(result, target);
	}

获取到的bound为null:
在这里插入图片描述
BindResult用于返回Binder绑定操作结果的容器对象,可能包含成功绑定的对象或空结果。BindResult的of方法:

	static <T> BindResult<T> of(T value) {
		if (value == null) {
			return (BindResult<T>) UNBOUND;
		}
		return new BindResult<>(value);
	}
	
	private static final BindResult<?> UNBOUND = new BindResult<>(null);

	private BindResult(T value) {
		this.value = value;
	}

在这里插入图片描述
在执行完bindToSpringApplication方法后,会判断当前环境是否是自定义环境,如果是,则会调用convertEnvironment方法:

	/**
	 * 将给定environment转换为不尝试直接解析配置文件属性的应用程序环境。
	 * @since 2.5.7
	 * @deprecated since 2.5.8 for removal in 2.7.0
	 */
	@Deprecated
	public StandardEnvironment convertEnvironment(ConfigurableEnvironment environment) {
		return new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
				deduceEnvironmentClass());
	}

由于绑定后的环境可能会被修改,所以需要再次执行ConfigurationPropertySources.attach方法在这里插入图片描述
在这里插入图片描述
SpringApplication的configureIgnoreBeanInfo方法:

	private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) {
		if (System.getProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME) == null) {
			Boolean ignore = environment.getProperty("spring.beaninfo.ignore", Boolean.class, Boolean.TRUE);
			System.setProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME, ignore.toString());
		}
	}

CachedIntrospectionResults是为Java 类缓存JavaBeans PropertyDescriptor信息的类,该类不适合应用程序代码直接使用。Spring自己在应用程序ClassLoader中缓存 bean 描述符所必需的,而不是依赖于 JDK 的系统范围的BeanInfo缓存(以避免在共享 JVM 中个别应用程序关闭时泄漏)。信息是静态缓存的,因此我们不需要为我们操作的每个 JavaBean 创建此类的新对象。因此,该类实现了工厂设计模式,使用私有构造函数和静态forClass(Class)工厂方法来获取实例。

	/**
	* 指示 Spring 在调用 JavaBeans Introspector时使用Introspector.IGNORE_ALL_BEANINFO模式的系统属性:
	* “spring.beaninfo.ignore”,值为“true”跳过对BeanInfo类的搜索(通常用于未定义此类类的场景首先用于应用程序中的 bean)。
	* 默认值为“false”,考虑所有BeanInfo元数据类,例如标准Introspector.getBeanInfo(Class)调用。
	* 如果遇到对不存在的BeanInfo类的重复ClassLoader访问,请考虑将此标志切换为“true”,以防此类访问在启动或延迟加载时代价高昂。
	*/
	public static final String IGNORE_BEANINFO_PROPERTY_NAME = "spring.beaninfo.ignore";

在这里插入图片描述

	private Banner printBanner(ConfigurableEnvironment environment) {
		if (this.bannerMode == Banner.Mode.OFF) {
			return null;
		}
		ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader
				: new DefaultResourceLoader(null);
		SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);
		if (this.bannerMode == Mode.LOG) {
			return bannerPrinter.print(environment, this.mainApplicationClass, logger);
		}
		return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
	}

printBanner方法用于打印Spring应用程序横幅
在这里插入图片描述
在这里插入图片描述
这里获取到banner是SpringBootBanner

class SpringBootBanner implements Banner {

	private static final String[] BANNER = { "", "  .   ____          _            __ _ _",
			" /\\\\ / ___'_ __ _ _(_)_ __  __ _ \\ \\ \\ \\", "( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\",
			" \\\\/  ___)| |_)| | | | | || (_| |  ) ) ) )", "  '  |____| .__|_| |_|_| |_\\__, | / / / /",
			" =========|_|==============|___/=/_/_/_/" };

	private static final String SPRING_BOOT = " :: Spring Boot :: ";

	private static final int STRAP_LINE_SIZE = 42;

	@Override
	public void printBanner(Environment environment, Class<?> sourceClass, PrintStream printStream) {
		for (String line : BANNER) {
			printStream.println(line);
		}
		String version = SpringBootVersion.getVersion();
		version = (version != null) ? " (v" + version + ")" : "";
		StringBuilder padding = new StringBuilder();
		while (padding.length() < STRAP_LINE_SIZE - (version.length() + SPRING_BOOT.length())) {
			padding.append(" ");
		}

		printStream.println(AnsiOutput.toString(AnsiColor.GREEN, SPRING_BOOT, AnsiColor.DEFAULT, padding.toString(),
				AnsiStyle.FAINT, version));
		printStream.println();
	}

}

printBanner运行后的结果如下:
在这里插入图片描述

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-04-22 18:22:34  更:2022-04-22 18:24:08 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 4:42:39-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码