成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Spring-Mybatis運(yùn)行機(jī)制概括

qieangel2013 / 749人閱讀

摘要:使用這個(gè)類庫(kù)中的類將會(huì)加載必要的工廠類和類。最終它并不會(huì)依賴于或來(lái)構(gòu)建應(yīng)用程序代碼。下面對(duì)各部分作用總結(jié)下。和無(wú)縫整合的機(jī)制和的認(rèn)識(shí)在講如何無(wú)縫整合進(jìn)之前,我們先認(rèn)識(shí)下和這兩個(gè)接口的作用。附上上篇博文地址原理概括。

前言

本篇是繼上篇MyBatis原理概括延伸的,所以如果有小伙伴還沒(méi)看上篇博文的話,可以先去看下,也不會(huì)浪費(fèi)大家太多的時(shí)間,因?yàn)楸酒獣?huì)結(jié)合到上篇敘述的相關(guān)內(nèi)容。

好,切入正題,這篇主要講一個(gè)點(diǎn),就是我們?cè)?strong>結(jié)合spring去使用mybatis的時(shí)候,spring為我們做了什么事。還是老套路,我們只講過(guò)程思路,具體細(xì)節(jié)還望各位小伙伴找時(shí)間去研究,如果我全講了,你們也都看懂了,那你們最多也就是感到一種獲得感,而不是成就感,獲得感是會(huì)隨著時(shí)間的推移而慢慢減少的,所以我這里主要提供給大家一個(gè)思路,然后大家可以順著這條思路慢慢摸索下去,從而獲得成就感!

使用spring-mybatis 1.spring-mybatis是什么

MyBatis-Spring 會(huì)幫助你將 MyBatis 代碼無(wú)縫地整合到 Spring 中。 使用這個(gè)類庫(kù)中的類, Spring 將會(huì)加載必要的 MyBatis 工廠類和 session 類。 這個(gè)類庫(kù)也提供一個(gè)簡(jiǎn)單的方式來(lái)注入 MyBatis 數(shù)據(jù)映射器和 SqlSession 到業(yè)務(wù)層的 bean 中。 而且它也會(huì)處理事務(wù), 翻譯 MyBatis 的異常到 Spring 的 DataAccessException 異常(數(shù)據(jù)訪問(wèn)異常,譯者注)中。最終,它并 不會(huì)依賴于 MyBatis,Spring 或 MyBatis-Spring 來(lái)構(gòu)建應(yīng)用程序代碼。(這是官網(wǎng)解釋)

2.基于XML配置和注解形式使用 a.基于XML配置

一般情況下,我們使用xml的形式引入mybatis,一般的配置如下:


    
    
    
    
     
     
     
     
     
     
     
     
     
     




    
     
     


 
 
     
     

如上配置所示,我們一般需要申明dataSource、sqlSessionFactory以及MapperScannerConfigurer。如何我們還有其他mybatis的配置,比如plugin、typehandler等,我們可以另外申明一個(gè)mybaits-config.xml文件,在sqlSessionFactory配置中引入即可。下面對(duì)各部分作用總結(jié)下。
dataSource:申明一個(gè)數(shù)據(jù)源;
sqlSessionFactory:申明一個(gè)sqlSession的工廠;
MapperScannerConfigurer:讓spring自動(dòng)掃描我們持久層的接口從而自動(dòng)構(gòu)建代理類。

b.基于注解形式

注解形式的話相當(dāng)于將上述的xml配置一一對(duì)應(yīng)成注解的形式

@Configuration  
@MapperScan(value="org.fhp.springmybatis.dao")  
public class DaoConfig {
  
    @Value("${jdbc.driverClass}")  
    private String driverClass;  
  
    @Value("${jdbc.user}")  
    private String user;  
  
    @Value("${jdbc.password}")  
    private String password;  
  
    @Value("${jdbc.jdbcUrl}")  
    private String jdbcUrl;  
  
    @Bean  
    public DataSource dataSource() {  
        DriverManagerDataSource dataSource = new DriverManagerDataSource();  
        dataSource.setDriverClassName(driverClass);  
        dataSource.setUsername(user);  
        dataSource.setPassword(password);  
        dataSource.setUrl(jdbcUrl);  
        return dataSource;  
    }  
  
