0102Bean配置和解析-Bean生命周期-spring

1 前言

根据配置Bean方式不同,在定义域解析注册阶段,会执行不同的流程。下面给出根据不同配置方式,执行的不同流程图:

在这里插入图片描述

2 第一阶段-Bean信息配置阶段

2.1 配置方式

Bean信息配置(定义)有4种方式:

  • 注解方式:@Component、@Configuration@Bean等等
  • xml文件方式:xxx.xml
  • API方式:通过BeanDefinitionBuilder工具类提供的各种API完成
  • properties文件方式:不常用,这里不详述,感兴趣的自行查阅相关文档。

2.2 配置信息

具体可以配置那些信息,在下面API配置打印BeanDefiniton信息后,我们在详细说明。

2.3 配置示例

下面给出一个简单的应用场景,现在我们需要把一个User(用户)信息存入数据库,按照三层架构,这里省略Controller,只给出UserService和UserDao。分别通过不同的方式配置UserDao和UserService的bean。

User类:

public class User {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                '}';
    }
}
2.3.1 注解方式配置
  • UserDao

    @Repository
    public class UserDao {
        public void insert(User user) {
            System.out.println("数据库正在插入数据!: " + user);
        }
    }
    
  • UserService

    @Service
    public class UserService {
    
        @Autowired
        private UserDao userDao;
    
        public void insert(User user) {
            userDao.insert(user);
        }
    }
    
2.3.2 xml文件配置

在UserService需要给属性userDao添加set方法

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

xml文件放置在类路径resources下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="userDao" class="com.gaogzhen.myspring.dao.UserDao"/>

    <bean id="userService" class="com.gaogzhen.myspring.service.UserService">
        <property name="userDao" ref="userDao"/>
    </bean>
</beans>
2.3.3 API方式

这里只做简单示范,在讲解完BeanDefinition注册后,单独讲解API方式详细配置,包括设置简单类型,设置引用类型,设置parent等等。

    public void testApiConfig() {
        BeanDefinitionBuilder userDaoBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserDao.class);
        Definition beanDefinition = userDaoBuilder.getBeanDefinition();

        System.out.println("userDao 的配置信息:" + beanDefinition);
        BeanDefinitionBuilder userServiceBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserService.class)
                .addPropertyReference("userDao", "userDao");
       BeanDefinition serviceBeanDefinition = userServiceBuilder.getBeanDefinition();
        System.out.println("userService 的配置信息:" + serviceBeanDefinition);
    }

输出信息如下:

userDao 的配置信息:Generic bean: class [com.gaogzhen.myspring.dao.UserDao]; scope=; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null
userService 的配置信息:Generic bean: class [com.gaogzhen.myspring.service.UserService]; scope=; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null

bean可配置信息:

  • class:类
  • scope:作用域,单例或者多例;在web应用中,还可以配置request,session等。
  • abstract:是否是抽象的
  • lazyInit:是否懒惰初始化
  • autowireMode:自动注入模式
    • AUTOWIRE_NO:不自动注入
    • AUTOWIRE_BY_NAME:通过bean名称自动注入(需要提供set方法)
    • AUTOWIRE_BY_TYPE:通过类型自动注入(需要提供set方法)
    • AUTOWIRE_CONSTRUCTOR:通过构造函数自动注入
    • AUTOWIRE_AUTODETECT:自动检测注入方式
  • dependencyCheck:依赖检查
    • DEPENDENCY_CHECK_NONE:不检查
    • DEPENDENCY_CHECK_OBJECTS:检查对象引用
    • DEPENDENCY_CHECK_SIMPLE:检查简单类型属性
  • autowireCandidate:是否是自动注入其他bean的候补,默认true。只影响根据类型的主动注入,不影响根据名称的自动注入。
  • primary:是否是自动注入主要候补
  • factoryBeanName:工厂bean名称
  • factoryMethodName:工厂bean方法名称
  • initMethodName:自定义初始化bean方法名称
  • destroyMethodName:自定义销毁bean方法名称

