beanDefination的加载主要分为三种
1、配置文件的读取
public static void main(String[] args) {
创建ioc容器
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:app1.xml");
Student student =(Student)context.getBean("mym");
System.out.println(student.getTeacher().getId());
}
在下面这一块来创建ioc容器
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
继续往下看
this(new String[]{configLocation}, true, (ApplicationContext)null);
}
创建ioc容器
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException {
super(parent);
//加载配置文件 主要解析出配置文件的路径 放入在数组中保存
//这里有解析的规则,比如为什么需要classpath:开头等
this.setConfigLocations(configLocations);
if (refresh) {
//往下看
this.refresh();
}
}
这一块是核心的几个方法 以后所有的解读都是围绕这一块去进行
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
this.prepareRefresh();
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);
try {
this.postProcessBeanFactory(beanFactory);
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
this.initMessageSource();
this.initApplicationEventMulticaster();
this.onRefresh();
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
还是回到我们本章的重点 beanDefinition的加载
//创建beanFactory 以后所有的数据都会保存这里面 我们的ioc会持有一个beanFactory的引用
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
创建beanFactory
AbstractApplicationContext 319 line
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//继续往下看
this.refreshBeanFactory();
return this.getBeanFactory();
}
AbstractRefreshableApplicationContext 39 line
protected final void refreshBeanFactory() throws BeansException {
......
try {
//这里我们可以看到 beanFactory的原貌
DefaultListableBeanFactory beanFactory = this.createBeanFactory();
beanFactory.setSerializationId(this.getId());
//设置ioc中的bean是否允许bean的覆盖以及循环引用
this.customizeBeanFactory(beanFactory);
//加载beanDefination 这里是重点咯 继续往下看
this.loadBeanDefinitions(beanFactory);
......
}
加载beanDefinition
AbstractXmlApplicationContext 31 line
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
//xml的解析器 因为我们是解析xml文件,然后去加载bean的
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
//设置各式各样的信息 属性 略过吧
......
//加载beanDefination 继续往下看
this.loadBeanDefinitions(beanDefinitionReader);
}
根据路径获取资源流
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
......
//拿到路径 然后去加载资源流
String[] configLocations = this.getConfigLocations();
if (configLocations != null) {
//下面这一块 最终会将路径包装成资源数组(执行我注释起来的方法)
//然后走到上面的哪一块
//Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
reader.loadBeanDefinitions(configLocations);
}
}
加载资源
AbstractBeanDefinitionReader 184 line
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
int count = 0;
for (Resource resource : resources) {
//往下看
count += loadBeanDefinitions(resource);
}
return count;
}
XmlBeanDefinitionReader 320 line
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
......
//获取流 设置编码
try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
//流的处理 往下看
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
......
}
处理流
XmlBeanDefinitionReader 386 line
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
//流的处理 最终会将xml解析成为一个doc
//至于解析就不是重点了 我们是看ioc流程 不是扣细节的 下面有doc的结果截图
Document doc = doLoadDocument(inputSource, resource);
//处理doc文档 继续往下看
int count = registerBeanDefinitions(doc, resource);
return count;
}
......
}
XmlBeanDifinitionReader 508 line
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//doc的解析器
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
//已经解析好的beanDefinition的数量 因为配置文件可多个 然后去循环一个一个解析
int countBefore = getRegistry().getBeanDefinitionCount();
//解析 doc 往下看
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
//返回本次加载的beanDefinition的数量
return getRegistry().getBeanDefinitionCount() - countBefore;
}
DefaultBeanDefinitionDocumentReader 94 line
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
//注意看 这里获取了doc的结点 入参截图在下面
doRegisterBeanDefinitions(doc.getDocumentElement());
}
由上我们可以看到 入参就是我们xml里面配置的beans结点咯
接着往下走
defaultBeanDefinitionDocumentReader 121 line
protected void doRegisterBeanDefinitions(Element root) {
//由于beans里面也可以定义beans
//如果是内部的beans,那么如果他没定义某些信息,就会直接用外部的beans的
//什么是某些信息 感兴趣可以去看看delegate的创建那块 里面有
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
//拿到profile 我们都知道spring可设置激活环境 这一块判断是否需要加载这个结点
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
//环境没激活 直接返回 也就代表一个xml文件解析结束
return;
}
}
}
//模板方法 需要的一些细节子类可以去实现
preProcessXml(root);
//解析beans标签
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}
解析beans标签
DefaultBeanDefinitionDocumentReader 168 line
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)) {
//去解析 还是默认的几个标签 其他标签走esle 往下看
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
子标签的解析
defaultBeanDefinitionDocumentReader 189 line
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
//import标签的解析
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
//alias标签的解析
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
//bean标签的解析
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
//处理bean标签 往下看
processBeanDefinition(ele, delegate);
}
//beans标签的解析
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
//这一块 最终还是会像我们解析外层beans一样的流程
doRegisterBeanDefinitions(ele);
}
}
处理bean标签
defaultBeanDefinitionDocumentReader 305 line
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//解析ele结点
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
//装饰一些其他的必要的信息 略过吧
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
//注册beanDefinition
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
......
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
解析ele结点
BeanDefinitionParserDelegate 414 line
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
//拿到bean标签中的name id 值
String id = ele.getAttribute(ID_ATTRIBUTE);
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));
}
//将id设置为bean的名字
String beanName = id;
......
//检验beanName是否已存在 内部用一个set来存放所有的beanName 也就是bean的id
if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}
//创建BeanDefinition
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
......
String[] aliasesArray = StringUtils.toStringArray(aliases);
//包装一下
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
终于来到了创建BeanDefinition
BeanDefinitionParserDelegate 414 line
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, @Nullable BeanDefinition containingBean) {
......
try {
//创建bd GenericBeanDefinition
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
//获取bean的singleton、scope、abstract、lazy-init、autowire、depends-on、
//autowire- candidate、primary、init-method、destroy-method、
//factory-method、factory-bean属性的值,并存入GenericBeanDefinition对应的字段
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
//bean标签存在子标签 那么将其内容存储在bd中
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
//bean标签存在子标签 将其解析存储在bd中(bd中使用BeanMetadataAttribute存储)
parseMetaElements(ele, bd);
//bean标签存在子标签 将其解析存储 (MethodOverrides是bd的一个字段,
//MethodOverrides内部维护一个CopyOnWriteArraySet,
//CopyOnWriteArraySet中定义了存储类型为MethodOverride)
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
//bean标签存在子标签 将其解析存储 也是放在MethodOverrides
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
//bean标签存在子标签 解析存储在bd的ConstructorArgumentValues字段
parseConstructorArgElements(ele, bd);
//bean标签存在子标签 解析存储在bd的MutablePropertyValues字段
parsePropertyElements(ele, bd);
//bean标签存在子标签 解析存储在bd中的AutowireCandidateQualifier中的map中
parseQualifierElements(ele, bd);
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));
return bd;
......
return null;
}
我们来分析property标签的解析
bean标签存在子标签 解析存储在bd的MutablePropertyValues字段
获取property标签的name 因为值是唯一的 多个property标签name相同直接抛异常
如果标签存在value字段,则使用TypedStringValue存储值
如果是ref,则使用RuntimeBeanReference存值
如果两个都存在,报错
如果存在子标签 则继续解析子标签 此时会根据标签类型去做对应的解析
我这一块是一个list 所以他会解析并封装 最后的结果如下图
ManagedList也就是我们常用的集合,它里面封装了我们集合中每一个索引指向的bean的名字
将上述存值的对象封装成PropertyValue存储在MutablePropertyValues中的List中
最后将创建的bd返回
接着就到注册beanDefinition
beanDefinitionReaderUtils 158 line
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
//拿到bean的名字
String beanName = definitionHolder.getBeanName();
//bean的注册
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
//有别名的话 绑定别名 别名是与beanName绑定的
registry.registerAlias(beanName, alias);
}
}
}
DefaultListableBeanFactory 926 line
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
......
//根据beanName获取beanDefinition
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
//已存在beanDefinition 判断是否可以覆盖
if (existingDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
...... 覆盖bean的日志
//进行beanDefinition的注册 其实是保存在beanDefinitionMap中
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
//判断是否已经有其他bean开始初始化了
if (hasBeanCreationStarted()) {
//这一块没调试 我们走的是流程 不是抠细节
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 {
//注册beanDefinition 也就是保存在map中
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
removeManualSingletonName(beanName);
}
this.frozenBeanDefinitionNames = null;
}
......
}
至此,一个beanDefinition已经注册成功 后面都是循环去注册所有xml文件中定义的bean
再来看看我们走到了哪里
protected final void refreshBeanFactory() throws BeansException {
......
try {
DefaultListableBeanFactory beanFactory = this.createBeanFactory();
beanFactory.setSerializationId(this.getId());
this.customizeBeanFactory(beanFactory);
//加载beanDefinition
this.loadBeanDefinitions(beanFactory);
//然后将创建好的beanFacorty返回
this.beanFactory = beanFactory;
...
}
最后在返回到这里
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
到此 基于xml文件的BeanDefinition已经加载到了beanFactory中了
还是从配置开始
public static void main(String[] args) {
//创建ioc容器
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(MainConfig.class);
Student student = app.getBean("student", Student.class);
System.out.println(student.getTeacher().getName());
app.close();
}
创建ioc容器
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
//这个里面还是有非常丰富的内容 spring给我们注册了很多的beanDefinition,以供ioc正常运行
//核心重点 创建了beanFacroty
//DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
this();
//加载配置类 也就是将配置类解析成beanDefinition
this.register(componentClasses);
//这一块就跟xml解析的哪一块一样的refresh
this.refresh();
}
来看我们的重点 加载配置类
public void register(Class<?>... componentClasses) {
//往下看
this.reader.register(componentClasses);
}
public void register(Class<?>... componentClasses) {
Class[] var2 = componentClasses;
int var3 = componentClasses.length;
for(int var4 = 0; var4 < var3; ++var4) {
Class<?> componentClass = var2[var4];
//继续往下看
this.registerBean(componentClass);
}
}
看这个名字我们也知道这是来注册 但不是注册bean!!!是注册beanDefinitation
private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name, @Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier, @Nullable BeanDefinitionCustomizer[] customizers) {
//人狠话不多 直接搞了一个beanDefinition
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
//判断是不是需要跳过 也就是加载的配置类有没有@Condition 注解
//confitional里面配置的类来确定标注了该注解的配置类是否生效
//不理解的可百度这个注解使用方式 就一目了然了
if (!this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
abd.setInstanceSupplier(supplier);
//解析 abd的scope类型
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
//设置abd为单例的 默认就是单例 如果有@Scope注解,则按照注解的来设置
abd.setScope(scopeMetadata.getScopeName());
//bean的名字
String beanName = name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry);
//解析bean的一些注解值 往后面看
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
int var10;
int var11;
//qualifiers注解处理 我们这里为null 在注入其他bean的时候分析
if (qualifiers != null) {
Class[] var9 = qualifiers;
var10 = qualifiers.length;
for(var11 = 0; var11 < var10; ++var11) {
Class<? extends Annotation> qualifier = var9[var11];
if (Primary.class == qualifier) {
abd.setPrimary(true);
} else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
} else {
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
//对bean的个性化处理 前提是bean实现了BeanDefinitionCustomizer接口 这个也很有用哦
if (customizers != null) {
BeanDefinitionCustomizer[] var13 = customizers;
var10 = customizers.length;
for(var11 = 0; var11 < var10; ++var11) {
BeanDefinitionCustomizer customizer = var13[var11];
customizer.customize(abd);
}
}
//包装
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
//一个简单的包装 但是这里不符合条件,也就是没包装 怎么包装?分析其他的bean的时候来看
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
//注册beanDefinition 也就是将其放入map,并将别名与bean的名字绑定
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
}
解析设置bean的注解
static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
//解析@Lazy注解的值
AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
if (lazy != null) {
abd.setLazyInit(lazy.getBoolean("value"));
} else if (abd.getMetadata() != metadata) {
lazy = attributesFor(abd.getMetadata(), (Class)Lazy.class);
if (lazy != null) {
abd.setLazyInit(lazy.getBoolean("value"));
}
}
//解析设置@Primary注解的值
if (metadata.isAnnotated(Primary.class.getName())) {
abd.setPrimary(true);
}
//解析设置DependOn注解的值 这个注解之间的bean不能循环依赖!!!
//也就是说 不能A标注这个注解,值是B B也标注这个注解 值是A 这样直接报错
AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
if (dependsOn != null) {
abd.setDependsOn(dependsOn.getStringArray("value"));
}
//解析设置@Role注解 这个注解有啥用???
AnnotationAttributes role = attributesFor(metadata, Role.class);
if (role != null) {
abd.setRole(role.getNumber("value").intValue());
}
//解析设置@Descript注解
AnnotationAttributes description = attributesFor(metadata, Description.class);
if (description != null) {
abd.setDescription(description.getString("value"));
}
}
再来看看我们走到了哪里 没错 我们走到了refresh
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
this();
//注册beanDifinition
this.register(componentClasses);
this.refresh();
}
继续看refresh 没错哦 跟xml解析的那个refresh是一个方法
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
this.prepareRefresh();
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);
try {
this.postProcessBeanFactory(beanFactory);
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
this.initMessageSource();
this.initApplicationEventMulticaster();
this.onRefresh();
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
对比一下 ,我们看下注解版是怎么获取beanFactory的,他在这其中又做了什么
//往下看
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
//继续往下看
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
this.refreshBeanFactory();
return this.getBeanFactory();
}
GenericApplicationContext 95 line
protected final void refreshBeanFactory() throws IllegalStateException {
if (!this.refreshed.compareAndSet(false, true)) {
throw new IllegalStateException("GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
} else {
//设置了id
this.beanFactory.setSerializationId(this.getId());
}
}
由上我们可以看到,注解版的beanFactory在这里只设置了id,然后就将其返回了
而xml版,在这里来解析xml文件,注册beanDefinition等信息
看后续的分析哦 这一块也是一个很大的内容点!!!