• 谈谈Spring的ImportSelector和ImportBeanDefinitionRegistrar


    1、@Import

    在聊ImportSelector和ImportBeanDefinitioRegistar之前需要先知道@Import。

    @Import是写在我们的配置类上的,如下:

    @Configuration
    @Import({XXX.class,XXX2.class})
    public class AppConfig {
    }
    

    当Spring扫描我们AppConfig后,就能拿到我们@Import中填的Class,并将其实例化后放到容器当中。

    2、@Import中的三种类

    @Import中填入的类可以区分为三种:

    • 实现ImportSelector的类
    • 实现ImportBeanDefinitionRegistrar的类
    • 其余的普通类

    3、ImportSelector

    首先我们看看接口方法:

    public interface ImportSelector {
    
    	/**
    	 * Select and return the names of which class(es) should be imported based on
    	 * the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
    	 * @return the class names, or an empty array if none
    	 */
    	String[] selectImports(AnnotationMetadata importingClassMetadata);
    
    }
    

    这里面要求返回一个String数组,该数组的值为类的全包名,例如:new String[]{"com.dh.AccountService","com.dh.UserService"},那么Spring就会将数组中的类实例化到容器当中。

    该方法的参数AnnotationMetadata,此对象为我们@Import所在的类的元信息,例如其他注解,类信息等,在我们的示例代码中,此AnnotationMetadata中可以拿到Configuration注解,Import注解,Class信息,看下图:

    这玩意应用场景:可以根据不同的情况来决定注入哪些类,在我们不考虑环境的情况下,可以直接@Bean注入类,也可以直接扫描,而当我们考虑环境的情况下,就有可能某些类并不注入,而且甚至可能需要逻辑代码校验来决定,那么就可以使用这个接口来进行逻辑代码校验并决定是否注入等。

    4、ImportBeanDefinitionRegistrar

    先看看接口方法

    public interface ImportBeanDefinitionRegistrar {
    
    	/**
    	 * Register bean definitions as necessary based on the given annotation metadata of
    	 * the importing {@code @Configuration} class.
    	 * <p>Note that {@link BeanDefinitionRegistryPostProcessor} types may <em>not</em> be
    	 * registered here, due to lifecycle constraints related to {@code @Configuration}
    	 * class processing.
    	 * @param importingClassMetadata annotation metadata of the importing class
    	 * @param registry current bean definition registry
    	 */
    	void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);
    
    }
    

    这个相比上一个Selector更牛逼,它给了我们一个BeanDefinition的注册器(其实它也是我们的Bean工厂,而我们的Bean工程也是注册器),我们先看看BeanDefinitionRegistry实际上的类型:

    而这里的AnnotationMetadata和上面的ImportSelector是一样的。

    这玩意的应用场景:

    ​ 例如Mybatis的代理我们Dao的操作,它需要干的事情是这样的:

    ​ 1、拿到我们的需要代理的Mapper包并进行扫描

    ​ 2、生成这些Mappeer的代理实现类,其中包含了它自己的业务规则

    ​ 3、将生成的Mapper代理实现类存入Spring容器当中去

    ​ 那么这里我们将Mapper代理实现类存入Spring容器这个步骤就需要我们的ImportBeanDefinitionRegistrar来实现。

    ​ MyBatis是如何做的呢?

    ​ 它首先需要一个@MapperScan注解,这个注解里面包含了@Import注解,并导入了它自己ImportBeanDefinitionRegistrar实现类,名字叫MapperScannerRegistrar

    ,此类当中首先扫描我们MapperScan中value的包,然后循环这些Mapper,完了再创建BeanDefinition,再通过FactoryBean实例化这些Mapper的代理类,并将这些BeanDefinition存入spring容器中,然后Spring容器就会实例化这些代理类。

    5、使用ImportBeanDefinitionRegistar模拟一下Mybatis代理Mapper

    5.1、自定义注解Select

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    @Documented
    public @interface Select {
    
    	public String value() default "";
    
    }
    

    5.2、TestMyFactoryBean

    @SuppressWarnings({"rawtypes", "unchecked"})
    public class TestMyFactoryBean implements FactoryBean,InvocationHandler {
    
    	@SuppressWarnings({"rawtypes", "unchecked"})
    	Class interfaces;
    
    	@SuppressWarnings({"rawtypes", "unchecked"})
    	public TestMyFactoryBean(Class interfaces) {
    		this.interfaces = interfaces;
    	}
    
    	@SuppressWarnings({"rawtypes", "unchecked"})
    	@Override
    	public Object getObject() throws Exception {
    		Class[] classes = new Class[]{interfaces};
    		return Proxy.newProxyInstance(this.getClass().getClassLoader(), classes,this);
    		//return userDao;
    	}
    
    	@SuppressWarnings({"rawtypes", "unchecked"})
    	@Override
    	public Class getObjectType() {
    		return interfaces;
    	}
    
    	@Override
    	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    		Select select = method.getAnnotation(Select.class);
    		if (Objects.nonNull(select)) {
    			System.out.println("method : "+method.getName()+"run sql :" + select.value());
    		}
    		return "this is return value";
    	}
    }
    

    5.3、UserDao

    public interface UserDao {
    
    	@Select("select * from user were id = ?")
    	public Object findById();
    
    }
    

    5.4、MyImportBeanDefinitionRegister

    public class MyImportBeanDefinitionRegister implements ImportBeanDefinitionRegistrar {
    	@Override
    	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    		/* 假装这是我们扫描到的Mapper */
    		UserDao userDao;
    		/* 生成一个FactoryBean,Mybatis对应的 */
    		BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(TestMyFactoryBean.class);
    		/* 从Builder中拿到BeanDefinition */
    		AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
    		/* 添加构造器参数 */
    		beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(UserDao.class.getName());
    		registry.registerBeanDefinition("userDao",beanDefinition);
    	}
    }
    
    

    5.5、AppConfig

    @Configuration
    @Import(MyImportBeanDefinitionRegister.class)
    public class AppConfig {
    }
    

    5.6、Main1

    public class Main1 {
    
    	/**
    	 * 测试方法1
    	 * */
    	public static void test1(){
    		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
    		applicationContext.register(AppConfig.class);
    		applicationContext.refresh();
    		UserDao userDao = applicationContext.getBean(UserDao.class);
    		System.out.println(userDao.findById());
    	}
    	public static void main(String[] args) {
    		test1();
    	}
    }
    

    这个代码解释:

    ​ @Select:这个是用来模拟Mybatis的Select注解的,里面只有一个value参数

    ​ TestMyFactoryBean:这个涉及到Spring中FactoryBean的知识,当我们的类实现FactoryBean这个接口后,那么Spring将不会直接把我们这个类的实例对象当做Bean存入到容器当中,而是将实现的getObject()方法的返回值实例对象当做Bean存入到容器当中去

    ​ UserDao:模拟我们Mybatis当中的Mapper接口(实际上它就应该是一个Mapper接口)

    ​ MyImportBeanDefinitionRegister:实现了我们ImportBeanDefinitionRegistar接口的实现类,在这里面我们假装UserDao.class是我们扫描到的,然后生成一个BeanDefinitionBuilder,然后再设置其FactoryBean实现类中构造器的参数,然后再将我们生成的BeanDefinition存入到Spring当中去

    ​ AppConfig:配置类,其中注意我们@Import中填入了我们的MyImportBeanDefinitionRegister

    ​ Main1:主类

    这里我们可能有疑问,Mybatis是使用MapperScan的,然后在MapperScan中@import了它自己的ImportBeanDefinitionRegistar实现类,而我们这里直接在配置类里面自己@Import了,那么这块需要涉及到自定义扫描我们的注解,这样才能让我们扫描到MapperScan并做后序解析,这块内容是其他方面的知识,后序随笔中会加入这些内容,这里就不对其进行过于的描述,主要是要让大家明白@Import中的三个类,以及其应用场景。

    6、源码解析Import的操作在哪

    1、我们从底下往上看,首先是我们的Main1中去调用test1,这个是我自己写的Main方法, 不重要:

    public class Main1 {
    	public static void test1(){
    		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
    		applicationContext.register(AppConfig.class);
    		applicationContext.refresh();	// 进入到此方法中
    		UserDao userDao = applicationContext.getBean(UserDao.class);
    		System.out.println(userDao.findById());
    		}
    
    	public static void main(String[] args) {
    		test1();
    	}
    }
    

    2、然后我们看applicationContext中的refresh方法

    @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.,获取BeanFactory
    			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    			// Prepare the bean factory for use in this context.,做一些Bean的准备工作
    			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);					//	=================================line1
    				// Register bean processors that intercept bean creation.注册BeanPostProcessor
    				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) {
    				if (logger.isWarnEnabled()) {
    					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;
    			}
    			finally {
    				// Reset common introspection caches in Spring's core, since we
    				// might not ever need metadata for singleton beans anymore...
    				resetCommonCaches();
    			}
    		}
    	}
    

    此refresh方法中进入到line1方法中,line1这个方法主要是用于执行我们自己定义的BeanFactoryPostProcessor和Spring内置的BeanFactoryPostProcessor,进入看line1下的代码。

    3、进入invokeBeanFactoryPostProcessors方法

    protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    		PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());	//	line1
    		// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
    		// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
    		if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
    			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
    			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    		}
    	}
    

    此方法会进入到line1当中去,在我们的BeanFactoryPostProcessors当中有三种来源:

    ​ 1、Spring内置的

    ​ 2、我们手动加入到Spring的

    ​ 3、我们自定义后被Spring扫描到的

    这里的getBeanFactoryPostProcessor是我们自己手动加入到Spring的。

    4、进入到invokeBeanFactoryPostProcessors方法中

    public static void invokeBeanFactoryPostProcessors(
    			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
    
    		// Invoke BeanDefinitionRegistryPostProcessors first, if any.
    		Set<String> processedBeans = new HashSet<>();
    
    		if (beanFactory instanceof BeanDefinitionRegistry) {
    			BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
    			/* 用来存放我们手动添加的BeanFactoryPostProcessor */
    			List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
    			/* 用来存放我们手动添加的BeanDefinitionRegistryPostProcessor */
    			List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
    			/* 此处判断我们手动添加的BeanPostProcessor是否为BeanDefinitionRegistryPostProcessor类型的,如果是,那么则直接执行以下,否则就到后面去执行默认自带的BeanDefinitionRegistryPostProcessor */
    			for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
    				/* 判断BeanPostProcessor的类型是否为BeanDefinitionRegistryPostProcessor,但注意它的类型一定为BeanFactoryPostProcessor */
    				if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
    					BeanDefinitionRegistryPostProcessor registryProcessor =
    							(BeanDefinitionRegistryPostProcessor) postProcessor;
    					registryProcessor.postProcessBeanDefinitionRegistry(registry);
    					registryProcessors.add(registryProcessor);
    				}
    				else {
    					regularPostProcessors.add(postProcessor);
    				}
    			}
    
    			// Do not initialize FactoryBeans here: We need to leave all regular beans
    			// uninitialized to let the bean factory post-processors apply to them!
    			// Separate between BeanDefinitionRegistryPostProcessors that implement
    			// PriorityOrdered, Ordered, and the rest.这个就是一个临时的List用来存放找到的内置的BeanDefinitionRegistryPostProcessor
    			/* 用来存放Spring内置的BeanDefinitionRegistryPostProcessor */
    			List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
    			// BeanDefinitionRegistry
    			// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.拿到所有实现BeanDefinitionRegistryPostProcessor接口的BeanFactoryPostProcessor,并放置到currentRegistryProcessors中
    			/* 拿到实现了BeanDefinitionRegistryPostProcessor接口的类名的beanName */
    			String[] postProcessorNames =
    					beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
    			/* 循环的放到currentRegistryProcessors */
    			for (String ppName : postProcessorNames) {
    				if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
    					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
    					processedBeans.add(ppName);
    				}
    			}
    			/** 对Processor进行排序,该排序规则对象的设置位置为:
    			 * org.springframework.context.annotation.AnnotationConfigUtils.registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object)
    			 * beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
    			 * 此时currentRegistryProcessors中存放的时spring内置的,registryProcessors本身放置的是我们自定义的,需要将两个给合并起来
    			 */
    			sortPostProcessors(currentRegistryProcessors, beanFactory);
    			/* 将我们手动加入的BeanDefinitionRegistryPostProcessor和spring内置的合并到一起 */
    			registryProcessors.addAll(currentRegistryProcessors);
    			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);				// line1
    			currentRegistryProcessors.clear();/* 清除list */
    
    			................很多代码
    	}
    

    这里重点是看line1,至于上面的代码操作我大概解释一下:

    ​ 首先将我们手动给Spring的BeanFactoryPostProcessor执行,然后哦从容器当中拿实现了BeanDefinitionRegistryPostProcessor(BeanDefinitionRegistryPostProcessor是BeanFactoryPostProcessor的子类,做了一个扩展)接口的实现类(注意此时Spring还未扫描包,所以这里能拿出来的就只有内置的),然后将这些内置的BeanDefinitionRegistryPostProcessor排个序,完了再拿去执行,那么执行就是invokeBeanDefinitionRegistryPostProcessors这行代码。

    5、进入invokeBeanDefinitionRegistryPostProcessors方法

    private static void invokeBeanDefinitionRegistryPostProcessors(
    			Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
    
    		for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
    			postProcessor.postProcessBeanDefinitionRegistry(registry);		// line1
    		}
    	}
    

    这里面的postProcessors是一个数组,因为内置的BeanDefinitionRegistryPostProcessor可能有多个,但当前只一个,名字叫ConfigurationClassPostProcessor,然后我们进入这个类的postProcessBeanDefinitionRegistry方法。

    6、ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry

    @Override
    	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
    		int registryId = System.identityHashCode(registry);
    		if (this.registriesPostProcessed.contains(registryId)) {
    			throw new IllegalStateException(
    					"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
    		}
    		if (this.factoriesPostProcessed.contains(registryId)) {
    			throw new IllegalStateException(
    					"postProcessBeanFactory already called on this post-processor against " + registry);
    		}
    		this.registriesPostProcessed.add(registryId);
    
    		processConfigBeanDefinitions(registry);	// line1
    	}
    

    不关系这些校验,进入到line1当中

    7、进入processConfigBeanDefinitions

    public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
    		List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
    		String[] candidateNames = registry.getBeanDefinitionNames();/*获取所有BeanDefinition中的Bean的名称*/
    		/* 循环所有的类,看是否为配置类,如果是,则需要对这些类进行解析 */
    		for (String beanName : candidateNames) {
    			BeanDefinition beanDef = registry.getBeanDefinition(beanName);/* 循环拿到所有的BeanDefiniton */
    			if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||	/* 判断该类是否已经加载过,如果已经加载过,那么则打一个log */
    					ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
    				/* 说明此类已经加载过,无需再加载 */
    				if (logger.isDebugEnabled()) {
    					logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
    				}
    			}
    			/* 如果没加载过,那么判断此类是否是配置类,如果是则加入到configCandidates中后面会对这些配置类进行解析, */
    			else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {	/*  */
    				configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
    			}
    		}
    
    		// 如果配置类一个都没有,那就没必要继续往下一步走了
    		if (configCandidates.isEmpty()) {
    			return;
    		}
    
    		// Sort by previously determined @Order value, if applicable,对前面解析出来带有Configration相关的集合排序,此排序值取决于该这些类上面放置的@Order注解
    		configCandidates.sort((bd1, bd2) -> {
    			int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
    			int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
    			return Integer.compare(i1, i2);
    		});
    
    		// Detect any custom bean name generation strategy supplied through the enclosing application context,如果我们设置了BeanName生成器,那么则使用我们的,否则就使用Spring内置的
    		SingletonBeanRegistry sbr = null;
    		if (registry instanceof SingletonBeanRegistry) {
    			sbr = (SingletonBeanRegistry) registry;
    			if (!this.localBeanNameGeneratorSet) {
    				BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
    				if (generator != null) {
    					this.componentScanBeanNameGenerator = generator;
    					this.importBeanNameGenerator = generator;
    				}
    			}
    		}
    
    		if (this.environment == null) {
    			this.environment = new StandardEnvironment();
    		}
    
    		// Parse each @Configuration class
    		ConfigurationClassParser parser = new ConfigurationClassParser(
    				this.metadataReaderFactory, this.problemReporter, this.environment,
    				this.resourceLoader, this.componentScanBeanNameGenerator, registry);
    
    		Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
    		Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
    		do {/* 解析这些类 */
    			parser.parse(candidates);
    			parser.validate();
    
    			Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
    			configClasses.removeAll(alreadyParsed);
    
    			// Read the model and create bean definitions based on its content
    			if (this.reader == null) {
    				this.reader = new ConfigurationClassBeanDefinitionReader(
    						registry, this.sourceExtractor, this.resourceLoader, this.environment,
    						this.importBeanNameGenerator, parser.getImportRegistry());
    			}
    			this.reader.loadBeanDefinitions(configClasses);					// line1
    			..............很多代码
    	}
    

    重点看line1,对上面的代码大概描述一下:

    ​ 1、拿到Spring当中当前所有的Bean的名称

    ​ 2、循环遍历这些类

    ​ 2.1、如果当前Bean已经被解析过了,那么不操作,

    ​ 2..2、如果当前Bean未解析,那么判断其是否为配置类,如果是则加入到集合,不是则不操作。

    ​ 判断是否为配置类的依据为:是否加入了@Configuration、是否加入了@Import、@Component、@ImportResource、@ComponentScan其中一个,如果加入了@Configuration那么则不会再去判断后面的

    ​ 3、判断是否存在配置类,不存在则停止

    ​ 4、对配置类进行排序,排序规则为其@Order注解

    ​ 5、获取BeanName生成器,如果没配置则会获取默认的

    ​ 6、创建配置类解析器

    ​ 7、do...while的解析我们的这些类

    ​ 8、parser.parse(candidates);解析这些类,

    ​ 注意这个方法,这里面有我们这次很重要的@Import(这里不解析其他注解例如扫描包,导入xml等),这里面@Import的类我们上面说了三种,除了ImportBeanDefinitionRegistart以外,其他的类都会立即被解析存放Spring到BeanDefinition或调用其ImportSelector的方法,而我们的ImportBeanDefinitionRegistart则会单独的北方知道parser的configutationClasses集合当中。

    ​ 9、到了我们重点的line1当中,这里面对我们上面解析拿到的ImportBeanDefinitionRegistart实现类单独的拿去执行

    8、进入到this.reader.loadBeanDefinitions(configClasses);

    public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
    		TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
    		for (ConfigurationClass configClass : configurationModel) {
    			loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);	// line1
    		}
    	}
    

    同样我们的ImportBeanDefinitionRegistart实现类可能有多个,这里挨个去执行,而我们本次案例中只有一个,为:MyImportBeanDefinitionRegister,这个类存在的地方在ConfigurationClass的importBeanDefinitionRegistrars属性中:

    9、进入到loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);方法中

    private void loadBeanDefinitionsForConfigurationClass(
    			ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
    
    		if (trackedConditionEvaluator.shouldSkip(configClass)) {
    			String beanName = configClass.getBeanName();
    			if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
    				this.registry.removeBeanDefinition(beanName);
    			}
    			this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
    			return;
    		}
    
    		if (configClass.isImported()) {
    			registerBeanDefinitionForImportedConfigurationClass(configClass);
    		}
    		for (BeanMethod beanMethod : configClass.getBeanMethods()) {
    			loadBeanDefinitionsForBeanMethod(beanMethod);
    		}
    
    		loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
    		loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());				// line1
    	}
    

    可以看到line1中就是将我们刚才展示的importBeanDefinitionRegistrars拿出来传给这个方法。

    10、进入到loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());

    private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
    		registrars.forEach((registrar, metadata) ->
    				registrar.registerBeanDefinitions(metadata, this.registry));				/// line1
    	}
    

    这没什么好说的,就是去执行registerBeanDefinitions方法,此时我们看registrar,它就是我们的MyImportBeanDefinitionRegister

    11、进入到registrar.registerBeanDefinitions(metadata, this.registry)

    此时就到了我们自己定义的ImportBeanDefinitionRegistrar中来,注意这里的importingClassMetadata就是我们前面ConfigurationClass的importBeanDefinitionRegistrars属性的值,而后者registry就是Bean工厂。

    本次随笔到此结束,如文有误,深感抱歉,请提出后我改正,感激不尽,

  • 相关阅读:
    如何将已有的本地Git 库推送到远端仓库?
    2017(秋)软工作业: (4)用户体验分析
    微信公众号UX分析—— 学生作业小结
    2017(秋)软工作业: (3)用户体验分析
    珞珈旧时光
    用scp这个命令来通过ssh传输文件
    课堂讨论:分析软件
    2017(秋)软工作业: (2)硬币游戏—— 代码分析与改进
    地铁口的零钱箱:
    Swagger .Net配置
  • 原文地址:https://www.cnblogs.com/daihang2366/p/15080679.html
Copyright © 2020-2023  润新知