问题:

  1. 为什么在Service的BeanDefiniton打印信息中,没有关于userDao属性的相关信息呢?
  2. Bean与BeanDefinition的关系

在文章的最后统一给出解答。

3 第二阶段-Bean元信息解析阶段

解析过程就是把Bean元信息封装为BeanDefinition的过程。

因为API方式配置不同,相应的解析方式也不同。这里只讲解下XML文件和注解方式的解析,properties文件自行查阅相关文档。

  • 不同配置方式解析所需要的类
    • 注解:AnnotatedBeanDefinitionReader或者 ClassPathBeanDefinitionScanner
    • xml文件:XmlBeanDefinitionReader
    • properties文件:PropertiesBeanDefinitionReader
  • 说明:
    • 在new解析对象时,都需要一个BeanDefinitionRegister注册器类型的对象
    • 都是通过某个方法,在调用链中完成了解析和注册,并没有单独的解析注册接口(方法)。

3.1 注解方式解析

3.1.1 AnnotatedBeanDefinitionReader解析过程

以配置阶段注解配置示例为例,看下AnnotatedBeanDefinitionReader如何解析,示例代码如下:

    public void testAnnotateParse() {
        //定义一个spring容器,这个容器默认实现了BeanDefinitionRegistry,所以本身就是一个bean注册器
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        //定义一个注解方式的BeanDefinition读取器,需要传递一个BeanDefinitionRegistry(bean注册器)对象
        AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader = new AnnotatedBeanDefinitionReader(factory);
        // 解析注册
        annotatedBeanDefinitionReader.register(UserDao.class, UserService.class);


        //打印出注册的bean的配置信息
        for (String beanName : new String[]{"userDao", "userService"}) {
            //通过名称从容器中获取对应的BeanDefinition信息
            BeanDefinition beanDefinition = factory.getBeanDefinition(beanName);
            //获取BeanDefinition具体使用的是哪个类
            String beanDefinitionClassName = beanDefinition.getClass().getName();
            //通过名称获取bean对象
            Object bean = factory.getBean(beanName);
            //打印输出
            System.out.println(beanName + ":");
            System.out.println("    beanDefinitionClassName:" + beanDefinitionClassName);
            System.out.println("    beanDefinition:" + beanDefinition);
            System.out.println("    bean:" + bean);
        }

    }

也就是说解析注册通过AnnotatedBeanDefinitionReader的register()方法完成。下面我们通过源码来追踪下,经过了那些步骤(操作),解析出BeanDefinition。

  • regist()调用registerBean()

    	public void register(Class<?>... componentClasses) {
    		for (Class<?> componentClass : componentClasses) {
    			registerBean(componentClass);
    		}
    	}
    
  • registerBean()调用doRegisterBean()

    	public void registerBean(Class<?> beanClass) {
    		doRegisterBean(beanClass, null, null, null, null);
    	}
    
  • doRegisterBean()方法第一行:AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);通过AnnotatedGenericBeanDefinition构造方法new一个BeanDefinition对象。

    	private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
    			@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
    			@Nullable BeanDefinitionCustomizer[] customizers) {
    
    		AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
    		// ...省略其他代码
    		}
    
3.1.2 ClassPathBeanDefinitionScanner解析过程

下面看下ClassPathBeanDefinitionScanner解析实例代码:

ClassPathBeanDefinitionScanner beanDefinitionScanner = new ClassPathBeanDefinitionScanner(factory);
        beanDefinitionScanner.scan("com.gaogzhen.myspring.dao", "com.gaogzhen.myspring.service");

