这边我们将分析obtainFreshBeanFactory() BeanFactory的创建以及相关的准备工作!
//这一步主要作用是将配置文件定义解析成beanDefine 注册到beanFactory中
//但是这里的bean并没有初始化出来 只是提取配置信息 定义相关的属性
//将这些信息保存到beanDefineMap中(beanName->beanDefine)对应的map
//我们将深入进去 仔细看看源码下面内容大多数解释我放在贴出来的代码中 这里只是引入一个类的走向
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 关闭旧的beanFactory 创建新的beanFactory 并注册
refreshBeanFactory();
//返回上面创建的beanFactory对象(注意这里是自己改造的)
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
logger.info("Bean factory for " + getDisplayName() + ": " + beanFactory);
return beanFactory;
}
首先我们进入refreshBeanFactory方法 我们找到 AbstractRefreshableApplicationContext 对应的实现类
@Override
protected final void refreshBeanFactory() throws BeansException {
//ApplicationContext 如果已经加载了BeanFactory 则销毁所有的Bean 关闭BeanFactory
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);
}
}
if (hasBeanFactory()) { destroyBeans();closeBeanFactory()} 首先我们判断是否存在BeanFactory 如果不为空我们就将其销毁 和关闭
接下来 我们新建一个DefaultListableBeanFactory 的beanFactory 对象 我们进入createBeanFactory()方法
protected DefaultListableBeanFactory createBeanFactory() {
return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}
这步默认创建DefaultListableBeanFactory 对象 这个时候我们的BeanFactory初步形成 这也将是管理整个bean的核心接口
beanFactory.setSerializationId(getId()); 设置相应的序列化id
customizeBeanFactory(beanFactory); 设置对应的属性 1:设置是否可重复定义bean 2设置 可循环依赖 代码如下
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
if (this.allowBeanDefinitionOverriding != null) {
//是否允许bean定义的覆盖
// BeanDefinition 的覆盖问题大家也许会碰到,
// 就是在配置文件中定义 bean 时使用了相同的 id 或 name
// ,默认情况下,allowBeanDefinitionOverriding 属性为 null,
// 如果在同一配置文件中重复了,会抛错,但是如果不是同一配置文件中,会发生覆盖。
beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
if (this.allowCircularReferences != null) {
//是否允许bean 间的循环依赖
// A 依赖 B,而 B 依赖 A。或 A 依赖 B,B 依赖 C,而 C 依赖 A
// 默认情况下,Spring 允许循环依赖,当然如果你在 A 的构造方法中依赖 B,在 B 的构造方法中依赖 A 是不行的。
beanFactory.setAllowCircularReferences(this.allowCircularReferences);
}
}
这些属性 我们后面会用到
下面进入最核心的方法loadBeanDefinitions(beanFactory); 这个方法将开始解析配置 转化为对应的BeanDefinition对象
我们点进去(进入)AbstractXmlApplicationContext下的
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
// 创建同一个XmlBeanDefinitionReader 见名知意 xml的BeanDefine读取器转换器 也就是将xml文件转化为BeanDefinition
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
// 设置当前环境
beanDefinitionReader.setEnvironment(this.getEnvironment());
//这里的setResourceLoader赋值 我们在refresh方法的时候就已经给this赋值
//且看
// super(parent);
// // 将配置文件路径设置给AbstractRefreshableConfigApplicationContext 的 configLocations的属性
// setConfigLocations(configLocations); //这个方法就将配置路径赋值了
// // 由上面的参数传进refresh为true 下面我们就进入refresh方法 spring初始化全程
// if (refresh) {
// refresh();
// }
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);
}
继续进入loadBeanDefinitions(beanDefinitionReader);方法
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
//拿到对应配置文件的地址 对应Resources文件夹下面
String[] configLocations = getConfigLocations();
if (configLocations != null) {
System.out.println(configLocations);
reader.loadBeanDefinitions(configLocations);
}
}
点进reader.loadBeanDefinitions(configLocations);方法
@Override
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
Assert.notNull(locations, "Location array must not be null");
int count = 0;
for (String location : locations) {
count += loadBeanDefinitions(location);
}
return count;
}
继续。。。。这中间有点啰嗦 就不一一贴出来了。。我们一直点到XmlBeanDefinitionReader下面的loadBeanDefinitions方法的具体实现
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isTraceEnabled()) {
logger.trace("Loading XML bean definitions from " + encodedResource);
}
// 用一个 ThreadLocal 来存放所有的配置文件资源
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
//生成一个输入流
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
//核心 我们点进去
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
进入doLoadBeanDefinitions(inputSource, encodedResource.getResource());
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
//这里我们将资源文件转化为Document对象
Document doc = doLoadDocument(inputSource, resource);
//开始注册对应的BeanDefinition 我们继续进去
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
}
}
咋们直接进入DefaultBeanDefinitionDocumentReader 下面的doRegisterBeanDefinitions
protected void doRegisterBeanDefinitions(Element root) {
// Any nested <beans> elements will cause recursion in this method. In
// order to propagate and preserve <beans> default-* attributes correctly,
// keep track of the current (parent) delegate, which may be null. Create
// the new (child) delegate with a reference to the parent for fallback purposes,
// then ultimately reset this.delegate back to its original (parent) reference.
// this behavior emulates a stack of delegates without actually necessitating one.
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
// We cannot use Profiles.of(...) since profile expressions are not supported
// in XML config. See SPR-12458 for details.
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
//钩子 没有作任何的实现 不理会
preProcessXml(root);
// 解析xml 将xml元素转化为BeanDefinition
parseBeanDefinitions(root, this.delegate);
//钩子 没有作任何的实现 不理会
postProcessXml(root);
this.delegate = parent;
}
根据上面的解释我们直接进入parseBeanDefinitions(root, this.delegate);
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
//默认的命令空间 如beans bean import resource alias name会进此方法
parseDefaultElement(ele, delegate);
}
else {
//其他的元素 如扫包 定时器 都会有对应的handler去处理 可以断点看看
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
因为我们这里只是介绍bean的初始化 那么我们暂时只进parseDefaultElement(ele, delegate); 我们点进去
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
//处理import标签
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
//处理alias标签
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
//处理bean标签
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// 处理beans标签
doRegisterBeanDefinitions(ele);
}
}
通过标签元素找到对应的process 这里我们只进入processBeanDefinition(ele, delegate);方法体
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// xml节点信息转化为BeanDefinitionHolder对象
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
//如果有自定义属性的话 进行相应的解析
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
// 这一步就是注册bean啦
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
delegate.parseBeanDefinitionElement(ele)方法将节点元素转化为BeanDefinitionHolder 我们进入该方法
@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
//<bean id="test" class="com.test.seivice.TestService" ></bean>
//解析像上面这种配置
// 获取xml中id对应的值
String id = ele.getAttribute(ID_ATTRIBUTE);
// 获取xml中name对应的值
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
List<String> aliases = new ArrayList<>();
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
String beanName = id;
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
if (logger.isTraceEnabled()) {
logger.trace("No XML 'id' specified - using '" + beanName +
"' as bean name and " + aliases + " as aliases");
}
}
//核心方法 对bean对应的节点进行属性设置 得到xml中全类名
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
if (!StringUtils.hasText(beanName)) {
try {
//如果配置中没有定义name只定义了class name我们默认类名的首字母小写作为id(这里很常用)
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
}
else {
beanName = this.readerContext.generateBeanName(beanDefinition);
// Register an alias for the plain bean class name, if still possible,
// if the generator returned the class name plus a suffix.
// This is expected for Spring 1.2/2.0 backwards compatibility.
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null &&
beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName);
}
}
if (logger.isTraceEnabled()) {
logger.trace("Neither XML 'id' nor 'name' specified - " +
"using generated bean name [" + beanName + "]");
}
}
catch (Exception ex) {
error(ex.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
这个方法完成了bean对应节点元素的解析 转化为BeanDefinitionHolder元素 包括beanDefinition(包含类名 ),beanName,别名。
beanDefinition主要定义了bean创建时候的一些属性 比如是否懒加载,是否单例等等 用于后期创建对象的判断依据 可以去看看这个类 我们在看法中也会定义对应bean的创建所约定的规则。
创建为对应的一个BeanDefinitionHolder 我们回到上上面processBeanDefinition这个方法
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());在这里我们注册我们转化的BeanDefinitionHolder对象 进入该方法
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
//拿到对应的beanName 就是我们前面定义的id的名字
//<bean id="test" 。。。> 就是这里的test
// Register bean definition under primary name.
String beanName = definitionHolder.getBeanName();
// 进一步注册
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
//如果有别名 同样注册别名
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
我们看看DefaultListableBeanFactory下面的注册方法
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
//判断是否重新创建BeanDefinition 如果不为空而且 不是可重复出现的bean则报错(前面已经提到过)
if (existingDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
else if (existingDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (logger.isInfoEnabled()) {
logger.info("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
existingDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(existingDefinition)) {
if (logger.isDebugEnabled()) {
logger.debug("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
removeManualSingletonName(beanName);
}
}
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
removeManualSingletonName(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (existingDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
在这里我们需要关注一下DefaultListableBeanFactory这个类 至关重要!
- ApplicationContext 继承了 ListableBeanFactory,这个 Listable 的意思就是,通过这个接口,我们可以获取多个 Bean,最顶层 BeanFactory 接口的方法都是获取单个 Bean 的。
- ApplicationContext 继承了 HierarchicalBeanFactory,Hierarchical 单词本身已经能说明问题了,也就是说我们可以在应用中起多个 BeanFactory,然后可以将各个 BeanFactory 设置为父子关系。
- AutowireCapableBeanFactory 这个名字中的 Autowire 大家都非常熟悉,它就是用来自动装配 Bean 用的,但是仔细看上图,ApplicationContext 并没有继承它,不过不用担心,不使用继承,不代表不可以使用组合,如果你看到 ApplicationContext 接口定义中的最后一个方法 getAutowireCapableBeanFactory() 就知道了。
- ConfigurableListableBeanFactory 也是一个特殊的接口,看图,特殊之处在于它继承了第二层所有的三个接口,而 ApplicationContext 没有。这点之后会用到。
DefaultListableBeanFactory也是BeanFactory重要实现类 主要是用来管理对应的beanDefinition 我们看看这个类的属性
/** Map of bean definition objects, keyed by bean name. */
//注册的类就保存在该map中
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
/** Map of singleton and non-singleton bean names, keyed by dependency type. */
private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64);
/** Map of singleton-only bean names, keyed by dependency type. */
private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<>(64);
/** List of bean definition names, in registration order. */
private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
上面是BeanFactory常用管理容器
我们接着上面的注册看 我们将解析出来的beanDefinition用
this.beanDefinitionMap.put(beanName, beanDefinition);装起来 后面我们通过getBean(beanName)就是获得对应beanDefinition 获取类名 通过一系列的手段创建出对象
到此 我们基本已经完成了将xml中配置的<bean id="test" class="com.test.seivice.TestService" ></bean>(类似)
解析为一个个beanDefinition 放在我们beanDefinitionMap中管理起来 但是我们并未创建对象 创建对象在倒数第二步,不急。。。。
当然 我们在开发中 肯定不会<bean 。。。。/>这样配置很多的这样的内容 一般的都会通过<context:component-scan base-package="XXXX" > 扫包的形式 后面我们会分析通过扫包形成对应的beanDefinition 同样用beanDefinitionMap装起来。