手写Mybatis框架(二)

对于Mybatis2.0框架,主要是对代码进行优化,重构,实现了专人做专事的职责功能,在里面我们主要使用了设计模式中装饰器模式,代理模式,工厂模式。
对于Mybatis代理模式有些特殊的
在这里插入图片描述
对于专人做做事加入了
在这里插入图片描述
整体布局:
在这里插入图片描述
MConfiguration 代码:

/**
 * 
 */
package com.matao.mybatis.config;

import com.matao.mybatis.mapper.MapperRegistory;

/**
 * @author MT
 *
 */

public class MConfiguration {
	private String scanPath;
	private MapperRegistory mapperRegistory = new MapperRegistory();
	
	public MConfiguration scanPath(String scanPath){
		this.scanPath = scanPath;
		return this;
	}
	
	public void build(){
		if (scanPath == null || scanPath.length() <1) {
			throw new RuntimeException("this scanPath is required");
		}
	}

	public String getScanPath() {
		return scanPath;
	}

	public void setScanPath(String scanPath) {
		this.scanPath = scanPath;
	}

	public MapperRegistory getMapperRegistory() {
		return mapperRegistory;
	}

	public void setMapperRegistory(MapperRegistory mapperRegistory) {
		this.mapperRegistory = mapperRegistory;
	}
	
	

}

MSqlSession代码:

/**
 * 
 */
package com.matao.mybatis.sqlsession;

import java.lang.reflect.Proxy;

import com.matao.mybatis.config.MConfiguration;
import com.matao.mybatis.excuter.Executer;
import com.matao.mybatis.excuter.SimpleExecuter;
import com.matao.mybatis.mapper.MapperProxy;
import com.matao.mybatis.mapper.MapperRegistory;

public class MSqlSession {
	private  MConfiguration configuration;
	private Executer<?> executer;
	
	
	public MConfiguration getConfiguration() {
		return configuration;
	}
	
	//构造方法
	public MSqlSession(MConfiguration configuration, Executer executer) {
		super();
		this.configuration = configuration;
		this.executer = executer;
	}
	//得到mapper对象
	
	public MSqlSession() {
		super();
		// TODO Auto-generated constructor stub
	}


	public <T> T getMapper(Class<T> clazz){
		return (T) Proxy.newProxyInstance(clazz.getClassLoader(),
				new Class[]{clazz}, new MapperProxy<T>(this,clazz));
	}
	//实现查询方法
	public <T> T selectOne(MapperRegistory.MapperData<T> statement,Object parameter){

		return (T) executer.query(statement, parameter);
	}

}

MapperProxy代码:

/**
 * 
 */
package com.matao.mybatis.mapper;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

import com.matao.mybatis.sqlsession.MSqlSession;

/**
 * @author MT
 * @param <T>
 *
 */
public class MapperProxy<T> implements InvocationHandler{

	private final MSqlSession mSqlSession;
	private final Class<T> mapperInterface;
	/**
	 * @param <T>
	 * @param mSqlSession
	 * @param clazz
	 */
	public  MapperProxy(MSqlSession mSqlSession, Class<T> clazz) {
		this.mSqlSession = mSqlSession;
		this.mapperInterface = clazz;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println(method.getDeclaringClass().getName() + "." + method.getName());
		MapperRegistory.MapperData mapperData = 
				 mSqlSession
				.getConfiguration()
				.getMapperRegistory()
				.get(method.getDeclaringClass().getName() + "." + method.getName());
				
		if (mapperData != null) {
			return mSqlSession.selectOne(mapperData, String.valueOf(args[0]));
		}
		return method.invoke(proxy, args);
	}

}

MapperRegistory 代码:

/**
 * 
 */
package com.matao.mybatis.mapper;

import java.util.HashMap;
import java.util.Map;

import com.matao.mybatis.Test;


/**
 * @author MT
 *
 */
public class MapperRegistory {
	
	private static Map<String, MapperData> methodSqlMapping = new HashMap<String, MapperData>();
	
	public MapperRegistory(){
		methodSqlMapping.put("com.matao.mybatis.mapper.TestMapper.selectByPrimaryKey", 
				new MapperData("select * from test where id = %d", Test.class));
	}
	