    @Bean  
    public DataSourceTransactionManager transactionManager() {  
        return new DataSourceTransactionManager(dataSource());  
    }  
  
    @Bean  
    public SqlSessionFactory sqlSessionFactory() throws Exception {  
        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();  
        sessionFactory.setDataSource(dataSource());  
        return sessionFactory.getObject();  
    }  
}  

很明顯,一樣需要一個(gè)dataSource,SqlSessionFactory以及一個(gè)@MapperScan的注解。這個(gè)注解的作用跟上述的
MapperScannerConfigurer的作用是一樣的。

3.spring和mybatis無(wú)縫整合的機(jī)制 a.BeanDefinitionRegistryPostProcessor和ImportBeanDefinitionRegistrar的認(rèn)識(shí)

在講mybatis如何無(wú)縫整合進(jìn)spring之前,我們先認(rèn)識(shí)下BeanDefinitionRegistryPostProcessor和ImportBeanDefinitionRegistrar這兩個(gè)接口的作用。

我們先看下這兩個(gè)接口是什么樣的。

//BeanDefinitionRegistryPostProcessor接口
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
    void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry var1) throws BeansException;
}

//ImportBeanDefinitionRegistrar接口
public interface ImportBeanDefinitionRegistrar {
    void registerBeanDefinitions(AnnotationMetadata var1, BeanDefinitionRegistry var2);
}

對(duì)于這兩個(gè)接口我們先看官方文檔給我們的解釋。

以下是BeanDefinitionRegistryPostProcessor的解釋:

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor

Extension to the standard BeanFactoryPostProcessor SPI, allowing for the registration of further bean definitions before regular BeanFactoryPostProcessor detection kicks in. In particular, BeanDefinitionRegistryPostProcessor may register further bean definitions which in turn define BeanFactoryPostProcessor instances.

意思大概就是我們可以擴(kuò)展spring對(duì)于bean definitions的定義。也就是說(shuō)可以讓我們實(shí)現(xiàn)自定義的注冊(cè)bean定義的邏輯。
再來(lái)看下ImportBeanDefinitionRegistrar的解釋:

public interface ImportBeanDefinitionRegistrar Interface to be implemented by types that register additional bean definitions when processing @Configuration classes. Useful when operating at the bean definition level (as opposed to @Bean method/instance level) is desired or necessary.

Along with @Configuration and ImportSelector, classes of this type may be provided to the @Import annotation (or may also be returned from an ImportSelector).

通俗解釋來(lái)講就是在@Configuration上使用@Import時(shí)可以自定義beanDefinition,或者作為ImportSelector接口的返回值(有興趣的小伙伴可以自行研究)。

所以總結(jié)下就是如果我想擴(kuò)展beanDefinition那么我可以繼承這兩個(gè)接口實(shí)現(xiàn)。下面我們就從mybatis配置方式入手講講spring和mybatis是如何無(wú)縫整合的。

b.基于XML配置mybatis是如何整合進(jìn)spring的

首先,容器啟動(dòng)的時(shí)候,我們?cè)趚ml配置中的SqlSessionFactoryBean會(huì)被初始化,所以我們先看下SqlSessionFactoryBean是在初始化的時(shí)候作了哪些工作。

public class SqlSessionFactoryBean implements FactoryBean, InitializingBean, ApplicationListener {
    private static final Log LOGGER = LogFactory.getLog(SqlSessionFactoryBean.class);
    private Resource configLocation;
    private Configuration configuration;
    private Resource[] mapperLocations;
    private DataSource dataSource;
    private TransactionFactory transactionFactory;
    private Properties configurationProperties;
    private SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
    private SqlSessionFactory sqlSessionFactory;
    private String environment = SqlSessionFactoryBean.class.getSimpleName();
    private boolean failFast;
    private Interceptor[] plugins;
    private TypeHandler[] typeHandlers;
    private String typeHandlersPackage;
    private Class[] typeAliases;
    private String typeAliasesPackage;
    private Class typeAliasesSuperType;
    private DatabaseIdProvider databaseIdProvider;
    private Class vfs;
    private Cache cache;
    private ObjectFactory objectFactory;
    private ObjectWrapperFactory objectWrapperFactory;

