最后处理实现了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注解引入的Bean
ScannedGenericBeanDefinition:通过@Component扫描包引入的Bean
ConfigurationClassBeanDefinition:通过@Bean注解引入的Bean
RootBeanDefinition: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在启动的时候调用我们的自定义扫描器呢?我们现在就来看看源码吧
@MapperScanMybatis整合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)); }