• spring 学习-bean创建-scan扫描bean


    概述

    文章分析注解方式注入bean 的代码过程。本篇将介绍 AnnotationConfigApplicationContext 该类的关于扫描注释关于 bean 的过程。

    前言

    我们使用过spring框架 ,知道了生成 bean 的方式可以有 XML 配置文件, 也可以通过注解。我们分析源码前可以思考假如给你一个XML文件最终要装配到容器中去,你的步骤应该是如何的 :

    • 读取
    • 解析
    • 注册

    spring 中也是遵循这个思路的, 我们先看一下 BeanFactory 和 Context 的关系 ,并且了解一下他们的继承关系 , 这两个类是生成 bean 重要的两个接口。

    1297993-20200430151701108-2090354936.png

    注释方式注入Bean 方式

    注解式生成bean的过程,总的来说就是 :

    1. 初始化一个Context

    2. 扫描生成 BeanDefinition

    3. 调用 refresh 方法

    其中第一个步骤由于是注解类,利用第一步初始化生成的 Scan 类进行扫描特定包下的 bean ,然后根据属性,例如作用域,单例模式还是模板模式等属性生成 BeanDefinition ,最后调用 上下文 context 父类的refresh 方法,进行调用(BeanFactoryPostProcess)后置处理器处理方法和BeanPostProcess处理器处理方法。

    Demo 1

        public static void main(String[] args) {
            AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext();
            //这里看到我们注册了一个 configuration 的类进行配置,然后刷新一下容器得到最新的结果
            consumerContext.register(ConsumerConfiguration.class);
            consumerContext.refresh();
    
            //从容器中获取类
            FooServiceConsumer service = consumerContext.getBean(FooServiceConsumer.class);
    
            ...
    
        }   
    

    Demo 2

    idea 中new一个新的 spring项目,然后编写两个类 。

    @Component
    public class MyService {
        public String sayHello(){
            return "hello world ";
        }
    
    
    }
    
    
    public class SpringTest {
    
        public static void main(String[] args) {
            ApplicationContext ctx = new AnnotationConfigApplicationContext("main");//A
            MyService myService = ctx.getBean(MyService.class);
            String s = myService.sayHello();
            System.out.println("s : "+ s);
        }
    }
    
    

    我们以例子二为源码阅读,从 A 处 debug 进去,看一下 bean 的加载和创建

    AnnotationConfigApplicationContext 的创建过程概述

    构造方法很清晰 : 初始化,扫描,刷新三个步骤。

    	public AnnotationConfigApplicationContext(String... basePackages) {
    		//初始化
            this();
            //扫描包
    		scan(basePackages);
            //刷新 
    		refresh();
    	}
    

    源码分析

    需要知道的类 :

    • Resoure 对应读取操作
    • BeanDefinitionRead 对应解析操作
    • Registry 对应注册操作。

    AnnotationConfigApplicationContext为例子,查看类图主要包含三个类型的接口

    • AppContext接口 : 上下文相关
    • Lifecycle接口 : 生命周期相关
    • Registry接口 : 用于注册 BeanDefinition

    AnnotationConfigApplicationContext 的初始化创建的两个类作用如下 :

    • AnnotatedBeanDefinitionReader :注册几个后置处理器
    • ClassPathBeanDefinitionScanner :扫描包内的bean
    	public AnnotationConfigApplicationContext(String... basePackages) {
            //初始化
    		this();
            //扫描包
    		scan(basePackages);
            //刷新 
    		refresh();
    	}
    
    
    	/**
    	 * Create a new AnnotationConfigApplicationContext that needs to be populated
    	 * through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
         * 
         * 构造方法,从注释也可以看到,构造完,需要调用  register 方法进行填充和 refresh 方法进行刷新
    	 */
    	public AnnotationConfigApplicationContext() {
    		this.reader = new AnnotatedBeanDefinitionReader(this);
    		this.scanner = new ClassPathBeanDefinitionScanner(this);
    	}
    
    
    	//============ 父类初始化  ==============
    
        //==========================
    	//GenericApplicationContext
    	public GenericApplicationContext() {
    		this.beanFactory = new DefaultListableBeanFactory();
    	}
    
    
    	//AbstractApplicationContext
    	public AbstractApplicationContext() {
    		this.resourcePatternResolver = getResourcePatternResolver();
    	}
    
    
    	//DefaultResourceLoader
    	public DefaultResourceLoader() {
    		this.classLoader = ClassUtils.getDefaultClassLoader();
    	}
    
    	public static ClassLoader getDefaultClassLoader() {
    		ClassLoader cl = null;
    		try {
    			cl = Thread.currentThread().getContextClassLoader();
    		}
    		catch (Throwable ex) {
    			// Cannot access thread context ClassLoader - falling back...
    		}
    		if (cl == null) {
    			// No thread context class loader -> use class loader of this class.
    			cl = ClassUtils.class.getClassLoader();
    			if (cl == null) {
    				// getClassLoader() returning null indicates the bootstrap ClassLoader
    				try {
    					cl = ClassLoader.getSystemClassLoader();
    				}
    				catch (Throwable ex) {
    					// Cannot access system ClassLoader - oh well, maybe the caller can live with null...
    				}
    			}
    		}
    		return cl;
    	}
    
    
    	//============ 父类初始化  ==============
    
    	//============ AnnotatedBeanDefinitionReader 类初始化  ==============
    
    	
    	public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
    		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    		Assert.notNull(environment, "Environment must not be null");
    		//保存父类字段
    		this.registry = registry;
    		//步骤一 : 用于解析 @Condition 注解相关
    		this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
    		//步骤二 : 最终会调用 register&registerBeanDefinition方法注册入几个默认的 BeanDefinition 
    		AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
    	}
    
    	
    
    
    

    其中步骤二中注入的类包括 :

    作用:内部托管配置注释处理器。
    对应的类:ConfigurationClassPostProcessor.class
    
    作用:内部管理的自动注入注解处理器
    对应的类:AutowiredAnnotationBeanPostProcessor.class
    
    作用:内部管理的JSR-250注释处理器
    对应的类:CommonAnnotationBeanPostProcessor.class
    
    作用:内部管理的JPA注释处理器(不一定注入)。
    对应的类:PersistenceAnnotationBeanPostProcessor.class
    
    作用:内部管理的@EventListener注释处理器
    对应的类:EventListenerMethodProcessor.class
    
    作用:内部管理的EventListenerFactory。
    对应的类:DefaultEventListenerFactory.class
    
    

    BeanDefinition 是个接口,我们看一下 ClassPathBeanDefinitionScanner 会扫描我们项目中的 bean

    1297993-20200502223721279-36302072.png

    该类注解 : 
    
    A bean definition scanner that detects bean candidates on the classpath, registering corresponding bean definitions with a given registry (BeanFactory or ApplicationContext).
    Candidate classes are detected through configurable type filters. The default filters include classes that are annotated with Spring's @Component, @Repository, @Service, or @Controller stereotype.
    
    

    下面我们看一下核心的scan 方法,它的调用栈挺长的,我们只需要知道scan 中会进行 :

    • 扫描所有 bean
    • 添加几个postprocess(后置处理器)作为 beanDefinition ,方便后续的
    	
    
        @Override
    	public void scan(String... basePackages) {
    		Assert.notEmpty(basePackages, "At least one base package must be specified");
            //使用上面构造方法生成的 scan 对象,执行 scan 方法 
    		this.scanner.scan(basePackages);
    	}
    
    	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);
    	}
    
    
    	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) {
    			//这里会把配置文件中的 bean 读取出来,然后进行注册
    			Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
    			for (BeanDefinition candidate : candidates) {
    				ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
    				candidate.setScope(scopeMetadata.getScopeName());
    				String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
    				if (candidate instanceof AbstractBeanDefinition) {
    					//为每个 BeanDefinition 填充作为 BeanDefinition 的属性值 
    					postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
    				}
    				if (candidate instanceof AnnotatedBeanDefinition) {
    					AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
    				}
    				//检查这个 BeanDefinition 是否一件存在,因为默认是单例,可以想象得到肯定是去 DefaultListableBeanFactory 中判断寻找
    				if (checkCandidate(beanName, candidate)) {
    					//封装成 BeanDefinitionHolder 对象
    					BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
    					definitionHolder =
    							AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
    					beanDefinitions.add(definitionHolder);
    					// register 注册  
    					registerBeanDefinition(definitionHolder, this.registry);
    				}
    			}
    		}
    		return beanDefinitions;
    	}		
    
    
    
    	protected void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {
    		//这里调用的一个工具类的静态方法
            BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
    	}	
    
    	//BeanDefinitionReaderUtils 类方法 
    	public static void registerBeanDefinition(
    			BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
    			throws BeanDefinitionStoreException {
    
    		// Register bean definition under primary name.
    		String beanName = definitionHolder.getBeanName();
    		//最终调用的是 registry 的 registerBeanDefinition 方法 
    		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);
    			}
    		}
    	}	
    
    

    继续看 , 也就是说我们扫描到的类跑到了 registry ,我们看一下 registry 的 registerBeanDefinition 方法做了什么事呢 ?

        
        /** Map of bean definition objects, keyed by bean name. */
    	private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
        
    
        ...
    
       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,就是将BeanDefinition放入一个map中,key是beanName
    	//注册之前,先查下是否被注册过
    	BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
    	//如果已经存在,那么就检查是否允许覆盖,不允许直接跑异常,允许的话就记录一些日志,然后覆盖
    	if (existingDefinition != null) {
    		//默认允许覆盖
    		if (!isAllowBeanDefinitionOverriding()) {
    			//如果bean已经被注册了,并且不允许覆盖,那么抛出异常
    			throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
    					"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
    							"': There is already [" + existingDefinition + "] bound.");
    		} else if (existingDefinition.getRole() < beanDefinition.getRole()) {
    			// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
    			if (logger.isWarnEnabled()) {
    				logger.warn("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.isInfoEnabled()) {
    				logger.info("Overriding bean definition for bean '" + beanName +
    						"' with a different definition: replacing [" + existingDefinition +
    						"] with [" + beanDefinition + "]");
    			}
    		} else {
    			if (logger.isDebugEnabled()) {
    				logger.debug("Overriding bean definition for bean '" + beanName +
    						"' with an equivalent definition: replacing [" + existingDefinition +
    						"] with [" + beanDefinition + "]");
    			}
    		}
    		this.beanDefinitionMap.put(beanName, beanDefinition);
    	} else {
    		//检查bean的创建过程是否已经开始了
    		//通过判断一个set集合是否为空,因为创建过的bean都会放到那个set中保存下
    		if (hasBeanCreationStarted()) {
    			// Cannot modify startup-time collection elements anymore (for stable iteration)
    			// 这是使用同步方法 
    			synchronized (this.beanDefinitionMap) {
    				this.beanDefinitionMap.put(beanName, beanDefinition);
    				//下面4行是更新beanDefinitionNames的list
    				List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
    				updatedDefinitions.addAll(this.beanDefinitionNames);
    				updatedDefinitions.add(beanName);
    				this.beanDefinitionNames = updatedDefinitions;
    				//manualSingletonNames人工注册的单例集合,也要更新
    				if (this.manualSingletonNames.contains(beanName)) {
    					Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
    					updatedSingletons.remove(beanName);
    					this.manualSingletonNames = updatedSingletons;
    				}
    			}
    		} else {
    			// Still in startup registration phase:仍然在启动注册阶段
    			this.beanDefinitionMap.put(beanName, beanDefinition);
    			this.beanDefinitionNames.add(beanName);
    			this.manualSingletonNames.remove(beanName);
    		}
    		this.frozenBeanDefinitionNames = null;
    	}
    
    	if (existingDefinition != null || containsSingleton(beanName)) {
    		resetBeanDefinition(beanName);
    	}
    }
    
    

    核心的逻辑就是放入该类的一个 map 中去 , 这个 map 为 ConcurrentHashMap 。还有一个地方 , 这个 registry 是在哪里传进来的呢?

    public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
    
    	private final AnnotatedBeanDefinitionReader reader;
    
    	private final ClassPathBeanDefinitionScanner scanner;
    
    
    	/**
    	 * Create a new AnnotationConfigApplicationContext that needs to be populated
    	 * through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
    	 */
    	public AnnotationConfigApplicationContext() {
    		StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
    		this.reader = new AnnotatedBeanDefinitionReader(this);
    		createAnnotatedBeanDefReader.end();
    		// context 把自己传给了我们上面的扫描对象 
    		this.scanner = new ClassPathBeanDefinitionScanner(this);
    	}
        
        ...
    }
    
    
    	//看一下我们刚才上面分析的扫描对象 
    	public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
    			Environment environment, @Nullable ResourceLoader resourceLoader) {
    
    		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    		this.registry = registry;
    
    		if (useDefaultFilters) {
    			registerDefaultFilters();
    		}
    		setEnvironment(environment);
    		setResourceLoader(resourceLoader);
    	}
    	...
    }
    
    

    ok, scan 方法我们就了解这么多,下篇我们看一下 refresh方法。

    总结

    该篇文章我们介绍了 AnnotationConfigApplicationContext 的初始化过程,剩下的 refresh 方法将会留到下一篇文章进行讲解。

    参考资料

    参考资料

  • 相关阅读:
    4.2Python数据处理篇之Matplotlib系列(二)---plt.scatter()散点图
    4.1Python数据处理篇之Matplotlib系列(一)---初识Matplotlib
    3.8Python数据处理篇之Numpy系列(八)---Numpy的梯度函数
    3.7Python数据处理篇之Numpy系列(七)---Numpy的统计函数
    3.6Python数据处理篇之Numpy系列(六)---Numpy随机函数
    3.5Python数据处理篇之Numpy系列(五)---numpy文件的存取
    3.4Python数据处理篇之Numpy系列(四)---ndarray 数组的运算
    3.3Python数据处理篇之Numpy系列(三)---数组的索引与切片
    3.2Python数据处理篇之Numpy系列(二)--- ndarray数组的创建与变换
    3.1Python数据处理篇之Numpy系列(一)---ndarray对象的属性与numpy的数据类型
  • 原文地址:https://www.cnblogs.com/Benjious/p/15087613.html
Copyright © 2020-2023  润新知