前言
前几篇已经介绍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配置文件的属性值到当前工厂中,最重要的就是BeanDefinition
ConfigurableListableBeanFactory 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的classloader
beanFactory.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.
// 注册BPP
beanFactory.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;
}
@Override
protected 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的classloader
beanFactory.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;
}
@Override
public 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框架的写法:
- 需要类实现PropertyEditorRegistrar类并实现自己的registerCustomEditors方法将类注册到Editors类中
- 在自定义的Editors类中,重写setAsText方法,实现类中的属性自定义扩展。
- 让自定义的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 {
@Override
public void registerCustomEditors(PropertyEditorRegistry registry) {
registry.registerCustomEditor(Address.class,new AddressPropertyEditor());
}
}
//根据参数text属性实现自定义扩展
public class AddressPropertyEditor extends PropertyEditorSupport {
@Override
public 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);