    public class MapperData<T>{
	   private String sql;
	   private Class<T> type;
	public MapperData(String sql, Class<T> type) {
		super();
		this.sql = sql;
		this.type = type;
	}
	/**
	 * @return the sql
	 */
	public String getSql() {
		return sql;
	}
	/**
	 * @param sql the sql to set
	 */
	public void setSql(String sql) {
		this.sql = sql;
	}
	/**
	 * @return the type
	 */
	public Class<T> getType() {
		return type;
	}
	/**
	 * @param type the type to set
	 */
	public void setType(Class<T> type) {
		this.type = type;
	}
	  
	  
	  
  } 

	public Map<String, MapperData> getMethodSqlMapping() {
		return methodSqlMapping;
	}

	public void setMethodSqlMapping(Map<String, MapperData> methodSqlMapping) {
		MapperRegistory.methodSqlMapping = methodSqlMapping;
	}

	/**
	 * @param string
	 * @return
	 */
	public MapperData get(String key) {
		
		return methodSqlMapping.get(key);
	}
	
	

}


Executer代码:

/**
 * 
 */
package com.matao.mybatis.excuter;

import com.matao.mybatis.mapper.MapperRegistory;

/**
 * @author MT
 * @param <T>
 *
 */
public interface Executer<T> {

	/**
	 * @param statement
	 * @param parameter
	 * @return
	 */
	T query(MapperRegistory.MapperData statement, Object parameter);

}

ExecuterFactory 代码:

/**
 * 
 */
package com.matao.mybatis.factory;

import java.io.ObjectInputStream.GetField;

import com.matao.mybatis.config.MConfiguration;
import com.matao.mybatis.excuter.CacheingExecuter;
import com.matao.mybatis.excuter.Executer;
import com.matao.mybatis.excuter.SimpleExecuter;

/**
 * @author MT
 *
 */
public class ExecuterFactory {
	private static final String SIMPLE="simple";
	private static final String CACHE="cache";
	
	public static Executer DEFAULT(MConfiguration configuration){
		return get(SIMPLE,configuration);
	}

	/**
	 * @param simple2
	 * @param configuration
	 * @return
	 */
	public static Executer get(String key, MConfiguration configuration) {
		if (SIMPLE.equalsIgnoreCase(key)) {
			return new SimpleExecuter(configuration);
		}
		if (CACHE.equalsIgnoreCase(key)) {
			return new CacheingExecuter(new SimpleExecuter(configuration));
		}
		throw new RuntimeException("executer is not found");
	}
	
	public enum ExecuterType{
		SIMPLE,
		CACHE
	}

}

SimpleExecuter 代码:

/**
 * 
 */
package com.matao.mybatis.excuter;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import com.matao.mybatis.Test;
import com.matao.mybatis.config.MConfiguration;
import com.matao.mybatis.handler.StatementHandler;
import com.matao.mybatis.mapper.MapperRegistory;

/**
 * @author MT
 * @param <E>
 *
 */
public class SimpleExecuter implements Executer{
	
	private MConfiguration configuration;
	
	
	public SimpleExecuter() {
		super();
		// TODO Auto-generated constructor stub
	}

	public SimpleExecuter(MConfiguration configuration) {
		super();
		this.configuration = configuration;
	}

	public MConfiguration getConfiguration() {
		return configuration;
	}

	public void setConfiguration(MConfiguration configuration) {
		this.configuration = configuration;
	}

	/* (non-Javadoc)
	 * @see com.matao.mybatis.excuter.Executer#query(java.lang.String, java.lang.Object)
	 */
	@Override
	public Object query(MapperRegistory.MapperData mapperdata, Object parameter) {
		
		try {
			StatementHandler handler = new StatementHandler(configuration);
			return handler.query(mapperdata,parameter);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}
	
}

StatementHandler代码:

/**
 * 
 */
package com.matao.mybatis.handler;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

import com.matao.mybatis.config.MConfiguration;
import com.matao.mybatis.mapper.MapperRegistory;


/**
 * @author MT
 * @param <E>
 *
 */
public class StatementHandler<E> {
	private final MConfiguration configuration;
	private final Resulthandler resulthandler;
	String driver = "com.mysql.jdbc.Driver";
	String username = "root";
	String password = "123456";
	String url = "jdbc:mysql://localhost:3310/test";
	
	

