prepareBeanFactory(beanFactory)
方法是refresh
方法中第三个核心流程,主要是给容器对象 BeanFactory
的属性值赋值操作,通过一系列的add
、set
、ignore
和register
开头的方法完成赋值操作。
一、prepareBeanFactory
方法代码
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
beanFactory.setBeanClassLoader(getClassLoader());
// 设置 beanFactory 的表达式解析器
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
// 为 beanFactory 增加一个默认的PropertyEditor,这个主要是针对bean的属性值编辑管理的工具类;是Spring预留的一个扩展点
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// 添加 BeanPostProcessor
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
// 设置需要忽略的自动装配的接口,为什么要对这些接口进行忽略?因为这些接口的实现是由容器通过set方法进行注入的,
// 所以在使用autowire进行注入的时候需要将这些接口忽略掉,不是在 invokerMethod 中设置的
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
// 设置几个自动装配的特殊规则,当在进行IOC初始化时如果有多个实现,那么就使用指定的对象进行注入,
// 比如注入多个DataSource数据源时,会取@Primary注解标识对象进行注入
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// 注册 BeanPostProcessor
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// 增加对AspectJ的支持,在java中织入分为三种方式,分为编译器织入,类加载器织入,运行期织入;
// 编译器织入是指在java编译器,采用特殊的编译器,将切面织入到java类中;
// 而类加载期织入则指通过特殊的类加载器,在类字节码加载到JVM时,织入切面;
// 运行期织入则是采用cglib和jdk进行切面的织入;
// aspectj提供了两种织入方式,第一种是通过特殊编译器,在编译器,将aspectj语言编写的切面类织入到java类中;
// 第二种是类加载期织入,就是下面的load time weaving,此处逻辑后面到aop源码再讲
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()));
}
// 注册默认的系统环境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());
}
}
看了该方法的全貌之后,下面对方法中的重点逻辑点进行逐一解释
1. SpEL
表达式语言解析器
beanFactory.setBeanExpressionResolver()
中设置了SpEL
表达式解析器;SpEL
使用#{...}
作为占位符,所有在大括号内的字符都将被认为是SpEL
。SpEL
表达式使用非常丰富,如果感兴趣参考这篇博文:Spring 表达式语言 (SpEL)
BeanFactory
在 setBeanExpressionResolver
方法中注册了表达式语言解析器,那么它在哪里解析的表达式呢?
- 在Bean的生命周期:Bean属性填充 阶段对表达式进行解析的,也就是
AbstractAutowireCapableBeanFactory
的doCreateBean
中的populateBean
方法中执行的,方法调用过程如下:
evaluateBeanDefinitionString
方法中就是调用setBeanExpressionResolver
方法中设置的表达式解析器的解析方法进行解析
2. 属性编辑器
beanFactory.addPropertyEditorRegistrar
:给 BeanFactory
设置一个默认的PropertyEditor
,主要对Bean
的属性值编辑管理的工具类,是Spring预留的一个扩展点
- 先看这样一个业务场景:如何在
xml
中给一个实体bean
注入一个日期类型的属性?
public class User {
private String username;
private Date birthday;
}
Spring
注入时是无法将String
类型解析成Date
类型的。要解决该问题就得自定义一个属性编辑器来转换日期类型。
(1)自定义日期属性编辑器
public class DatePropertyEditor extends PropertyEditorSupport {
private DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.SHORT, Locale.CHINA);
@Override
public void setAsText(String text) throws IllegalArgumentException {
if (!StringUtils.hasText(text)) {
return;
}
try {
setValue(this.dateFormat.parse(text));
} catch (ParseException ex) {
throw new IllegalArgumentException("Could not parse date: " + ex.getMessage(), ex);
}
}
}
(2)日期属性编辑器注册到Spring
容器中
public class DatePropertyEditorRegistrar implements PropertyEditorRegistrar {
@Override
public void registerCustomEditors(PropertyEditorRegistry registry) {
registry.registerCustomEditor(Date.class, new DatePropertyEditor());
}
}
(3)xml
文件配置
(4)运行结果
public class TestBean {
public static void main(String[] args) {
testPropertyEditor();
}
public static void testPropertyEditor() {
ApplicationContext cx = new ClassPathXmlApplicationContext("application-property-editor.xml");
User user = (User) cx.getBean("user4");
System.out.println(user.getUsername() + "; " + user.getBirthday());
}
}
registerCustomEditors
方法的调用时机?
通过方法调用链路可以看出registerCustomEditors
方法是在Bean生命周期的Bean对象实例化之后、对象属性填充之前 调用的
setValue
方法的调用时机?
通过方法调用链路可以看出registerCustomEditors
方法是在Bean生命周期的Bean对象属性填充 时调用的
3. ApplicationContextAwareProcessor
处理器
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this))
为 BeanFactoty
添加 BeanPostProcessor
处理器,只不过这个处理器是 ApplicationContextAwareProcessor
,它到底干了什么事?
先简单回顾一下Bean
的生命周期流程,如下图所示:
在调populateBean
完成bean属性填充之后,会调用 initializeBean
方法,该方法依次调用Aware
接口、BeanPostProcessor
前置处理器、init-method
、调用BeanPostProcessor
后置处理器。
但是我们发现通过invokeAwareMethods
调用 Aware
接口时只处理了BeanNameAware、 BeanClassLoaderAware、BeanFactoryAware 三个接口
,那么其他的Aware
接口是在哪里处理的呢???
ApplicationContextAwareProcessor
就是处理其他Aware
接口的。因为它是BeanPostProcessor
,所以在postProcessBeforeInitialization
中做了Aware
接口处理逻辑
class ApplicationContextAwareProcessor implements BeanPostProcessor {
private final ConfigurableApplicationContext applicationContext;
private final StringValueResolver embeddedValueResolver;
public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {
this.applicationContext = applicationContext;
this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory());
}
@Override
@Nullable
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
AccessControlContext acc = null;
if (System.getSecurityManager() != null &&
(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
}
if (acc != null) {
AccessController.doPrivileged((PrivilegedAction) () -> {
invokeAwareInterfaces(bean);
return null;
}, acc);
}
else {
invokeAwareInterfaces(bean);
}
return bean;
}
// 处理其他 Aware 接口
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof Aware) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
return bean;
}
}
所以 EnvironmentAware
EmbeddedValueResolverAware
ResourceLoaderAware
ApplicationEventPublisherAware
MessageSourceAware
ApplicationContextAware
这些接口的调用时机是在BeanPostProcessor
前置处理器中处理的