    public SqlSessionFactoryBean() {
    }
    ...
}

我們可以看到這個(gè)類實(shí)現(xiàn)了FactoryBean、InitializingBean和ApplicationListener接口,對(duì)應(yīng)的接口在bean初始化的時(shí)候?yàn)閳?zhí)行些特定的方法(如果不清楚的小伙伴請(qǐng)自行百度,這里不作過(guò)多敘述)。現(xiàn)在我們來(lái)看看都有哪些方法會(huì)被執(zhí)行,這些方法又作了哪些工作。

//FactoryBean
public SqlSessionFactory getObject() throws Exception {
    if (this.sqlSessionFactory == null) {
        this.afterPropertiesSet();
    }

    return this.sqlSessionFactory;
}

//InitializingBean
public void afterPropertiesSet() throws Exception {
    Assert.notNull(this.dataSource, "Property "dataSource" is required");
    Assert.notNull(this.sqlSessionFactoryBuilder, "Property "sqlSessionFactoryBuilder" is required");
    Assert.state(this.configuration == null && this.configLocation == null || this.configuration == null || this.configLocation == null, "Property "configuration" and "configLocation" can not specified with together");
    this.sqlSessionFactory = this.buildSqlSessionFactory();
}

//ApplicationListener
public void onApplicationEvent(ApplicationEvent event) {
    if (this.failFast && event instanceof ContextRefreshedEvent) {
        this.sqlSessionFactory.getConfiguration().getMappedStatementNames();
    }

}

通過(guò)觀察代碼我們可以知道前面兩個(gè)都是在做同一件事情,那就是在構(gòu)建sqlSessionFactory,在構(gòu)建sqlSessionFactory時(shí)mybatis會(huì)去解析配置文件,構(gòu)建configuation。后面的onApplicationEvent主要是監(jiān)聽(tīng)?wèi)?yīng)用事件時(shí)做的一些事情(不詳講,有興趣的同學(xué)可以自己去了解下)。

其次,我們回憶下我們?cè)趚ml配置中還配置了MapperScannerConfigurer,或者也可以配置多個(gè)的MapperFactoryBean,道理都是一樣的,只是MapperScannerConfigurer幫我們封裝了這一個(gè)過(guò)程,可以實(shí)現(xiàn)自動(dòng)掃描指定包下的mapper接口構(gòu)建MapperFactoryBean。

問(wèn)題1:為什么我們從spring容器中能直接獲取對(duì)應(yīng)mapper接口的實(shí)現(xiàn)類?而不用使用sqlSession去getMapper呢?
答案其實(shí)在上面就已經(jīng)為大家解答了,就是MapperFactoryBean。我們先看看這個(gè)類。

public class MapperFactoryBean extends SqlSessionDaoSupport implements FactoryBean {
    private Class mapperInterface;
    private boolean addToConfig = true;

    public MapperFactoryBean() {
    }

    public MapperFactoryBean(Class mapperInterface) {
        this.mapperInterface = mapperInterface;
    }
    ...
}

這個(gè)類繼承了SqlSessionDaoSupport,實(shí)現(xiàn)了FactoryBean。
我們先講講SqlSessionDaoSupport這個(gè)類

public abstract class SqlSessionDaoSupport extends DaoSupport {
    private SqlSession sqlSession;
    private boolean externalSqlSession;

    public SqlSessionDaoSupport() {
    }

    public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
        if (!this.externalSqlSession) {
            this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);
        }

    }

    public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
        this.sqlSession = sqlSessionTemplate;
        this.externalSqlSession = true;
    }

    public SqlSession getSqlSession() {
        return this.sqlSession;
    }

    protected void checkDaoConfig() {
        Assert.notNull(this.sqlSession, "Property "sqlSessionFactory" or "sqlSessionTemplate" are required");
    }
}

可以看到這個(gè)類繼承了DaoSupport,我們?cè)賮?lái)看下這個(gè)類。

