当前位置: 首页 > news >正文

Sping源码(六)— prepareBeanFactory()

前言

前几篇已经介绍lBeanFactory的创建已经xml配置文件中自定义标签和默认标签的解析过程,此时的BeanFactory中已经包含了xml文件中的标签属性。但BeanFactory中还有一些本身重要的属性没有填充,所以接着方法继续往下看BeanFactory中的属性是如何填充的。

refresh
refresh()主流程中前几个方法已经介绍过,这里不过多赘述,去掉后面的无用代码,我们这篇帖子主要看prepareBeanFactory方法中做了些什么。

public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing./*** 前戏,做容器刷新前的准备工作* 1、设置容器的启动时间* 2、设置活跃状态为true* 3、设置关闭状态为false* 4、获取Environment对象,并加载当前系统的属性值到Environment对象中* 5、准备监听器和事件的集合对象,默认为空的集合*/prepareRefresh();// Tell the subclass to refresh the internal bean factory.// 创建容器对象:DefaultListableBeanFactory// 加载xml配置文件的属性值到当前工厂中,最重要的就是BeanDefinitionConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.// beanFactory的准备工作,对各种属性进行填充prepareBeanFactory(beanFactory);}}

prepareBeanFactory
见名知意,这个方法中也是为了BeanFactory做准备工作,所以刚上来设置了BeanFacroty的类加载器。

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {// Tell the internal bean factory to use the context's class loader etc.// 设置beanFactory的classloader为当前context的classloaderbeanFactory.setBeanClassLoader(getClassLoader());// 设置beanfactory的表达式语言处理器beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));// 为beanFactory增加一个默认的propertyEditor,这个主要是对bean的属性等设置管理的一个工具类beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));// Configure the bean factory with context callbacks.// 添加beanPostProcessor,ApplicationContextAwareProcessor此类用来完成某些Aware对象的注入beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));// 设置要忽略自动装配的接口,这些接口的实现是由容器通过set方法进行注入的,// 所以在使用autowire进行注入的时候需要将这些接口进行忽略beanFactory.ignoreDependencyInterface(EnvironmentAware.class);beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);beanFactory.ignoreDependencyInterface(MessageSourceAware.class);beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);// BeanFactory interface not registered as resolvable type in a plain factory.// MessageSource registered (and found for autowiring) as a bean.// 设置几个自动装配的特殊规则,当在进行ioc初始化的如果有多个实现,那么就使用指定的对象进行注入beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);beanFactory.registerResolvableDependency(ResourceLoader.class, this);beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);beanFactory.registerResolvableDependency(ApplicationContext.class, this);// Register early post-processor for detecting inner beans as ApplicationListeners.// 注册BPPbeanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));// Detect a LoadTimeWeaver and prepare for weaving, if found.// 增加对AspectJ的支持,在java中织入分为三种方式,分为编译器织入,类加载器织入,运行期织入,编译器织入是指在java编译器,采用特殊的编译器,将切面织入到java类中,// 而类加载期织入则指通过特殊的类加载器,在类字节码加载到JVM时,织入切面,运行期织入则是采用cglib和jdk进行切面的织入// aspectj提供了两种织入方式,第一种是通过特殊编译器,在编译器,将aspectj语言编写的切面类织入到java类中,第二种是类加载期织入,就是下面的load time weaving,此处后续讲if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));// Set a temporary ClassLoader for type matching.beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));}// Register default environment beans.// 注册默认的系统环境bean到一级缓存中if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());}if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());}if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());}}

StandardBeanExpressionResolver

这个方法主要是创建了一个标准的Bean表达式的解析器。主要是用来对spel表达式的解析。
其中类之间的关系是Resolver处理类 包含了-> spelParser的解析类 包含了 -> spelConfiguration配置类。其中具体的解析过程是在SpelExpressionParser中的doParseExpression()方法完成。

/*** 默认表达式前缀** Default expression prefix: "#{". */public static final String DEFAULT_EXPRESSION_PREFIX = "#{";/*** 默认表达式后缀** Default expression suffix: "}". */public static final String DEFAULT_EXPRESSION_SUFFIX = "}";private String expressionPrefix = DEFAULT_EXPRESSION_PREFIX;private String expressionSuffix = DEFAULT_EXPRESSION_SUFFIX;public StandardBeanExpressionResolver(@Nullable ClassLoader beanClassLoader) {this.expressionParser = new SpelExpressionParser(new SpelParserConfiguration(null, beanClassLoader));}public SpelParserConfiguration(@Nullable SpelCompilerMode compilerMode, @Nullable ClassLoader compilerClassLoader,boolean autoGrowNullReferences, boolean autoGrowCollections, int maximumAutoGrowSize) {this.compilerMode = (compilerMode != null ? compilerMode : defaultCompilerMode);this.compilerClassLoader = compilerClassLoader;this.autoGrowNullReferences = autoGrowNullReferences;this.autoGrowCollections = autoGrowCollections;this.maximumAutoGrowSize = maximumAutoGrowSize;}

SpelExpressionParser
省略具体解析过程。知道使用时会调用doParseExpression方法即可。

public SpelExpressionParser(SpelParserConfiguration configuration) {Assert.notNull(configuration, "SpelParserConfiguration must not be null");this.configuration = configuration;}@Overrideprotected SpelExpression doParseExpression(String expressionString, @Nullable ParserContext context) throws ParseException {return new InternalSpelExpressionParser(this.configuration).doParseExpression(expressionString, context);}

回到prepareBeanFactory主方法,看下面的具体方法。

addPropertyEditorRegistrar

这个方法主要是对类属性的一个扩展,比如说Customer类中引用了Address变量。Address中包含了省市区的属性,但Customer中对address的值是省_市_区,将值捏合成了一个,这时可通过自定义的扩展对类中属性进行拆分。

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {// Tell the internal bean factory to use the context's class loader etc.// 设置beanFactory的classloader为当前context的classloaderbeanFactory.setBeanClassLoader(getClassLoader());// 设置beanfactory的表达式语言处理器beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));// 为beanFactory增加一个默认的propertyEditor,这个主要是对bean的属性等设置管理的一个工具类beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));}

先看方法的具体执行流程。

ResourceEditorRegistrar
addPropertyEditorRegistrar()方法会为BeanFacroty中PropertyEditorRegistrar属性赋值,在PropertyEditorRegistrar的构造器中,会对类中属性进行初始化赋值,并在类中包含了一个registerCustomEditors()方法。
registerCustomEditors方法会将Spring中默认的一些类注册到Editors中,默认的会执行overrideDefaultEditor操作。
registerCustomEditors方法会在Spring后面的源码中进行调用,这里不过多讲解

public class ResourceEditorRegistrar implements PropertyEditorRegistrar {public ResourceEditorRegistrar(ResourceLoader resourceLoader, PropertyResolver propertyResolver) {this.resourceLoader = resourceLoader;this.propertyResolver = propertyResolver;}@Overridepublic void registerCustomEditors(PropertyEditorRegistry registry) {ResourceEditor baseEditor = new ResourceEditor(this.resourceLoader, this.propertyResolver);doRegisterEditor(registry, Resource.class, baseEditor);//省略部分doRegisterEditor代码...if (this.resourceLoader instanceof ResourcePatternResolver) {doRegisterEditor(registry, Resource[].class,new ResourceArrayPropertyEditor((ResourcePatternResolver) this.resourceLoader, this.propertyResolver));}}private void doRegisterEditor(PropertyEditorRegistry registry, Class<?> requiredType, PropertyEditor editor) {if (registry instanceof PropertyEditorRegistrySupport) {((PropertyEditorRegistrySupport) registry).overrideDefaultEditor(requiredType, editor);}else {registry.registerCustomEditor(requiredType, editor);}}
}

ResourceEditor
ResourceEditor类继承了PropertyEditorSupport,PropertyEditorSupport实现了PropertyEditor类,其中ResourceEditor类包含了一些对类属性的一些实现。包括setAsText,setValue等一些方法。

public class ResourceEditor extends PropertyEditorSupport {public void setAsText(String text) throws java.lang.IllegalArgumentException {if (value instanceof String) {setValue(text);return;}throw new java.lang.IllegalArgumentException(text);}public void setValue(Object value) {this.value = value;firePropertyChange();}
}

结合ResourceEditor和ResourceEditorRegistrar两者来看的话,对属性的扩展就是将具体的class类,通过Editor定义好具体的逻辑后,通过Spring框架的识别,而后根据自己定义的逻辑来针对具体的class类的属性进行处理。

自定义类属性扩展

根据上面介绍的执行流程,仿照Spring框架的写法:

  1. 需要类实现PropertyEditorRegistrar类并实现自己的registerCustomEditors方法将类注册到Editors类中
  2. 在自定义的Editors类中,重写setAsText方法,实现类中的属性自定义扩展。
  3. 让自定义的Registrar类能够被Spring发现,并调用。

自定义类
Customer类中包含着Address属性,此时Customer对address的属性设置是“”省_市_区“”的格式,到Address类中要拆分成对应的值。

public class Customer {private String name;private Address address;
}public class Address {private String province;private String city;private String town;
}

实现Registrar
实现Registrar,调实现registerCustomEditors注册。

public class AddressPropertyEditorRegistrar implements PropertyEditorRegistrar {@Overridepublic void registerCustomEditors(PropertyEditorRegistry registry) {registry.registerCustomEditor(Address.class,new AddressPropertyEditor());}
}
//根据参数text属性实现自定义扩展
public class AddressPropertyEditor  extends PropertyEditorSupport {@Overridepublic void setAsText(String text) throws IllegalArgumentException {String[] s = text.split("_");Address address = new Address();address.setProvince(s[0]);address.setCity(s[1]);address.setTown(s[2]);this.setValue(address);}
}

xml配置
这里的xml采用了两种方法配置,目的是让Spring框架可以发现我们自定义的Editor,并进行调用。将我们自定义的Editor填充到CustomEditorConfigurer类中的customEditors属性其实就可让Spring框架发现并调用。这里埋个小坑,会在后面源码具体执行调用customEditors属性时再填。

 <bean id="customer" class="com.xxx.selfEditor.Customer"><property name="name" value="zhangsan"></property><property name="address" value="省_市_区"></property></bean>
<!--    <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">-->
<!--        <property name="propertyEditorRegistrars">-->
<!--            <list>-->
<!--                <bean class="com.xxx.selfEditor.AddressPropertyEditorRegistrar"></bean>-->
<!--            </list>-->
<!--        </property>-->
<!--    </bean>--><bean class="org.springframework.beans.factory.config.CustomEditorConfigurer"><property name="customEditors"><map><entry key="com.xxx.selfEditor.Address"><value>com.xxx.selfEditor.AddressPropertyEditor</value></entry></map></property></bean>

ignoreDependencyInterface

忽略自动装配的接口,这些接口的实现是由容器通过set方法进行注入的,所以在使用autowire进行注入的时候需要将这些接口进行忽略。
源码中忽略类的方法有两个,代表着不同的含义,具体可以看这篇帖子,关于ignoreDependencyInterface的方法讲述的很细。

/*** 自动装配时忽略的类** Ignore the given dependency type for autowiring:* for example, String. Default is none.* @param type the dependency type to ignore*/void ignoreDependencyType(Class<?> type);/*** 自动装配时忽略的接口** Ignore the given dependency interface for autowiring.* <p>This will typically be used by application contexts to register* dependencies that are resolved in other ways, like BeanFactory through* BeanFactoryAware or ApplicationContext through ApplicationContextAware.* <p>By default, only the BeanFactoryAware interface is ignored.* For further types to ignore, invoke this method for each type.* @param ifc the dependency interface to ignore* @see org.springframework.beans.factory.BeanFactoryAware* see org.springframework.context.ApplicationContextAware*/void ignoreDependencyInterface(Class<?> ifc);
http://www.lryc.cn/news/128025.html

相关文章:

  • LeetCode(力扣)257. 二叉树的所有路径Python
  • nodejs实现http与https服务;同时处理proxy代理的解决方案
  • C# WPF ListBox 动态显示图片
  • 游戏如何防御DDOS流量攻击呢,用游戏盾真的有用么?
  • vue项目引入antDesignUI组件
  • 非结构化数据库-MinIO基本集成
  • Etcd备份及恢复
  • 使用JavaMail发送邮件时嵌入公司logo图片
  • 注解 @Async
  • Python“牵手”lazada商品评论数据采集方法,lazadaAPI申请指南
  • 微信小程序通用字体代码
  • LVS负载均衡DR模式
  • ArcGIS Pro基础入门、制图、空间分析、影像分析、三维建模、空间统计分析与建模、python融合、案例全流程科研能力提升
  • ​ Spring Clould 配置中心 - Nacos
  • 1609.奇偶数
  • c++--异常
  • ArcGIS 利用cartogram插件制作变形地图
  • Mybatis批量插入方式有哪些
  • 前端框架学习-React(一)
  • Android Studio实现解析HTML获取图片URL将图片保存到本地
  • 单例模式的理论与实践
  • 深入了解MongoDB:灵活的文档型数据库与应用案例
  • 【HarmonyOS北向开发】-01 HarmonyOS概述
  • Node.js入门
  • 指针、数组、sizeof、strlen相关知识与练习题目
  • 分类预测 | MATLAB实现WOA-CNN-BiLSTM-Attention数据分类预测
  • MyBatis动态SQL:打造灵活可变的数据库操作
  • nginx代理请求到内网不同服务器
  • 【C# 基础精讲】文件读取和写入
  • 设计模式——经典单例