	public StatementHandler(MConfiguration configuration) {
		super();
		this.configuration = configuration;
		this.resulthandler = new Resulthandler(configuration);
	}



	/**
	 * @param mapperdata
	 * @param parameter
	 * @return
	 * @throws Exception 
	 */
	public <E> E query(MapperRegistory.MapperData mapperdata, Object parameter) throws Exception {
		try {
		Connection conn = getConnection();
		
		PreparedStatement psStatement;
		
		psStatement = conn.prepareCall(String.format(mapperdata.getSql(), Integer.parseInt(String.valueOf(parameter))));
		
		psStatement.execute();
		return (E) Resulthandler.handle(psStatement,mapperdata);
		} catch (NumberFormatException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
		
	}
	
	/**
	 * @return
	 */
	private Connection getConnection() {
		Connection conn =null;
		try {
			Class.forName(driver);
			conn = DriverManager.getConnection(url, username, password);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return conn;
	}



	/**
	 * @return the configuration
	 */
	public MConfiguration getConfiguration() {
		return configuration;
	}



	/**
	 * @return the resulthandler
	 */
	public Resulthandler getResulthandler() {
		return resulthandler;
	}
}

Resulthandler 代码:

/**
 * 
 */
package com.matao.mybatis.handler;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import com.matao.mybatis.config.MConfiguration;
import com.matao.mybatis.mapper.MapperRegistory;


/**
 * @author MT
 *
 */
public class Resulthandler {
	private final MConfiguration configuration;
	

	public Resulthandler(MConfiguration configuration) {
		super();
		this.configuration = configuration;
	}
	


	/**
	 * @param <E>
	 * @param <T>
	 * @param psStatement
	 * @param mapperdata
	 * @return
	 * @throws Exception 
	 */
	public static <E, T> E handle(PreparedStatement psStatement, MapperRegistory.MapperData<T> mapperdata) throws Exception {
		Object resultObj = mapperdata.getType().newInstance();
		ResultSet rs = psStatement.getResultSet();
		if(rs.next()) {
			int i = 0;
			for(Field field : resultObj.getClass().getDeclaredFields()){
				System.out.println(field);
				setValue(resultObj,field,rs,i);
			}
		}
		return (E) resultObj;
	}



	/**
	 * @param <T>
	 * @param resultObj
	 * @param field
	 * @param rs
	 * @param i
	 * @throws Exception 
	 */
	private static <T> void setValue(Object resultObj, Field field, ResultSet rs, int i) throws Exception {
		Method setMethod = resultObj.getClass().getMethod("set" + upperCapital(field.getName()), field.getType());
		System.out.println(setMethod.getName());
		setMethod.invoke(resultObj, getResult(field,rs));
	}



	/**
	 * @param name
	 * @return
	 */
	private static  String upperCapital(String name) {
		String first = name.substring(0, 1);
		String tail = name.substring(1);
		return first.toUpperCase() + tail;
	}



	/**
	 * @param field
	 * @param rs
	 * @return
	 * @throws SQLException 
	 */
	private static Object getResult(Field field, ResultSet rs) throws SQLException {
		Class<?> type = field.getType();
		if (Integer.class == type) {
			return rs.getInt(field.getName());
		}
		if (String.class == type) {
			return rs.getString(field.getName());
		}
		return rs.getString(field.getName());
	}



	/**
	 * @return the configuration
	 */
	public MConfiguration getConfiguration() {
		return configuration;
	}
	

}

CacheingExecuter代码:

/**
 * 
 */
package com.matao.mybatis.excuter;



import java.util.HashMap;
import java.util.Map;

import com.matao.mybatis.config.MConfiguration;
import com.matao.mybatis.handler.StatementHandler;
import com.matao.mybatis.mapper.MapperRegistory.MapperData;

/**
 * @author MT
 * @param <T>
 * @param <T>
 *
 */
public class CacheingExecuter<T> implements Executer<T>{
	private MConfiguration configguration;
	
	private SimpleExecuter delegate;
	
	private Map<String, Object> localCache = new HashMap<String, Object>();
	
	public CacheingExecuter() {
		super();
		// TODO Auto-generated constructor stub
	}
	

	public MConfiguration getConfigguration() {
		return configguration;
	}


	public void setConfigguration(MConfiguration configguration) {
		this.configguration = configguration;
	}


	public CacheingExecuter(MConfiguration configguration) {
		super();
		this.configguration = configguration;
	}
	

	public CacheingExecuter(SimpleExecuter delegate) {
		super();
		this.delegate = delegate;
	}


	@Override
	public T query(MapperData mapperdata, Object parameter) {
		// TODO Auto-generated method stub
		StatementHandler handler = new StatementHandler<>(configguration);
		
		Object result = localCache.get(mapperdata.getSql());
		if (result != null) {
			return  (T) result;
		}
		result = (T) delegate.query(mapperdata, parameter);
		localCache.put(mapperdata.getSql(), result);
		
		return   (T) delegate.query(mapperdata, parameter);
	}

}

测试:

TestMapper 代码:

/**
 * 
 */
package com.matao.mybatis.mapper;

import com.matao.mybatis.Test;

/**
 * @author MT
 *
 */
public interface TestMapper {
	Test selectByPrimaryKey(Integer userid);

}

/**
 * 
 */
package com.matao.mybatis;

import com.matao.mybatis.config.MConfiguration;
import com.matao.mybatis.excuter.SimpleExecuter;
import com.matao.mybatis.factory.ExecuterFactory;
import com.matao.mybatis.factory.ExecuterFactory.ExecuterType;
import com.matao.mybatis.mapper.TestMapper;
import com.matao.mybatis.sqlsession.MSqlSession;

/**
 * @author MT
 *
 */
public class BootStrap {
	public static void main(String[] args) {
		MConfiguration config = new MConfiguration();
		config.setScanPath("com.matao.mybatis.mapper");
		config.build();
		MSqlSession sqlSession = new MSqlSession(config,ExecuterFactory.get(ExecuterType.CACHE.name(),config));
		TestMapper mapper = sqlSession.getMapper(TestMapper.class);
		Test test = mapper.selectByPrimaryKey(1);
		System.out.println(test);
	}

}

测试结果
在这里插入图片描述
总结:虽然只是简单的手写Mybatis代码:但是基本功能还是可以实现的,也没感觉Mybatis那么高高在上了,至少对他更感兴趣了,而不是说这是一个很难的业务需求了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
手写MyBatis框架可以遵循以下步骤: 1. 创建一个配置类,用于加载数据库配置信息和Mapper接口配置信息。 2. 创建一个SqlSession类,用于管理数据库连接、执行SQL语句和返回结果。 3. 创建一个Mapper接口,定义数据库操作方法。 4. 创建一个MapperProxy类,实现动态代理,将Mapper接口的方法调用转发给SqlSession执行对应的SQL语句。 5. 创建一个MapperRegistry类,用于管理Mapper接口和对应的MapperProxy对象。 6. 创建一个DefaultSqlSessionFactory类,用于创建SqlSession对象。 7. 创建一个SqlSessionFactoryBuilder类,用于读取配置信息并创建DefaultSqlSessionFactory对象。 8. 创建一个Configuration类,用于保存MyBatis的全局配置信息。 9. 创建一个Executor类,用于执行SQL语句。 10. 创建一个StatementHandler类,用于封装和执行JDBC操作。 11. 创建一个ResultSetHandler类,用于处理查询结果集。 12. 创建一个TypeHandler类,用于处理Java类型和数据库类型之间的转换。 13. 创建一个XMLMapperBuilder类,用于解析Mapper配置文件,并将解析结果注册到Configuration中。 14. 创建一个XMLConfigBuilder类,用于解析MyBatis配置文件,并将解析结果保存到Configuration中。 15. 在主程序中,使用SqlSessionFactoryBuilder读取配置信息创建SqlSessionFactory,并通过SqlSessionFactory创建SqlSession对象,最后使用SqlSession获取Mapper接口的代理对象,从而实现对数据库的操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值