之前基本理清了ClassPathXmlApplicationContext的继承层次,但一些重点方法和一些重要对象并未触及,本文继续调试和阅读spring源码,希望通过此次学习可以搞明白bean的加载和生成机制。调试的Main方法如下,很简单,实现了一个简单的Transaction对象,使用ClassPathXmlApplicationContext获取transaction对象,调用对象的transaction方法。
import com.thoughtworks.Transaction;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
ApplicationContext context = new ClassPathXmlApplicationContext("Application-context.xml");
Transaction transaction = (Transaction)context.getBean("transaction");
transaction.transaction();
}
}
下面是Transaction对象定义,其中stMapper用到了mybatis,mybatis是比较流行的orm框架,之前也没使用过,由于项目中使用,模仿着写了一个,如果可以的话,顺便将mybatis与spring的整合代码一起看了。trasaction方法上我加上了@Transactional注解,这个注解实现从spring框架中支持了数据库事务,好处在于让程序员避免了在每次提交事务sql时写那些模板代码,通过与mybatis的整合,针对数据库的操作看起来会相当干净,仅仅加上一个注解,就可以轻松实现对事物的控制。这里加上@Transactional注解,是想了解下spring的实现机制,之前看了一点这块的代码,了解到spring的事务本质实际上还是AOP的方式实现(Spring AOP通过动态代理的方式实现,动态代理本质就是动态生成继承接口的类或者继承父类的子类,最终在动态生成的代理类中对用户方法进行拦截),spring实现了两种动态代理:jdk和cglib的,区别在于:jdk使用java自带的动态代理功能实现,但是只能支持代理继承于接口的具体类;cglib是为了能支持代理非继承接口的具体类(final类无法支持,因为通过继承父类实现),使用了直接生成字节码的方式返回class类型(据介绍还比较屌,想了解java字节码实现的,可以看看这块的源码,不够估计是native方法,那就得去看jvm虚拟机c语言源码了)。关于动态代理在Spring AOP的实现方式,后续会单列一章详细分析,此处仅简单叙述。
package com.thoughtworks;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Date;
@Component
public class Transaction {
@Autowired
private StMapper stMapper;
@Transactional
public void transaction() {
System.out.println(stMapper.getStockCardId(119, 572));
System.out.println(stMapper.getStockCardId(1, 1));
System.out.println(stMapper.getCMMEntryHead());
}
}
下面是StMapping的实现,该部分是mybatis跟spring整合的代码,虽然还没来得及细看源码,但是即使是猜,大概能想到mybatis也只能靠实现spring的某些插件类,最终注册到spring当中去实现mybatis的orm功能。如果本文篇幅够的话,可以把mybatis和spring的整合部分一起看了,不够的话后面再单列一章。
package com.thoughtworks;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Options;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface StMapper {
@Select("select * from tmp where a = #{a}")
List<Integer> getStudent(@Param("a") int a);
@Select("select id from stock_cards where facilityid = ${facilityid} and productid = ${productid}")
Integer getStockCardId(@Param("facilityid") Integer facilityid, @Param("productid") Integer productid);
@Select("SELECT * FROM cmm_entries limit 1")
CMMEntry getCMMEntryHead();
}
ApplicationContext的xml配置,数据库密码我写在default.properties中,由于涉及项目信息安全,配置文件就不放置了,配置文件就是简单key=value,每行一对配置,spring会自己去加载配置,然后替换配置中的占位符(比如${openlmis.jdbc.password}),这块我们也会在后面的源码中看到spring是如何替换这些占位符的。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.1.xsd">
<context:annotation-config/>
<context:spring-configured/>
<tx:annotation-driven transaction-manager="openLmisTransactionManager"/>
<bean id="openLmisTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource">
<ref bean="openlmisDataSource"/>
</property>
</bean>
<context:property-placeholder location="default.properties"/>
<bean id="openlmisDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${jdbc.driverClassName}"/>
<property name="jdbcUrl" value="${openlmis.jdbc.url}"/>
<property name="user" value="${openlmis.jdbc.username}"/>
<property name="password" value="${openlmis.jdbc.password}"/>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="openlmisDataSource"/>
<!--property name="typeHandlersPackage" value="org.openlmis.core.repository.typehandler"/-->
</bean>
<bean id="myBatisMapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.thoughtworks"/>
<property name="annotationClass" value="org.springframework.stereotype.Repository"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
<bean id="transaction"
class="com.thoughtworks.Transaction">
<!-- 在这里写额外的bean的配置和相关引用 -->
</bean>
</beans>
首先,我们从上下文的初始化开始,传入配置文件名称,该配置文件路径放在工程的resource目录下(default.properties也放在resource下面):
ApplicationContext context = new ClassPathXmlApplicationContext("Application-context.xml");
ClassPathXmlApplicationContext首先调用自己的构造函数,将配置文件名称传入,随后继续内部调用另外一个参数更多的构造函数,我们这里parent为null,之前看到,ApplicationContext是具有层次性的,多个ApplicationContext可以构造层次关系。随后调用了最重要的方法refresh方法。
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
refresh方法,该方法在AbstractApplicationContext中实现。synchronized (this.startupShutdownMonitor) 用于保证bean刷新的完整性。
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
}
}
Bean加载流程解析
prepareRefresh
prepareRefresh负责刷新前的准备工作,包括环境信息、配置路径信息的初始化。
obtainFreshBeanFactory
随后,会初始化一个重要对象--beanFactory,该beanFactory对象为ConfigurableListableBeanFactory类型。
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
查看obtainFreshBeanFactory方法,调用了AbstractApplicationContext中的两个抽象方法refreshBeanFactory和getBeanFactory,在AbstractApplicationContext中,多个涉及beanFactory的方法都是抽象方法,该beanFactory对象为ConfigurableListableBeanFactory。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
AbstractApplicationContext的直接子类AbstractRefreshableApplicationContext实现了refreshBeanFactory和getBeanFactory的方法,getBeanFactory里面直接获取的beanFactory对象,而负责beanFactory对象初始化方法的实际上是refreshBeanFactory,在不涉及重建beanFactory的场景中,refreshBeanFactory方法不会触发if分支。其中createBeanFactory负责beanFactory的创建,该beanFactory类型为DefaultListableBeanFactory,这个类负责代理所有涉及beanFactory的动作,所以这个类相当重要。
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
@Override
public final ConfigurableListableBeanFactory getBeanFactory() {
synchronized (this.beanFactoryMonitor) {
if (this.beanFactory == null) {
throw new IllegalStateException("BeanFactory not initialized or already closed - " +
"call 'refresh' before accessing beans via the ApplicationContext");
}
return this.beanFactory;
}
}
protected DefaultListableBeanFactory createBeanFactory() {
return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}
下图为DefaultListableBeanFactory的继承层次:
之前已经介绍过的接口不再重复介绍,只介绍新遇到的接口和类型。
接口SingletonBeanRegistry,负责对单例进行注册,以及获取单例等跟单例等相关的方法。这说明beanFactory有专门处理单例对象的逻辑。
public interface SingletonBeanRegistry {
void registerSingleton(String beanName, Object singletonObject);
Object getSingleton(String beanName);
boolean containsSingleton(String beanName);
String[] getSingletonNames();
int getSingletonCount();
}
接口AliasRegistry,负责别名注册相关的方法。这个接口说明beanFactory可以为bean注册别名,可以让用户通过别名访问bean的相关信息。SimpleAliasRegistry为AliasRegistry的具体类,不出意外,该类在后续肯定是协助DefaultListableBeanFactory代理执行AliasRegistry的这几个方法。
public interface AliasRegistry {
void registerAlias(String name, String alias);
void removeAlias(String alias);
boolean isAlias(String beanName);
String[] getAliases(String name);
}
接口BeanDefinitionRegistry,负责bean定义信息注册相关的方法。
public interface BeanDefinitionRegistry extends AliasRegistry {
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException;
void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
boolean containsBeanDefinition(String beanName);
String[] getBeanDefinitionNames();
int getBeanDefinitionCount();
boolean isBeanNameInUse(String beanName);
}
DefaultSingletonBeanRegistry,这是个具体类,继承自SimpleAliasRegistry和SingletonBeanRegistry。该类主要负责实现SingletonBeanRegistry接口中所有的方法。同时,它还实现了很多其他关于bean的方法,其中包括注册bean的依赖关系,还有bean的销毁方法,其中由于包含依赖,所以多个方法都是递归实现的。该类只负责管理和注册bean信息,同时也包含创建bean的功能。整体类功能非常具体且独立,所以阅读起来也很简单,由于该类方法较多,就不贴代码了。
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
...
}
接口ConfigurableBeanFactory,继承自HierarchicalBeanFactory, SingletonBeanRegistry,接口中主要是配置beanFactory信息的接口,同时因为继承自SingletonBeanRegistry,也包含该接口相关方法。
public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, SingletonBeanRegistry
抽象类FactoryBeanRegistrySupport,继承自DefaultSingletonBeanRegistry。该抽象类没包含抽象方法,所以仅仅只是不能实例化。该类新增了几个方法未包含public方法,说明该类仅仅是为了给子类提供工具方法,新增方法主要是bean和beanFactory相关方法。
public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanRegistry
AbstractBeanFactory抽象类
AbstractBeanFactory抽象类继承自FactoryBeanRegistrySupport,ConfigurableBeanFactory。该类主要实现了BeanFactory接口中的方法,HierarchicalBeanFactory接口中的方法,以及ConfigurableBeanFactory接口中的方法。最后,该类提供了三个抽象方法交给子类实现。
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory
BeanFactory接口方法实现
AbstractBeanFactory抽象类实现了beanFactory的方法,用来获取bean的getBean方法以及一些与bean状态和类型相关的方法。比较重要的有getBean方法,getBean方法实际调用的是doGetBean方法,因为bean之间可能存在依赖,所以doGetBean方法中生成bean的时候是递归进行的,真正生成bean对象的是createBean方法,该方法为抽象方法,由子类负责实现。
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dependsOnBean : dependsOn) {
if (isDependent(beanName, dependsOnBean)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dependsOnBean + "'");
}
registerDependentBean(dependsOnBean, beanName);
getBean(dependsOnBean);
}
}
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; " +
"consider defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// Check if required type matches the type of the actual bean instance.
if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
try {
return getTypeConverter().convertIfNecessary(bean, requiredType);
}
catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type [" +
ClassUtils.getQualifiedName(requiredType) + "]", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
ConfigurableBeanFactory接口实现
该接口实现主要包含配置化beanFactory接口的实现。
AbstractBeanFactory的抽象方法
protected abstract boolean containsBeanDefinition(String beanName);
protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;
protected abstract Object createBean(String beanName, RootBeanDefinition mbd, Object[] args)
throws BeanCreationException;
AbstractAutowireCapableBeanFactory抽象类
该抽象类继承自AbstractBeanFactory和AutowireCapableBeanFactory,实现了AbstractBeanFactory的抽象方法creatBean,并且实现了继承自AutowireCapableBeanFactory的接口,提供了bean的创建,属性填充,自动装配等功能。
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory
了解了DefaultListableBeanFactory的继承层次后,可以知道DefaultListableBeanFactory负责的功能:bean信息的注册、bean的获取、bean的创建,同时,也支持了自动装配等功能,同时还实现了插件BeanPostProcessor,初步来看,这个beanPostProcessor可以用户实现注入到该框架当中增强spring的功能,还有一些其他功能并未细看,等到用到时候再详细解读。
至此,DefaultListableBeanFactory已经大致了解清楚。
createBeanFactory调用结束后,loadBeanDefinitions(beanFactory)是更重要的方法,因为创建出来的beanFactory对象还并未真正进行xml配置解析和信息的填充。
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
loadBeanDefinitions方法在AbstractXmlApplicationContext中继承后实现,该方法进一步调用XmlBeanDefinitionReader来解析bean信息,解析后填充到beanFactory对象中,由于该方法内部调用较为复杂,涉及相当多的对象,需要单列一章介绍。
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}
bean定义信息加载完成后,obtainFreshBeanFactory方法执行完成。
prepareBeanFactory(beanFactory)
beanFactory对象在此方法中,设置了多个属性。
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// Tell the internal bean factory to use the context's class loader etc.
beanFactory.setBeanClassLoader(getClassLoader());
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// Configure the bean factory with context callbacks.
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
// BeanFactory interface not registered as resolvable type in a plain factory.
// MessageSource registered (and found for autowiring) as a bean.
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// Detect a LoadTimeWeaver and prepare for weaving, if found.
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.
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());
}
}
postProcessBeanFactory(beanFactory)
空方法,需要子类继承实现才能生效。
未完待续。