public abstract class DaoSupport implements InitializingBean {
    protected final Log logger = LogFactory.getLog(this.getClass());

    public DaoSupport() {
    }

    public final void afterPropertiesSet() throws IllegalArgumentException, BeanInitializationException {
        this.checkDaoConfig();

        try {
            this.initDao();
        } catch (Exception var2) {
            throw new BeanInitializationException("Initialization of DAO failed", var2);
        }
    }

    protected abstract void checkDaoConfig() throws IllegalArgumentException;

    protected void initDao() throws Exception {
    }
}

可以看到實(shí)現(xiàn)了InitializingBean接口,所以在類初始化時(shí)為執(zhí)行afterPropertiesSet方法,我們看到afterPropertiesSet方法里面有checkDaoConfig方法和initDao方法,其中initDao是模板方法,提供子類自行實(shí)現(xiàn)相關(guān)dao初始化的操作,我們看下checkDaoConfig方法作了什么事。

//MapperFactoryBean
protected void checkDaoConfig() {
    super.checkDaoConfig();
    Assert.notNull(this.mapperInterface, "Property "mapperInterface" is required");
    Configuration configuration = this.getSqlSession().getConfiguration();
    if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
        try {
            configuration.addMapper(this.mapperInterface);
        } catch (Exception var6) {
            this.logger.error("Error while adding the mapper "" + this.mapperInterface + "" to configuration.", var6);
            throw new IllegalArgumentException(var6);
        } finally {
            ErrorContext.instance().reset();
        }
    }

}

這個(gè)方法具體的實(shí)現(xiàn)是在MapperFactoryBean類里面的,主要作用就是對(duì)驗(yàn)證mapperInterface是否存在configuration對(duì)象里面。

然后我們?cè)賮?lái)看下MapperFactoryBean實(shí)現(xiàn)了FactoryBean的目的是什么。我們都知道FactoryBean有一個(gè)方法是getObject,這個(gè)方法的作用就是在spring容器初始化bean時(shí),如果判斷這個(gè)類是否繼承自FactoryBean,那么在獲取真正的bean實(shí)例時(shí)會(huì)調(diào)用getObject,將getObject方法返回的值注冊(cè)到spring容器中。在明白了這些知識(shí)點(diǎn)之后,我們看下MapperFactoryBean的getObject方法是如何實(shí)現(xiàn)的。

//MapperFactoryBean
public T getObject() throws Exception {
    return this.getSqlSession().getMapper(this.mapperInterface);
}

看到這里是否就已經(jīng)明白為什么在結(jié)合spring時(shí)我們不需要使用sqlSession對(duì)象去獲取我們的mapper實(shí)現(xiàn)類了吧。因?yàn)閟pring幫我們作了封裝!
之后的操作可以結(jié)合上面博文去看mybatis如何獲取到對(duì)應(yīng)的Mapper對(duì)象的了。附上上篇博文地址:MyBatis原理概括。

接下來(lái)我們看下mybatis是如何結(jié)合spring構(gòu)建MapperFactoryBean的beanDefinition的。這里我們需要看看MapperScannerConfigurer這個(gè)類,這個(gè)類的目的就是掃描我們指定的dao層(持久層)對(duì)應(yīng)的包(package),構(gòu)建相應(yīng)的beanDefinition提供給spring容器去實(shí)例化我們的mapper接口對(duì)象。

//MapperScannerConfigurer
public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {
    private String basePackage;
    private boolean addToConfig = true;
    private SqlSessionFactory sqlSessionFactory;
    private SqlSessionTemplate sqlSessionTemplate;
    private String sqlSessionFactoryBeanName;
    private String sqlSessionTemplateBeanName;
    private Class annotationClass;
    private Class markerInterface;
    private ApplicationContext applicationContext;
    private String beanName;
    private boolean processPropertyPlaceHolders;
    private BeanNameGenerator nameGenerator;

    public MapperScannerConfigurer() {
    }
    ...
}

