GechangLiu 2020-04-08
导航:
在《聊聊、手写Mybatis XML配置方式》中聊了通过 XML配置方式 来实现 Mybatis,也聊到了 Mybatis 中用到的动态代理技术。我手动实现了 AccountMapperFactoryBean,但是有一个缺点,需要 XML 配置才可以用。类似 MapperFactoryBean。
这篇文章主要是聊聊通过注解方式来手写 Mybatis。我们向 Spring 注册 Bean 的方式有很多种,这里会用到 ImportBeanDefinitionRegistrar,它就是今天的主角。
自定义 AccountImportBeanDefinitionRegistrar 实现 ImportBeanDefinitionRegistrar
AccountImportBeanDefinitionRegistrar
package org.rockcode.factory;
import org.rockcode.mappers.AccountMapper;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
public class AccountImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
  BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(AccountMapperFactoryBean.class);
  AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
  beanDefinition.getPropertyValues().add("mapperInterface", AccountMapper.class);
  beanDefinitionRegistry.registerBeanDefinition("accountMapperFactoryBean",beanDefinition);
    }
}
AccountConfig
package org.rockcode.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.rockcode.factory.AccountImportBeanDefinitionRegistrar;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import javax.sql.DataSource;
@Configuration
@Import(AccountImportBeanDefinitionRegistrar.class)
public class AccountConfig {
    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        return sqlSessionFactoryBean;
    }
    @Bean
    public DataSource dataSource(){
        DruidDataSource driverManagerDataSource = new DruidDataSource();
        driverManagerDataSource.setDriverClassName("com.mysql.jdbc.Driver");
        driverManagerDataSource.setUrl("jdbc:mysql://127.0.0.1:3306/test?useSSL=false");
        driverManagerDataSource.setUsername("root");
        driverManagerDataSource.setPassword("root");
        return driverManagerDataSource;
    } 
}
AccountMapperFactoryBean
package org.rockcode.factory;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import static org.springframework.util.Assert.notNull;
public class AccountMapperFactoryBean extends SqlSessionDaoSupport implements FactoryBean {
    private Class mapperInterface;
    public void setMapperInterface(Class mapperInterface) {
        this.mapperInterface = mapperInterface;
    }
    @Autowired
    public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
        super.setSqlSessionFactory(sqlSessionFactory);
    }
    @Override
    protected void checkDaoConfig() {
        super.checkDaoConfig();
        notNull(this.mapperInterface, "Property ‘mapperInterface‘ is required");
        Configuration configuration = getSqlSession().getConfiguration();
        configuration.addMapper(this.mapperInterface);
    }
    @Override
    public Object getObject() throws Exception {
        return getSqlSession().getMapper(this.mapperInterface);
    }
    @Override
    public Class<?> getObjectType() {
        return this.mapperInterface;
    }
}  
Main方法
package org.rockcode.config;
import org.rockcode.mappers.AccountMapper;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
    public static void main(String[] args) {
  AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AccountConfig.class);
  AccountMapper accountMapper = (AccountMapper) ac.getBean("accountMapperFactoryBean");
  System.out.println(accountMapper.queryAll());
    }
} 
上面代码的重点在于 @Import(AccountImportBeanDefinitionRegistrar.class),这是 Spring 很重要的一个扩展点,与 ImportBeanDefinitionRegistrar 相同的扩展点还有 ImportSelector,它们都可以实现 Bean 的注册。