其他代码同上,这里调用scan()完成解析注册。下面通过源码跟踪下怎么完成解析的,我们只关注解析部分,其他暂时忽略。

  • 调用scan()方法里面doScan()方法

    	public int scan(String... basePackages) {
    		int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
    
    		doScan(basePackages);
    
    		// Register annotation config processors, if necessary.
    		if (this.includeAnnotationConfig) {
    			AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
    		}
    
    		return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
    	}
    
    
  • 276行doScan()执行findCandidateComponents()解析得到BeanDefinition集合

    	protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
    		Assert.notEmpty(basePackages, "At least one base package must be specified");
    		Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
    		for (String basePackage : basePackages) {
    			Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
    		//...省略其他代码
    		}
    
  • findCandidateComponents()判断如果有候选组件索引调用addCandidateComponentsFromIndex();否则调用scanCandidateComponents()。大部分情况下,没有开启候选组件索引生成,所以我们追踪下下面的方法。

    	public Set<BeanDefinition> findCandidateComponents(String basePackage) {
    		if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
                // 候选组件索引不为空且支持包含的过滤器
                // 通过生成的候选组件索引添加候选组件
    			return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
    		}
    		else {
                // 扫描包路径
    			return scanCandidateComponents(basePackage);
    		}
    	}
    
  • scanCandidateComponents()方法为解析生成BeanDefinition的核心方法

    	private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
    		Set<BeanDefinition> candidates = new LinkedHashSet<>();
    		try {
    			String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
    					resolveBasePackage(basePackage) + '/' + this.resourcePattern;
    			Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
    			boolean traceEnabled = logger.isTraceEnabled();
    			boolean debugEnabled = logger.isDebugEnabled();
    			for (Resource resource : resources) {
    				if (traceEnabled) {
    					logger.trace("Scanning " + resource);
    				}
    				try {
    					MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
    					if (isCandidateComponent(metadataReader)) {
    						ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
    						sbd.setSource(resource);
    						if (isCandidateComponent(sbd)) {
    							if (debugEnabled) {
    								logger.debug("Identified candidate component class: " + resource);
    							}
    							candidates.add(sbd);
    						}
    						//省略日志及异常处理
    		return candidates;
    	}
    
    • 执行流程

      • 转换包路径为绝对路径

        • basePacke->packageSearchPath->绝对路径: 形式 “com.gaogzhen.myspring.dao”==>classpath*:com/gaogzhen/myspring/dao/**/*.class==>“K:/projects/java/framework/spring6/spring6-006-cyclelife/target/classes/com/gaogzhen/myspring/dao/UserDao.class”
      • 通过资源解析器包装路径下的class为Resource对象

      • 通过MetadataReaderFactory传递resource创建对应的MetadataReader

        • MetadataReader:访问类元数据信息
      • isCandidateComponent()判断是否是候选组件

        	protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
        		for (TypeFilter tf : this.excludeFilters) {
        			if (tf.match(metadataReader, getMetadataReaderFactory())) {
        				return false;
        			}
        		}
        		for (TypeFilter tf : this.includeFilters) {
        			if (tf.match(metadataReader, getMetadataReaderFactory())) {
        				return isConditionMatch(metadataReader);
        			}
        		}
        		return false;
        	}
        
        • 判断如果和exclue过滤器内类型一致返回false;和include过滤器中类型一致返回true。

          • exclue过滤器默认为空;include过滤器中默认添加了Component.class,jakarta.annotation.ManagedBean,jakarta.inject.Named三种类型

            	protected void registerDefaultFilters() {
            		this.includeFilters.add(new AnnotationTypeFilter(Component.class));
            		ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
            		try {
            			this.includeFilters.add(new AnnotationTypeFilter(
            					((Class<? extends Annotation>) ClassUtils.forName("jakarta.annotation.ManagedBean", cl)), false));
            			logger.trace("JSR-250 'jakarta.annotation.ManagedBean' found and supported for component scanning");
            		}
            		catch (ClassNotFoundException ex) {
            			// JSR-250 1.1 API (as included in Jakarta EE) not available - simply skip.
            		}
            		try {
            			this.includeFilters.add(new AnnotationTypeFilter(
            					((Class<? extends Annotation>) ClassUtils.forName("jakarta.inject.Named", cl)), false));
            			logger.trace("JSR-330 'jakarta.inject.Named' annotation found and supported for component scanning");
            		}
            		catch (ClassNotFoundException ex) {
            			// JSR-330 API not available - simply skip.
            		}
            	}
            
        • 实际执行的match()方法为AbstractTypeHierarchyTraversingFilter中的

          	public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
          			throws IOException {
          
          		// This method optimizes avoiding unnecessary creation of ClassReaders
          		// as well as visiting over those readers.
          		if (matchSelf(metadataReader)) {
          			return true;
          		}
          		ClassMetadata metadata = metadataReader.getClassMetadata();
          		if (matchClassName(metadata.getClassName())) {
          			return true;
          		}
          
          		if (this.considerInherited) {
          			String superClassName = metadata.getSuperClassName();
          			if (superClassName != null) {
          				// Optimization to avoid creating ClassReader for super class.
          				Boolean superClassMatch = matchSuperClass(superClassName);
          				if (superClassMatch != null) {
          					if (superClassMatch.booleanValue()) {
          						return true;
          					}
          				}
          				else {
          					// Need to read super class to determine a match...
          					try {
          						if (match(metadata.getSuperClassName(), metadataReaderFactory)) {
          							return true;
          						}
          					}
          					catch (IOException ex) {
          						if (logger.isDebugEnabled()) {
          							logger.debug("Could not read super class [" + metadata.getSuperClassName() +
          									"] of type-filtered class [" + metadata.getClassName() + "]");
          						}
          					}
          				}
          			}
          		}
          
          		if (this.considerInterfaces) {
          			for (String ifc : metadata.getInterfaceNames()) {
          				// Optimization to avoid creating ClassReader for super class
          				Boolean interfaceMatch = matchInterface(ifc);
          				if (interfaceMatch != null) {
          					if (interfaceMatch.booleanValue()) {
          						return true;
          					}
          				}
          				else {
          					// Need to read interface to determine a match...
          					try {
          						if (match(ifc, metadataReaderFactory)) {
          							return true;
          						}
          					}
          					catch (IOException ex) {
          						if (logger.isDebugEnabled()) {
          							logger.debug("Could not read interface [" + ifc + "] for type-filtered class [" +
          									metadata.getClassName() + "]");
          						}
          					}
          				}
          			}
          		}
          
          		return false;
          	}
          
        • 先判断注解类型是否匹配

          • 示例中匹配这里
        • 在判断类名是否匹配

        • 在判断是否是继承匹配

        • 在判断是否是接口匹配

      • ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);new新的ScannedGenericBeanDefinition类型的BeanDefinition。解析完成。

思考:

  • 候选组件索引是啥东西?

3.2 xml文件解析

通过XmlBeanDefinitionReader解析xml中配置的bean为对应的BeanDefinition,以配置中xml文件为例,下面给出解析实例代码:

    public void testXmlParse() {
        //定义一个spring容器,这个容器默认实现了BeanDefinitionRegistry,所以本身就是一个bean注册器
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);

        // XmlBeanDefinitionReader加载xml配置文件,解析生成BeanDefinition注册到容器中
        String location = "classpath:config.xml";
        int beanCount = reader.loadBeanDefinitions(location);
        System.out.println(String.format("共注册了 %s 个bean", beanCount));

        //打印出注册的bean的配置信息
        for (String beanName : factory.getBeanDefinitionNames()) {
            //通过名称从容器中获取对应的BeanDefinition信息
            BeanDefinition beanDefinition = factory.getBeanDefinition(beanName);
            //获取BeanDefinition具体使用的是哪个类
            String beanDefinitionClassName = beanDefinition.getClass().getName();
            //通过名称获取bean对象
            Object bean = factory.getBean(beanName);
            //打印输出
            System.out.println(beanName + ":");
            System.out.println("    beanDefinitionClassName:" + beanDefinitionClassName);
            System.out.println("    beanDefinition:" + beanDefinition);
            System.out.println("    bean:" + bean);
        }
    }

