处理@Import
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass, Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter, boolean checkForCircularImports) { //importCandidates为@Import中的value数组 for (SourceClass candidate : importCandidates) { if (candidate.isAssignable(ImportSelector.class)) { // Candidate class is an ImportSelector -> delegate to it to determine imports Class<?> candidateClass = candidate.loadClass(); //实例化我们写的实现ImportSelector接口的类 ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class, this.environment, this.resourceLoader, this.registry); //调用selectImports方法返回我们需要注入到容器中bean数组 String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); //转为SourceClass集合 Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter); //再次递归调用本方法,如果我们返回的数组是一些没有实现Import相关接口的类, //就会走到最后的else逻辑,当成配置类处理 processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false); } //这里就走实现ImportBeanDefinitionRegistrar接口的逻辑 else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) { // Candidate class is an ImportBeanDefinitionRegistrar -> // delegate to it to register additional bean definitions Class<?> candidateClass = candidate.loadClass(); //实例化 ImportBeanDefinitionRegistrar registrar = ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class, this.environment, this.resourceLoader, this.registry); //这里先把Registrar放到配置类的importBeanDefinitionRegistrars属性中,最后解析完调用loadBeanDefinition进行处理 configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata()); } else { //普通的bean当做配置类处理 processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter); } } }
处理@Bean
// 将配置类中@Bean的方法解析成方法元数据放到配置类中 Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass); for (MethodMetadata methodMetadata : beanMethods) { configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass)); }
到这里配置类的主要解析流程就已经结束了,接下来回到解析之后的流程
处理@Import导入的beanDefintion和配置类中的@Bean
this.reader.loadBeanDefinitions(configClasses); public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) { TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator(); //循环刚刚解析过的所有配置类 for (ConfigurationClass configClass : configurationModel) { 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; } // 将Import注解引入的class注册到容器的BeanDefinitionMap中 if (configClass.isImported()) { registerBeanDefinitionForImportedConfigurationClass(configClass); } for (BeanMethod beanMethod : configClass.getBeanMethods()) { //将beanMethod转化成BeanDefinition注册到容器的beanDefinitionMap中 loadBeanDefinitionsForBeanMethod(beanMethod); } loadBeanDefinitionsFromImportedResources(configClass.getImportedResources()); //调用在解析Import时放入的ImportBeanDefinitionRegistrar的registerBeanDefinitions方法 loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars()); }
摘取处理BeanMethod逻辑如下
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) { ConfigurationClass configClass = beanMethod.getConfigurationClass(); MethodMetadata metadata = beanMethod.getMetadata(); String methodName = metadata.getMethodName(); //解析出方法上@Bean注解的所有属性值 AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class); //创建一个ConfigurationClassBeanDefinition,标识为通过@Bean注解注册的bean ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata); beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource())); //以下逻辑为拿出@Bean中的属性填充到BeanDefinition中,最后注册容器中 beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR); //解析注解填充属性 AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata); Autowire autowire = bean.getEnum("autowire"); if (autowire.isAutowire()) { beanDef.setAutowireMode(autowire.value()); } boolean autowireCandidate = bean.getBoolean("autowireCandidate"); if (!autowireCandidate) { beanDef.setAutowireCandidate(false); } String initMethodName = bean.getString("initMethod"); if (StringUtils.hasText(initMethodName)) { beanDef.setInitMethodName(initMethodName); } String destroyMethodName = bean.getString("destroyMethod"); beanDef.setDestroyMethodName(destroyMethodName); //将创建的BeanDefinition注册到容器中 this.registry.registerBeanDefinition(beanName, beanDefToRegister); }
以上,ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法大致过程就这些了,接下来回到刚开始的invokeBeanFactoryPostProcessors方法
invokeBeanFactoryPostProcessors
处理实现了Ordered接口的BeanDefinitionRegistryPostProcessor
//...省略之前代码片段 //调用ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法 invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); //清空,以便处理后面的后置处理器 currentRegistryProcessors.clear(); //再次查找实现了BeanDefinitionRegistryPostProcessor接口的BeanName,这里就是从配置类中解析出来的一些 postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); for (String ppName : postProcessorNames) { //不包括已经处理过的,并且先处理实现Ordered接口的 if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) { currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); } } //根据Ordered排序 sortPostProcessors(currentRegistryProcessors, beanFactory); //将后置处理器放到已注册的集合中 registryProcessors.addAll(currentRegistryProcessors); //调用所有后置处理器的postProcessBeanDefinitionRegistry方法 invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); //再次清理,因为后面还要处理未实现Ordered接口的 currentRegistryProcessors.clear();
最后需要循环处理剩下的所有后置处理器,因为可能从剩下的后置处理器中又解析出新的后置处理器
//下面的逻辑和上面的一模一样,while循环处理所有剩下的后置处理器,直到全部处理完毕 boolean reiterate = true; while (reiterate) { reiterate = false; postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); for (String ppName : postProcessorNames) { if (!processedBeans.contains(ppName)) { currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); reiterate = true; } } sortPostProcessors(currentRegistryProcessors, beanFactory); registryProcessors.addAll(currentRegistryProcessors); invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); currentRegistryProcessors.clear(); }
调用所有后置处理器的postProcessBeanFactory方法
/** * 调用所有后置处理器的postProcessBeanFactory方法, * 如果自己没实现的话,Spring中只有一个内置的ConfigurationClassPostProcessor * ConfigurationClassPostProcessor中的postProcessBeanFactory方法主要是将配置类换成动态代理 */ invokeBeanFactoryPostProcessors(registryProcessors, beanFactory); invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
ConfigurationClassPostProcessor#postProcessBeanFactory
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { //将所有配置类进行动态代理,这样@Bean中依赖其他的Bean就可以从容器中拿bean了 /** * example: * @Bean * public Car car(){ * return new Car(wheel()); * } * @Bean * public Wheel wheel(){ * return new Wheel(); * } * 如果配置类不换成动态代理的话,每次从容器中拿car都将new一个wheel * 注意,这里只有full类型的配置类才会生成代理类,lite类型的不会, * 所以lite类型的配置类每次获取car都会生成一个wheel */ enhanceConfigurationClasses(beanFactory); //添加一个beanPostProcessor beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory)); }
最后处理实现了BeanFactoryPostProcessor接口的后置处理器
//处理方式与BeanDefinitionRegistryPostProcessor相同 //找出所有实现了BeanDefinitionRegistryPostProcessor的后置处理器 String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false); //先处理实现PriorityOrdered接口的 invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory); //在处理实现Ordered接口的 invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory); //最后处理普通的 invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
到这里,关于
BeanFactoryPostProcessor
调用过程就已经完结了
关于BeanDefinition
的小彩蛋
解析配置类的流程我们已经分析完了,那么在这过程中用了多少种BeanDefinition
呢?他们对应的类型又是什么呢?这里附上本文的一个小彩蛋。
AnnotatedGenericBeanDefinition
:在开始传入的配置类,以及通过@Import注解引入的BeanScannedGenericBeanDefinition
:通过@Component扫描包引入的BeanConfigurationClassBeanDefinition
:通过@Bean注解引入的BeanRootBeanDefinition
:Spring内部使用,如生产Bean时将其他BeanDefinition
转成RootBeanDefinition
Mybatis 如何整合 Spring的?
此节知识为概要知识,具体内容将放在Mybatis源码系列详细说明
先带大家理理思路~
我们知道,在Spring中是可以通过扫描的方式扫描出标识了@Component
注解的class注册到容器中,并且该class不能为一个接口类(忘了请看上面的扫描逻辑),而我们的mapper
通常又是一个接口类,这是默认不允许被注册的。那么该如何解决这个问题呢?
思考:既然默认不允许是接口类,那么我们是否可以自定义一个扫码器继承Spring的扫描器,然后重写其中判断是否为接口类的逻辑,这样,我们不就可以使用我们自定义的扫描器去扫描包就可以了吗?
问题2:假设上面的方法可行,但是我们扫描出来的BeanDefintion
是个接口,接口是不能被实例化的,那在后面我们createBean
中的实例化步骤又该如何解决呢?
思考:我们知道其实我们的mapper
在mybatis
中本来就是个接口,我们创建时是通过sqlSessionTemplate.getMapper()
的方式创建的,这里其实是生成了一个代理类返回给我们,那我们应该如何将这个代理类给接到Spring的createBean
过程中呢,如何接过去了岂不是就万事大吉?
小知识:嘿,不知道大家还记不记的我们的bean
里有一种特殊的bean
称为FactoryBean
,我们这个FactoryBean
最后从容器中获取出来时其实是先拿到这个FactoryBean
,然后调用它的getObject()
方法返回我们真正需要的bean
思考:知道这个之后,那么我们是不是可以使用FactoryBean
,然后将扫描出来的接口(mapper)放到FactoryBean
的属性中,最后从容器中获取时只要这样:
public class FactoryBean{ private Class mapper; public Object getObject(){ sqlSessionTemplate.getMappper(mapper); } }
嘿,看看是不是好像搞定啦~
现在问题好像都已经解决了,那剩下的就是怎么让Spring在启动的时候调用我们的自定义扫描器呢?我们现在就来看看源码吧
@MapperScan
Mybatis
整合Spring
当然是从@MapperScan
注解看起,因为我们通常情况只加这个注解就可以了
@MapperScan简要内容如下
// 组合注解,组合了@Import注解,再通过@Import注解导入了MapperScannerRegistrar类 @Import(MapperScannerRegistrar.class) public @interface MapperScan{ // 包路径 String[] basePackages() default {} }
MapperScannerRegistrar
// 实现的是ImportBeanDefinitionRegistrar接口 public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware{ }
registerBeanDefinitions
@Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { // 从元数据中拿到@MapperScan的信息 AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName())); // 实例化一个自定义的扫描器 ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry); // 下面都是些属性填充,由于一般我们只配一个包路径,所以下面除了包路径,其他都是null if (resourceLoader != null) { scanner.setResourceLoader(resourceLoader); } Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass"); if (!Annotation.class.equals(annotationClass)) { scanner.setAnnotationClass(annotationClass); } Class<?> markerInterface = annoAttrs.getClass("markerInterface"); if (!Class.class.equals(markerInterface)) { scanner.setMarkerInterface(markerInterface); } Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator"); if (!BeanNameGenerator.class.equals(generatorClass)) { scanner.setBeanNameGenerator(BeanUtils.instantiateClass(generatorClass)); } Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean"); if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) { scanner.setMapperFactoryBean(BeanUtils.instantiateClass(mapperFactoryBeanClass)); } scanner.setSqlSessionTemplateBeanName(annoAttrs.getString("sqlSessionTemplateRef")); scanner.setSqlSessionFactoryBeanName(annoAttrs.getString("sqlSessionFactoryRef")); List<String> basePackages = new ArrayList<String>(); for (String pkg : annoAttrs.getStringArray("value")) { if (StringUtils.hasText(pkg)) { basePackages.add(pkg); } } for (String pkg : annoAttrs.getStringArray("basePackages")) { if (StringUtils.hasText(pkg)) { basePackages.add(pkg); } } for (Class<?> clazz : annoAttrs.getClassArray("basePackageClasses")) { basePackages.add(ClassUtils.getPackageName(clazz)); } // 注册自定义的过滤器,我们啥也没配,所以扫描出来的所以接口都通过 scanner.registerFilters(); // 开始扫描 scanner.doScan(StringUtils.toStringArray(basePackages)); }
scanner.registerFilters中的有效片段
// 添加一个直接返回true的过滤器 addIncludeFilter(new TypeFilter() { @Override public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { return true; } });
doScan
public Set<BeanDefinitionHolder> doScan(String... basePackages) { // 直接走的就是Spring的扫描逻辑了,但现在过滤器只有一个默认全放行的 Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages); if (beanDefinitions.isEmpty()) { logger.warn("No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration."); } else { // 处理扫描出来的BeanDefinition,这里就是我们思考中搞成`FactoryBean`的逻辑 processBeanDefinitions(beanDefinitions); } return beanDefinitions; }
我们思考中重写的扫描逻辑
@Override protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) { // 放行是接口的类 return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent(); }
摘取processBeanDefinitions中的代码片段
private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) { GenericBeanDefinition definition; for (BeanDefinitionHolder holder : beanDefinitions) { definition = (GenericBeanDefinition) holder.getBeanDefinition(); // 将原来的接口mapper放到beanDefintion的构造方法参数中,以指定的构造方法实例化 definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName()); // 注意这里:将原来的beanClass替换成FactoryBean了! definition.setBeanClass(this.mapperFactoryBean.getClass()); } }
Mybatis整合Spring的过程大致就是这些了
本文内容就是以上这些了,希望小伙伴们有所收获,有问题的小伙伴欢迎在下方留言哦