Mybatis源码学习(五)整合Spring原理

思路:

1使用Spring中的组件扫描,扫描所有Mapper注入到Spring容器中

2 mybatis中的SqlSessionFactory注入到spring容器
3 mybatis执行blogMapper.query时,使用动态代理,注入blogMapper时需要处理BeanDefinition时,name为blogMapper,实体类应该对应代理类

 

 

 

App.java

@ComponentScan("szjspringdemo")
@Import(SzjImportBeanDefinitionRegistrar.class)
public class App 
{

    @Bean
    public SqlSessionFactory sqlSessionFactory() throws IOException{
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        return sqlSessionFactory;
    }

    public static void main( String[] args )
    {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(App.class);
        applicationContext.refresh();
        
        SzjService szjService = applicationContext.getBean("szjService", SzjService.class);
        szjService.test();
    }
}

 

SzjService.java

@Component
public class SzjService {
    @Autowired
    private BlogMapper blogMapper;

    public void test(){
        System.out.println(blogMapper.query(101).getUsername());
    }
}

 

Blog.java

public class Blog {
    private Integer id;
    private String username;
    private String context;
}

 

BlogMapper.java

public interface BlogMapper {
  @Select("select * from blog where id=#{id}")
  Blog query(Integer id);
}

 

SzjFactoryBean.java

public class SzjFactoryBean implements FactoryBean {
    private Class mapperClass;
    private SqlSession sqlSession;

    public SzjFactoryBean(Class mapperClass){
        this.mapperClass = mapperClass;
    }

    @Autowired
    public void setSqlSession(SqlSessionFactory sqlSessionFactory){
        sqlSessionFactory.getConfiguration().addMapper(mapperClass);
        this.sqlSession = sqlSessionFactory.openSession();
    }

    @Override
    public Object getObject() throws Exception {
        return sqlSession.getMapper(mapperClass);
    }

    @Override
    public Class<?> getObjectType() {
        return mapperClass;
    }
}

 

SzjImportBeanDefinitionRegistrar.java

public class SzjImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        //扫描,1扫描路径 2扫描
        String path = "szjspringdemo.mapper";

        SzjScanner szjScanner = new SzjScanner(registry);
        szjScanner.addIncludeFilter(new TypeFilter() {
            @Override
            public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
                return true;
            }
        });
        szjScanner.scan(path);
    }
}

 

SzjScanner.java

public class SzjScanner extends ClassPathBeanDefinitionScanner {

    public SzjScanner(BeanDefinitionRegistry registry){
        super(registry);
    }

    @Override
    public int scan(String... basePackages) {
        int i = super.scan(basePackages);//走spring的扫描逻辑
        System.out.println(i);
        return i;
    }

    @Override
    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Set<BeanDefinitionHolder> beanDefinitionHolders = super.doScan(basePackages);

        for(BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders)
        {
            BeanDefinition beanDefinition = beanDefinitionHolder.getBeanDefinition();
            beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(beanDefinition.getBeanClassName());
            beanDefinition.setBeanClassName(SzjFactoryBean.class.getName());
        }

        System.out.println(beanDefinitionHolders);
        return beanDefinitionHolders;
    }

    @Override
    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
        return beanDefinition.getMetadata().isInterface();
    }
}

 mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <properties resource="jdbc.properties"/>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
</configuration>

jdbc.properties

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://192.168.*.*:3306/devdb?serverTimezone=UTC
username=***
password=***

 

 

分析

@ComponentScan("szjspringdemo")
@Import(SzjImportBeanDefinitionRegistrar.class)
public class App 
{
    @Bean
    public SqlSessionFactory sqlSessionFactory() throws IOException{
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        return sqlSessionFactory;
    }

    public static void main(String[] args )
    {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(App.class);
        applicationContext.refresh();

        SzjService szjService = applicationContext.getBean("szjService", SzjService.class);
        szjService.test();
    }
}

先看main方法,首先创建一个spring容器。

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();

这个容器的构造器中初始化scanner和reader

    public AnnotationConfigApplicationContext() {
        this.reader = new AnnotatedBeanDefinitionReader(this);
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }

然后回到main方法,注册App类,把App类注入到beanFactory的beanDefinitionMap中

applicationContext.register(App.class);

 

 

然后,refresh

applicationContext.refresh();

执行AbstractApplicationContext中的refresh方法

    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            prepareRefresh();
            // Tell the subclass to refresh the internal bean factory.
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
            // Prepare the bean factory for use in this context.
            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);
                // Register bean processors that intercept bean creation.
                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();
            }

        }
    }

执行如下方法

invokeBeanFactoryPostProcessors(beanFactory);
    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;
            List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
            List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

            // 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> currentRegistryProcessors = new ArrayList<>();

            // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
            String[] postProcessorNames =
                    beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
            for (String ppName : postProcessorNames) {
                if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                    currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                    processedBeans.add(ppName);
                }
            }
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);

            // Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
            ...

            // Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
            
    }

经过几次调用,到达ConfigurationClassPostProcessor.processConfigBeanDefinitions()

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
        List<BeanDefinitionHolder> configCandidates = new ArrayList<>();

        for (String beanName : candidateNames) {
            BeanDefinition beanDef = registry.getBeanDefinition(beanName);
             if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
                configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
            }
        }

        Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
        do {
            parser.parse(candidates);
            parser.validate();
       Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
       this.reader.loadBeanDefinitions(configClasses);
} while (!candidates.isEmpty()); } }

 

ConfigurationClassUtils的checkConfigurationClassCandidate方法,这里判断是fullConfig还是LiteConfig。如果以注解@Component,@ComponentScan,@Import,@ImportResource标注,则是LiteConfig。

然后执行

parser.parse(candidates);

经过几步调用执行ConfigurationClassParser.doProcessConfigurationClass()。在这里处理@ComponentScan、@Import、@Bean注解。

    protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
            throws IOException {
        // Process any @ComponentScan annotations
        Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
                sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
        if (!componentScans.isEmpty() &&
                !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
            for (AnnotationAttributes componentScan : componentScans) {
                // The config class is annotated with @ComponentScan -> perform the scan immediately
                Set<BeanDefinitionHolder> scannedBeanDefinitions =
                        this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
                // Check the set of scanned definitions for any further config classes and parse recursively if needed
                for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
                    BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
                    if (bdCand == null) {
                        bdCand = holder.getBeanDefinition();
                    }
                    if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
                        parse(bdCand.getBeanClassName(), holder.getBeanName());
                    }
                }
            }
        }

        // Process any @Import annotations
        processImports(configClass, sourceClass, getImports(sourceClass), true);

        // Process individual @Bean methods
        Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
        for (MethodMetadata methodMetadata : beanMethods) {
            configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
        }
    }

 

我们再回到 this.reader.loadBeanDefinitions(configClasses); 这里将@Import和@Bean注解标注的类注册到beanFactory的beanDefinitionMap中

以上总结大篇幅其实是讲spring容器初始化的过程,对于整合mybatis的精髓好像还没找到。

posted @ 2022-01-11 23:54  zhenjingcool  阅读(34)  评论(0编辑  收藏  举报