输出:

2023-03-08 09:43:06 521 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 2 bean definitions from class path resource [config.xml]
共注册了 2 个bean
2023-03-08 09:43:06 526 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'userDao'
userDao:
    beanDefinitionClassName:org.springframework.beans.factory.support.GenericBeanDefinition
    beanDefinition:Generic bean: class [com.gaogzhen.myspring.dao.UserDao]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [config.xml]
    bean:com.gaogzhen.myspring.dao.UserDao@55342f40
2023-03-08 09:43:06 536 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'userService'
userService:
    beanDefinitionClassName:org.springframework.beans.factory.support.GenericBeanDefinition
    beanDefinition:Generic bean: class [com.gaogzhen.myspring.service.UserService]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [config.xml]
    bean:com.gaogzhen.myspring.service.UserService@306851c7

XmlBeanDefinitionReader调用loadBeanDefinitions()完成了xml配置文件的加载解析和注册,下面我们通过源码追踪下解析为BeanDefinition的流程。在追踪过程中其他非关键步骤,我们直接省略。

调用AbstractBeanDefinitionReader的loadBeanDefinitions()

	public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
		return loadBeanDefinitions(location, null);
	}

继续调用loadBeanDefinitions()

	public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
		// 资源加载器
		ResourceLoader resourceLoader = getResourceLoader();
		if (resourceLoader == null) {
			throw new BeanDefinitionStoreException(
					"Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
		}

		if (resourceLoader instanceof ResourcePatternResolver) {
			// Resource pattern matching available.
			try {
				Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
				int count = loadBeanDefinitions(resources);
			// 省略
	}

int count = loadBeanDefinitions(resources);继续调用loadBeanDefinitions()

	public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
		Assert.notNull(resources, "Resource array must not be null");
		int count = 0;
		for (Resource resource : resources) {
		   // 继续调用
			count += loadBeanDefinitions(resource);
		}
		return count;
	}

调用loadBeanDefinitions()回到XMLBeanDefinition的loadBeanDefinitions()方法

	public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
		return loadBeanDefinitions(new EncodedResource(resource));
	}

