simple-mybatis的原理及实现

这是对前面分析的代码的分析的一个总结并实现一个简单的例子来加深对框架的理解,首先来看一下mybatis框架的架构图:git

能够看到Mybatis框架的核心是MapperStatements的组件,它主要依赖于 Configuration的Mapper,来完成对操做数据库的操做。github

1. 环境的配置

ublic class Configuration {
    /**
     * 配置
     */
    private static final String DEFAULT_CONFIG_LOCATION = "application.properties";

    /**
     * mapper扫描的包路径
     */
    public static final String MAPPER_SCAN_BASEPACKAGE = "mapper.scan.basepackage";

    /**
     * Mapper的注册
     */
    private Map<Class<?>, MapperProxy> mapperProxyRegister = new HashMap<>();

    /**
     * mapperClass
     */
    private List<Class<?>> mapperClass = new ArrayList<>();

    /**
     * mapperStatement的注册
     */
    private Map<String, MapperStatement> mapperStatementRegister = new HashMap<>();

    /**
     * 加载配置服务
     */
    public Properties load() {
        Properties config = new Properties();
        try {
            config.load(Configuration.class.getClassLoader().getResourceAsStream(DEFAULT_CONFIG_LOCATION));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return config;
    }
}
复制代码

2.1 Mapper的注册

/**
     * 扫描mapper类
     */
    public List<Class<?>> doScanMapper(String packageName) {

        addClass(Thread.currentThread().getContextClassLoader(), packageName, mapperClass);
        /**
         * 扫描包
         */
        for (Class<?> clazz : mapperClass) {
            if (!mapperProxyRegister.containsKey(clazz)) {
                mapperProxyRegister.put(clazz, new MapperProxy());
            }
        }
        return mapperClass;
    }
复制代码

2.2 MapperProxy动态代理类的生成

public class MapperProxy implements InvocationHandler {

    private SqlSession sqlSession;
    private Class<?> mapperInterface;
    private  Configuration configuraion;

    @Override
    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
        String mapperId = mapperInterface.getName() +"."+ method.getName();
        MapperStatement ms =  configuraion.getMapperStatementRegister().get(mapperId);
        if(ms  == null){
            throw  new RuntimeException("MapperStatement not found");
        }
        //这里暂时只实现了select操做
        if(SqlCommand.SELECT.equals(ms.getSqlCommand())){
           return sqlSession.selectList(ms,objects);
        }
        return null;
    }

    public <T> T newInstance(Class<?> target) {
        this.mapperInterface = target;
        return (T) Proxy.newProxyInstance(target.getClassLoader(),new Class<?>[]{target}, this);
    }

    public void setSqlSession(SqlSession sqlSession) {
        this.sqlSession = sqlSession;
    }

    public void setConfiguraion(Configuration configuraion) {
        this.configuraion = configuraion;
    }
}
复制代码

3.1 MapperStatement的注册

public void registerMapperStatement() {
        //注册MapperStatement
        for (Class<?> clazz : mapperClass) {
            Method[] methods = clazz.getDeclaredMethods();

            //循环遍历每个属性
            for (Method method : methods) {
                MapperStatement mapperStatement = new MapperStatement();
                String mapperId = clazz.getName() + "." + method.getName();
                mapperStatement.setMapperId(mapperId);

                String sql = "";
                if (method.isAnnotationPresent(Select.class)) {
                    sql = method.getAnnotation(Select.class).value();
                    mapperStatement.setSqlCommand(SqlCommand.SELECT);
                } else if (method.isAnnotationPresent(Update.class)) {
                    sql = method.getAnnotation(Update.class).value();
                    mapperStatement.setSqlCommand(SqlCommand.UPDATE);
                }else if (method.isAnnotationPresent(Insert.class)) {
                    sql = method.getAnnotation(Insert.class).value();
                    mapperStatement.setSqlCommand(SqlCommand.INSERT);
                }else if (method.isAnnotationPresent(Delete.class)) {
                    sql = method.getAnnotation(Delete.class).value();
                    mapperStatement.setSqlCommand(SqlCommand.DELETE);
                } else {
                    throw new RuntimeException("no annotaion found");
                }
                mapperStatement.setBoundSql(sql);
                mapperStatement.setParams(method.getParameterTypes());
                mapperStatement.setResult(method.getReturnType());
                mapperStatement.setMethod(method);

                if (!mapperStatementRegister.containsKey(mapperId)) {
                    mapperStatementRegister.put(mapperId, mapperStatement);
                }
            }
        }
    }