通過(guò)代碼,我們可以看到這個(gè)類實(shí)現(xiàn)了BeanDefinitionRegistryPostProcessor這個(gè)接口,通過(guò)前面對(duì)BeanDefinitionRegistryPostProcessor的講解,我們?nèi)タ纯碝apperScannerConfigurer中的postProcessBeanDefinitionRegistry方法的實(shí)現(xiàn)。

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
    if (this.processPropertyPlaceHolders) {
        this.processPropertyPlaceHolders();
    }

    ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
    scanner.setAddToConfig(this.addToConfig);
    scanner.setAnnotationClass(this.annotationClass);
    scanner.setMarkerInterface(this.markerInterface);
    scanner.setSqlSessionFactory(this.sqlSessionFactory);
    scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
    scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
    scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
    scanner.setResourceLoader(this.applicationContext);
    scanner.setBeanNameGenerator(this.nameGenerator);
    scanner.registerFilters();
    scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ",; 	
"));
}

可以看這里就是在構(gòu)建ClassPathMapperScanner對(duì)象,然后調(diào)用scan方法掃描。接下來(lái)我們繼續(xù)看這個(gè)掃描的操作,因?yàn)檫@個(gè)類繼承了ClassPathBeanDefinitionScanner,調(diào)用的scan方法是在ClassPathBeanDefinitionScanner里申明的。

//ClassPathBeanDefinitionScanner
public int scan(String... basePackages) {
    int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
    this.doScan(basePackages);
    if (this.includeAnnotationConfig) {
        AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
    }

    return this.registry.getBeanDefinitionCount() - beanCountAtScanStart;
}

這里我們需要注意doScan這個(gè)方法,這個(gè)方法在ClassPathMapperScanner中重寫了。

//ClassPathMapperScanner
public Set doScan(String... basePackages) {
    Set beanDefinitions = super.doScan(basePackages);
    if (beanDefinitions.isEmpty()) {
        this.logger.warn("No MyBatis mapper was found in "" + Arrays.toString(basePackages) + "" package. Please check your configuration.");
    } else {
        this.processBeanDefinitions(beanDefinitions);
    }

    return beanDefinitions;
}

這里調(diào)用了父類的doScan得到beanDefinitions的集合。這里的父類的doScan方法是spring提供的包掃描操作,這里不過(guò)多敘述,感興趣的小伙伴可以自行研究。我們還注意到在得到beanDefinitions集合后,這里還調(diào)用了processBeanDefinitions方法,這里是對(duì)beanDefinition做了一些特殊的處理以滿足mybaits的需求。我們先來(lái)看下這個(gè)方法。

//ClassPathMapperScanner#doScan
private void processBeanDefinitions(Set beanDefinitions) {
    Iterator var3 = beanDefinitions.iterator();

    while(var3.hasNext()) {
        BeanDefinitionHolder holder = (BeanDefinitionHolder)var3.next();
        GenericBeanDefinition definition = (GenericBeanDefinition)holder.getBeanDefinition();
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Creating MapperFactoryBean with name "" + holder.getBeanName() + "" and "" + definition.getBeanClassName() + "" mapperInterface");
        }

        definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName());
        definition.setBeanClass(this.mapperFactoryBean.getClass());
        definition.getPropertyValues().add("addToConfig", this.addToConfig);
        boolean explicitFactoryUsed = false;
        if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {
            definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName));
            explicitFactoryUsed = true;
        } else if (this.sqlSessionFactory != null) {
            definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory);
            explicitFactoryUsed = true;
        }

        if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) {
            if (explicitFactoryUsed) {
                this.logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
            }

            definition.getPropertyValues().add("sqlSessionTemplate", new RuntimeBeanReference(this.sqlSessionTemplateBeanName));
            explicitFactoryUsed = true;
        } else if (this.sqlSessionTemplate != null) {
            if (explicitFactoryUsed) {
                this.logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
            }

            definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);
            explicitFactoryUsed = true;
        }

        if (!explicitFactoryUsed) {
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Enabling autowire by type for MapperFactoryBean with name "" + holder.getBeanName() + "".");
            }

            definition.setAutowireMode(2);
        }
    }

}

