手写mybatis(代理模式实战)
1、数据源配置与数据源工厂
hikari.properties
username=root
password=root
jdbcUrl=jdbc:mysql://127.0.0.1:3306/ssm?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&useSSL=false
driverClassName=com.mysql.cj.jdbc.Driver
druid.properties
druid.url=jdbc:mysql://127.0.0.1:3306/ssm?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowPubl icKeyRetrieval=true&useSSL=false
druid.username=root
druid.password=root
druid.driverClassName=com.mysql.cj.jdbc.Driver
使用数据源工厂读取配置文件进行进行数据源的生成
DataSourceFactory
package com.assin.core;
import com.alibaba.druid.pool.DruidDataSource;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import javax.sql.DataSource;
import java.io.IOException;
import java.util.Properties;
/**
* @Author:ASSIN
* @Date: 2021/9/1 16:33
*/
public class DataSourceFactory {
public static final String DATASOURCE_TYPE_HIKARI = "hikari";
public static final String DATASOURCE_TYPE_DRUID = "druid";
public static void main(String[] args) {
DataSource dataSource = DataSourceFactory.CreateDataSource(DATASOURCE_TYPE_HIKARI);
System.out.println(dataSource);
}
public static DataSource CreateDataSource(String type) {
DataSource dataSource = null;
Properties properties = new Properties();
if ("hikari".equals(type)) {
try {
properties.load(DataSourceFactory.class.getClassLoader().getResourceAsStream("hikari.properties"));
} catch (IOException e) {
e.printStackTrace();
}
HikariConfig hikariConfig = new HikariConfig(properties);
dataSource = new HikariDataSource(hikariConfig);
} else if ("druid".equals(type)) {
try {
properties.load(DataSourceFactory.class.getClassLoader().getResourceAsStream("druid.properties"));
} catch (IOException e) {
e.printStackTrace();
}
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.configFromPropety(properties);
dataSource = druidDataSource;
}
return dataSource;
}
}
2、基本配置文件
mybatis-config.properties
使用的数据源和对应的mapper配置
<mybatis>
<dataSource>hikari</dataSource>
<mapper>mapper/userMapper.xml</mapper>
</mybatis>
UserMapper.xml
包括 sql类型 返回类型 参数类型
<mapper namespace="com.assin.dao.UserDao">
<insert id="saveUser" resultType="com.assin.entity.User" paramType="com.assin.entity.User">
insert into user values(?,?,?)
</insert>
<select id="findUser" resultType="com.assin.entity.User" paramType="com.assin.entity.User">
select * from user where id = ?
</select>
</mapper>
3、实体类
User
package com.assin.entity;
import java.io.Serializable;
/**
* @Author:ASSIN
* @Date: 2021/9/1 17:48
*/
public class User implements Serializable {
private int id;
private String username;
private String password;
public User() {
}
public User(int id, String username, String password) {
this.id = id;
this.username = username;
this.password = password;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
4、Dao
UserDao
package com.assin.dao;
import com.assin.entity.User;
import java.util.List;
/**
* @Author:ASSIN
* @Date: 2021/9/1 17:47
*/
public interface UserDao {
/**
* 保存用户
* @param user
* @return
*/
Integer saveUser(User user);
/**
* 查找用户
* @param id
* @return
*/
List<User> findUser(Integer id);
}
Dao包装将配置UserMapper.xml读取到内存中包装起来
DaoWrapper
package com.assin.core;
import java.io.Serializable;
/**
* 用于描述一个Dao的方法的必要条件
* @Author:ASSIN
* @Date: 2021/9/1 18:02
*/
public class DaoWrapper implements Serializable {
/**
* 类型,insert|update|delete
*/
private String type;
/**
* 返回值的类型
*/
private String resultType;
/**
* 参数的类型
* */
private String paramType;
/**
* sql语句
*/
private String sql;
public DaoWrapper(String type, String resultType, String paramType, String sql) {
this.type = type;
this.resultType = resultType;
this.paramType = paramType;
this.sql = sql;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getResultType() {
return resultType;
}
public void setResultType(String resultType) {
this.resultType = resultType;
}
public String getParamType() {
return paramType;
}
public void setParamType(String paramType) {
this.paramType = paramType;
}
public String getSql() {
return sql;
}
public void setSql(String sql) {
this.sql = sql;
}
@Override
public String toString() {
return "DaoWrapper{" +
"type='" + type + '\'' +
", resultType='" + resultType + '\'' +
", paramType='" + paramType + '\'' +
", sql='" + sql + '\'' +
'}';
}
}
5、会话
Session
package com.assin.core;
import com.assin.dao.UserDao;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.util.Map;
/**
* 会话对象
* @Author:ASSIN
* @Date: 2021/9/1 19:21
*/
public class Session {
/**
* 每个会话持有一个连接
*/
private Connection connection;
private Map<String,Map<String,DaoWrapper>> env;
public Session(Connection connection,Map<String,Map<String,DaoWrapper>> env) {
this.connection = connection;
this.env = env;
}
public Connection getConnection() {
return connection;
}
public void setConnection(Connection connection) {
this.connection = connection;
}
public <T> T getMapper(Class clazz) {
T t = (T) Proxy.newProxyInstance(Session.class.getClassLoader(),
new Class[]{clazz},new SqlInvocationHandler(connection,env.get(clazz.getName())));
return t;
}
}
Session工厂
package com.assin.core;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.*;
/**
* @Author:ASSIN
* @Date: 2021/9/1 19:23
*/
public class SessionFactory {
private DataSource dataSource;
private Map<String,Map<String,DaoWrapper>> env = new HashMap<>(8);
public SessionFactory(String configPath) {
parseConifgXml(configPath);
// dataSource = DataSourceFactory.CreateDataSource(type);
}
/**
* 解析配置文件,加载资源环境
* @param configPath
*/
private void parseConifgXml(String configPath) {
try {
//解析数据源
SAXReader saxReader = new SAXReader();
InputStream resourceAsStream = SessionFactory.class.getClassLoader().getResourceAsStream(configPath);
Document read= saxReader.read(resourceAsStream);
Element rootElement = read.getRootElement();
Element dataSourceElement = rootElement.element("dataSource");
dataSource = DataSourceFactory.CreateDataSource(dataSourceElement.getTextTrim());
//获取所有的mapper文件
List mapperElements = rootElement.elements("mapper");
List<String> mapperPaths = new ArrayList<>();
for (Object o : mapperElements) {
Element element = (Element)o;
mapperPaths.add(element.getTextTrim());
}
for (String mapperPath : mapperPaths) {
Map<String,DaoWrapper> wrapper = new HashMap<>(8);
Document document = saxReader.read(Session.class.getClassLoader().getResourceAsStream(mapperPath));
Element root = document.getRootElement();
String namespace = root.attribute("namespace").getValue();
Iterator iterator = root.elementIterator();
while (iterator.hasNext()){
Element element = (Element) iterator.next();
String type = element.getName();
String id = element.attribute("id").getValue();
String resultType = element.attribute("resultType").getValue();
String paramType = element.attribute("paramType").getValue();
String sqlStr = element.getTextTrim();
wrapper.put(id,new DaoWrapper(type,resultType,paramType,sqlStr));
}
env.put(namespace,wrapper);
}
} catch (DocumentException e) {
e.printStackTrace();
}
}
public Session openSession(){
try {
Session session = new Session(dataSource.getConnection(),env);
return session;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
}
6、SQLHandler
package com.assin.core;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
/**
* @Author:ASSIN
* @Date: 2021/9/1 20:02
*/
public class SqlInvocationHandler implements InvocationHandler {
/**
* 传入一个连接
*/
private Connection connection ;
/**
* 传入独立环境
*/
private Map<String,DaoWrapper> env;
public SqlInvocationHandler(Connection connection, Map<String, DaoWrapper> env) {
this.connection = connection;
this.env = env;
}
/**
* 生成代理对象
* @param proxy
* @param method
* @param args
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//拿到包装
String name = method.getName();
DaoWrapper daoWrapper = env.get(name);
PreparedStatement statement = connection.prepareStatement(daoWrapper.getSql());
//对每一种sql语句中操作
if ("insert".equals(daoWrapper.getType())){
//暂定传入一个对象
Class<?> clazz = args[0].getClass();
Field[] fields = clazz.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
fields[i].setAccessible(true);
statement.setObject(i+1,fields[i].get(args[0]));
}
return statement.executeUpdate();
}else if ("select".equals(daoWrapper.getType())){
for (int i = 0; i < args.length; i++) {
statement.setObject(i+1,args[i]);
}
ResultSet resultSet = statement.executeQuery();
List list = new ArrayList();
while (resultSet.next()){
Class<?> clazz = Class.forName(daoWrapper.getResultType());
Object object = clazz.newInstance();
Field[] fields = clazz.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
fields[i].setAccessible(true);
fields[i].set(object,resultSet.getObject(fields[i].getName()));
}
list.add(object);
}
return list;
}
return null;
}
}
7、Test main
package com.assin;
import com.assin.core.Session;
import com.assin.core.SessionFactory;
import com.assin.dao.UserDao;
import com.assin.entity.User;
/**
* @Author:ASSIN
* @Date: 2021/9/1 19:27
*/
public class Test {
public static void main(String[] args) {
SessionFactory sessionFactory = new SessionFactory("mybatis-config.xml");
Session session = sessionFactory.openSession();
UserDao userDao = session.getMapper(UserDao.class);
System.out.println(userDao.findUser(10));
}
}