复制代码

4.1 SqlSession的接口

public interface SqlSession {

   /**
    * 查询一个list集合
    */
   <T> List<T>  selectList(MapperStatement mapperStatement,Object[] objects);

   /**
    * 查询一个
    */
   <T> T selectOne(String statement);

   /**
    * 插入一条记录
    */
   int insert(String statement);

   /**
    * 更新一条记录
    */
   int update(String statement);

   /**
    * 删除一条记录
    */
   int delete(Serializable id);

   /**
    * 获取Mapper
    */
   <T> T getMapper(Class<?> clazz);
复制代码

4.2 SqlsessionFactory的工厂类的实现sql

public class SqlsessionFactory {

    private DataSource dataSource;
    private Configuration configuration;

    /**
     * 建立者
     */
    public SqlSession build() {
        this.configuration = new Configuration();
        DataSourceFacotry dataSourceFacotry = new JdbcDataSourceFactory();
        dataSourceFacotry.setProperties(configuration.load());
        this.dataSource = dataSourceFacotry.getDataSource();
        //扫描接口包
        configuration.doScanMapper(configuration.getKey(Configuration.MAPPER_SCAN_BASEPACKAGE));

        //注册mapperStatement
        configuration.registerMapperStatement();

        return new DefalutSqlSession(configuration, dataSource);
    }
复制代码

5.1 DataSourceFacoctory的接口及实现

public interface DataSourceFacotry {
    void setProperties(Properties props);
    DataSource getDataSource();
}
public class JdbcDataSourceFactory implements DataSourceFacotry {

    /**
     * url参数
     */
    private static final String DB_URL = "database.url";
    /**
     * 用户名
     */
    private static final String USER = "database.user";
    /**
     * 密码
     */
    private static final String pwd = "database.password";
    /**
     * driver
     */
    private static final String driver = "db.driver";

    /**
     * 数据源
     */
    private DruidDataSource dataSource;

    @Override
    public void setProperties(Properties props) {
        dataSource = new DruidDataSource();
        //设置链接参数
        dataSource.setUrl(props.getProperty(DB_URL));
        dataSource.setDriverClassName(props.getProperty(driver));
        dataSource.setUsername(props.getProperty(USER));
        dataSource.setPassword(props.getProperty(pwd));
        //配置初始化大小、最小、最大
        dataSource.setInitialSize(1);
        dataSource.setMinIdle(1);
        dataSource.setMaxActive(20);
        //链接泄漏监测
        dataSource.setRemoveAbandoned(true);
        dataSource.setRemoveAbandonedTimeout(30);
        //配置获取链接等待超时的时间
        dataSource.setMaxWait(20000);
        //配置间隔多久才进行一次检测,检测须要关闭的空闲链接,单位是毫秒
        dataSource.setTimeBetweenEvictionRunsMillis(20000);
        //防止过时
        dataSource.setValidationQuery("SELECT 'x'");
        dataSource.setTestWhileIdle(true);
        dataSource.setTestOnBorrow(true);
    }

    @Override
    public DataSource getDataSource() {
        return dataSource;
    }
复制代码

结果演示

@Test
    public void test(){
        SqlsessionFactory sqlsessionFactory = new SqlsessionFactory();

        SqlSession session = sqlsessionFactory.build();

        UserMapper userMapper = session.getMapper(UserMapper.class);

        List<User> userList = userMapper.selectList();

        System.out.println(userList);
    }
复制代码

代码在github地址:https://gitee.com/xjz1842/simple-mybatis。还有许多不完善的.请多多指正。数据库

相关文章
相关标签/搜索