分析:

  • EncodedResource :组合字符编码或者字符集,用于从resource读取信息

调用loadBeanDefinitions()方法

	public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
		// 省略
        	// 继续调用
			return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
	// 省略
	}

分析:

  • ThreadLocal<Set<EncodedResource>> resourcesCurrentlyBeingLoaded 这个用于当前线程保存已加载resource
  • 在finally中使用完之后做了移除

继续调用doLoadBeanDefinitions()

	protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {

		try {
            // Document为解析xml文件后封装的对象
			Document doc = doLoadDocument(inputSource, resource);
			int count = registerBeanDefinitions(doc, resource);
			if (logger.isDebugEnabled()) {
				logger.debug("Loaded " + count + " bean definitions from " + resource);
			}
			return count;
		}
	// 省略异常处理代码
	}

分析:

  • Document:HTML或者XML文档接口,表示文档树的根,提供访问数据的方法;文档中包含元素、文本结点、注释等等。

继续调用registerBeanDefinitions()

	public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		int countBefore = getRegistry().getBeanDefinitionCount();
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}

继续调用DefaultBeanDefinitionDocumentReader的registerBeanDefinitions()方法

	public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
		this.readerContext = readerContext;
		doRegisterBeanDefinitions(doc.getDocumentElement());
	}

调用doRegisterBeanDefinitions()

	protected void doRegisterBeanDefinitions(Element root) {
		// 省略
		// preProcessXml为空方法,由子类去实现
		preProcessXml(root);
		parseBeanDefinitions(root, this.delegate);
        // preProcessXml为空方法,由子类去实现
		postProcessXml(root);

		this.delegate = parent;
	}