這里我們注意到有這么一行代碼:definition.setBeanClass(this.mapperFactoryBean.getClass()),看到這里我們就可以知道為什么spring在加載初始化我們的mapper接口對(duì)象會(huì)初始化成MapperFactoryBean對(duì)象了

好了,到這里我們也就明白了spring是如何幫我們加載注冊(cè)我們的mapper接口對(duì)應(yīng)的實(shí)現(xiàn)類了。對(duì)于代碼里涉及到的其他細(xì)節(jié),這里暫時(shí)不作過(guò)多講解,還是老套路,只講解總體思路。

c.基于注解配置mybatis是如何整合進(jìn)spring的

基于注解形式的配置其實(shí)就是將xml配置對(duì)應(yīng)到注解中來(lái),本質(zhì)上的流程還是一樣的。所以這里我就簡(jiǎn)單講講。我們先看看MapperScannerRegistrar這個(gè)類,因?yàn)檫@個(gè)類是spring構(gòu)建MapperFactoryBean的核心類。

//MapperScannerRegistrar
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
    private ResourceLoader resourceLoader;

    public MapperScannerRegistrar() {
    }
    ...
}

這里我們注意到MapperScannerRegistrar實(shí)現(xiàn)了ImportBeanDefinitionRegistrar接口,在前面的敘述中我們已經(jīng)知道了實(shí)現(xiàn)ImportBeanDefinitionRegistrar接口的作用是什么了,所以我們直接看看這里具體做了什么操作。

public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
    ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
    if (this.resourceLoader != null) {
        scanner.setResourceLoader(this.resourceLoader);
    }

    Class 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 generatorClass = annoAttrs.getClass("nameGenerator");
    if (!BeanNameGenerator.class.equals(generatorClass)) {
        scanner.setBeanNameGenerator((BeanNameGenerator)BeanUtils.instantiateClass(generatorClass));
    }

    Class mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
    if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
        scanner.setMapperFactoryBean((MapperFactoryBean)BeanUtils.instantiateClass(mapperFactoryBeanClass));
    }

    scanner.setSqlSessionTemplateBeanName(annoAttrs.getString("sqlSessionTemplateRef"));
    scanner.setSqlSessionFactoryBeanName(annoAttrs.getString("sqlSessionFactoryRef"));
    List basePackages = new ArrayList();
    String[] var10 = annoAttrs.getStringArray("value");
    int var11 = var10.length;

    int var12;
    String pkg;
    for(var12 = 0; var12 < var11; ++var12) {
        pkg = var10[var12];
        if (StringUtils.hasText(pkg)) {
            basePackages.add(pkg);
        }
    }

    var10 = annoAttrs.getStringArray("basePackages");
    var11 = var10.length;

    for(var12 = 0; var12 < var11; ++var12) {
        pkg = var10[var12];
        if (StringUtils.hasText(pkg)) {
            basePackages.add(pkg);
        }
    }

    Class[] var14 = annoAttrs.getClassArray("basePackageClasses");
    var11 = var14.length;

    for(var12 = 0; var12 < var11; ++var12) {
        Class clazz = var14[var12];
        basePackages.add(ClassUtils.getPackageName(clazz));
    }

    scanner.registerFilters();
    scanner.doScan(StringUtils.toStringArray(basePackages));
}

通過(guò)觀察我們看到最后還是調(diào)用了ClassPathMapperScanner的doScan去掃描指定包下的mapper接口(持久層),然后構(gòu)建對(duì)應(yīng)的beanDefinition類。前面我們知道是通過(guò)MapperScan這個(gè)注解去指定包的,然后我們也可以看到,在這個(gè)方法一開(kāi)始就取出這個(gè)注解的值,然后進(jìn)行接下來(lái)的操作的。

 AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));

之后的過(guò)程其實(shí)跟xml形式配置的一樣了。

后序

好啦,這篇沒(méi)想啰理八嗦說(shuō)了那么多,可能有好多小伙伴看到最后也是懵逼狀態(tài),這里有個(gè)建議,打開(kāi)IDE,邊看邊對(duì)著代碼跟蹤,如果哪里覺(jué)得不對(duì),可以直接debug。

這里給大家提個(gè)看源碼的建議,就是猜想+驗(yàn)證。先猜想自己的想法,然后通過(guò)查找相關(guān)問(wèn)題或者debug代碼去驗(yàn)證自己的思路。

好啦,到這里為止,mybatis和spring-mybatis的基本原理都跟大家說(shuō)了一遍,不知道小伙伴們有沒(méi)有收獲呢,下一篇,我會(huì)帶大家手寫一遍mybatis,是純手寫而且還能跑起來(lái)的那種哦!

:本人不才,以上如有錯(cuò)誤的地方或者不規(guī)范的敘述還望各位小伙伴批評(píng)指點(diǎn)。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/69636.html

相關(guān)文章

  • 教你手寫Mybatis框架

    摘要:前言嗨,小伙伴們,這篇博文將帶大家手寫,讓大家對(duì)的核心原理以及工作流程有更加深刻的理解。模塊顧名思義,就是框架配置類,用于解析配置文件加載相關(guān)環(huán)境。配置模塊這里的對(duì)框架的配置使用了簡(jiǎn)單的,主要原因還是簡(jiǎn)單易懂然后節(jié)省時(shí)間。 前言 (????)??嗨,小伙伴們,這篇博文將帶大家手寫mybatis,讓大家對(duì)mybaits的核心原理以及工作流程有更加深刻的理解。在上篇Spring-Mybat...

    antyiwei 評(píng)論0 收藏0
  • 分布式軟件架構(gòu)整合(一)

    摘要:通過(guò)整合及可以實(shí)現(xiàn)數(shù)據(jù)庫(kù)查詢后將數(shù)據(jù)持久化。但是可能出現(xiàn)幻像讀這是花費(fèi)最高代價(jià)但是最可靠的事務(wù)隔離級(jí)別。事務(wù)被處理為順序執(zhí)行。 所需技術(shù):spring、mybatis、druid、flyway、logback、nodejs、html、css3 ;目標(biāo):創(chuàng)建一個(gè)業(yè)務(wù)框架,后端采用spring+mybatis,中間層采用node,前端html5,css3等; showImg(https:/...

    mochixuan 評(píng)論0 收藏0
  • MyBatis原理概括

    摘要:避免了幾乎所有的代碼和手動(dòng)設(shè)置參數(shù)以及獲取結(jié)果集。這個(gè)對(duì)象主要是獲取方法對(duì)應(yīng)的命令和執(zhí)行相應(yīng)操作等的處理,具體細(xì)節(jié)同學(xué)們可以抽空研究。所以這里的方法主要使用了和對(duì)象幫助我們處理語(yǔ)句集和參數(shù)的處理。 博文目標(biāo):希望大家看了這篇博文后,對(duì)Mybatis整體運(yùn)行過(guò)程有一個(gè)清晰的認(rèn)識(shí)和把握。 1.什么是 MyBatis ? MyBatis 是一款優(yōu)秀的持久層框架,它支持定制化 SQL、存儲(chǔ)過(guò)程...

    mikasa 評(píng)論0 收藏0
  • 事件循環(huán)機(jī)制和task執(zhí)行順序的一些概括(javascript)

    摘要:而當(dāng)響應(yīng)成功了以后,瀏覽器的事件表則會(huì)將回調(diào)函數(shù)添加至事件隊(duì)列中等待執(zhí)行。事件循環(huán)器會(huì)不停的檢查事件隊(duì)列,如果不為空,則取出隊(duì)首壓入執(zhí)行棧執(zhí)行。類型的任務(wù)目前包括了以及的回調(diào)函數(shù)。 事件循環(huán)(event loop) : 首先說(shuō)事件隊(duì)列(task queue) 事件隊(duì)列是一個(gè)存儲(chǔ)著待執(zhí)行任務(wù)的隊(duì)列,其中的任務(wù)嚴(yán)格按照時(shí)間先后順序執(zhí)行,排在隊(duì)頭的任務(wù)將會(huì)率先執(zhí)行,而排在隊(duì)尾的任務(wù)會(huì)最后執(zhí)行...

    未東興 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<