继续调用parseBeanDefinitions()

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 ele) {
             // 判断结点是否是Element
            if (delegate.isDefaultNamespace(ele)) {
                // 判断是不是默认,即命名空间是不是"http://www.springframework.org/schema/beans"
               parseDefaultElement(ele, delegate);
            }
            else {
                // 自定义
               delegate.parseCustomElement(ele);
            }
         }
      }
   }
   else {
      delegate.parseCustomElement(root);
   }
}

分析:

  • 一般我们直接使用spring提供标准的xml beans配置

    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    

继续调用parseDefaultElement()

	private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
		if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
			importBeanDefinitionResource(ele);
		}
		else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
			processAliasRegistration(ele);
		}
		else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
            // <bean></bean>标签对应的元素
			processBeanDefinition(ele, delegate);
		}
		else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
			// <beans></beans>标签对应的元素,会递归调用
			doRegisterBeanDefinitions(ele);
		}
	}

继续调用processBeanDefinition()

	protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		// 省略注册相关
	}

继续调用BeanDefinitionParserDelegate的parseBeanDefinitionElement()方法

	public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
		return parseBeanDefinitionElement(ele, null);
	}

继续调用parseBeanDefinitionElement()

	public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
		String id = ele.getAttribute(ID_ATTRIBUTE);
		// 省略
		AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
	// 省略设置别名等操作
	}

分析:id这里获取<bean id=“xxx”>中的id,即beanName

继续调用parseBeanDefinitionElement()

	@Nullable
	public AbstractBeanDefinition parseBeanDefinitionElement(
			Element ele, String beanName, @Nullable BeanDefinition containingBean) {

		this.parseState.push(new BeanEntry(beanName));

		String className = null;
		if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
			className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
		}
		String parent = null;
		if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
			parent = ele.getAttribute(PARENT_ATTRIBUTE);
		}

		try {
			AbstractBeanDefinition bd = createBeanDefinition(className, parent);

			parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
			bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

			parseMetaElements(ele, bd);
			parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
			parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

			parseConstructorArgElements(ele, bd);
			parsePropertyElements(ele, bd);
			parseQualifierElements(ele, bd);

			bd.setResource(this.readerContext.getResource());
			bd.setSource(extractSource(ele));

			return bd;
		}
		// 省略异常处理
		return null;
	}

哎总算找到了封装BeanDefinition的地方。这里获取并设置BeanDefinition信息,比如className,parent,等等。

总结,解析封装BeanDefinition的过程:

  • 加载读取xml文件为Docment文档对象;
  • 递归获取Bean标签对应的Element元素;
  • 从Element元素获取BeanDefinition所需信息。

3.3 注解解析与xml解析比较

  • AnnotatedBeanDefinitionReader,传递Class对象,通过Class对象及其注解获取BeanDefinition信息,封装为AnnotatedGenericBeanDefinition对象。
  • ClassPathBeanDefinitionScanner需要扫描包下面.class文件,完成class加载,完成注解类型校验后获取BeanDefinition信息封装为ScannedGenericBeanDefinition对象。
  • XmlBeanDefinitionReader加载校验解析xml文件中bean,获取信息封装为GenericBeanDefinition对象。
  • XmlBeanDefinitionReader过程更为繁琐复杂;ClassPathBeanDefinitionScanner在没有开启候选组件索引生成的情况下不建议使用,原因在解答候选组件索引这个内容的时候给出;更为推荐AnnotatedBeanDefinitionReader解析Bean。

4 问题解答

  • 为什么在Service的BeanDefiniton打印信息中,没有关于userDao属性的相关信息呢?
  • Bean与BeanDefinition的关系

这两个问题在理解了Bean和BeanDefinition关系之后,就很容易理解,参考下面的[2]。

  • 候选组件索引

参考下面[3]

后记

❓QQ:806797785

⭐️源代码仓库地址:https://gitee.com/gaogzhen/spring6-study

参考:

[1]Spring系列之Bean生命周期详解[CP/OL].

[2]spring源码分析系列2:Bean与BeanDefinition关系[CP/OL].

[2]Spring 5 启动性能优化之 @Indexed[CP/OL].

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gaog2zh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值