设计模式之Mybatis 初探,动态代理
【摘要】 设计模式之Mybatis 初探,动态代理
在项目中经常使用Mybatis框架作用DAO层,但是你真的对Mybatis的原理清楚吗?带着这个疑惑我们来实现一个简单的动态代理,本次了解的是接口实现动态代理,还有基于类的Mybatis的实现不在本次讨论范围之内
1.实现简单的动态代理
在了解Mybatis之前我们先来实现一个简单的动态代理的小demo
a. 定义一个接口
public interface HelloDao { void eat() ; }
b. 实现类 ,实现吃水果的方法
public class HelloDapImpl implements HelloDao{ @Override public void eat() { System.out.println("吃水果"); } }
c. 代理类 对传入的类方法进行增强
public class HelloHandler implements InvocationHandler { // 目标对象 private Object target; public HelloHandler(Object target) { super(); this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("先洗手\n------------------------------\n"); Object result = method.invoke(target, args); System.out.println("\n------------------------------\n吃完了"); return result; } /** * 获取目标对象的代理对象 * @return 代理对象 */ public Object getProxy() { return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(), this); } }
d. 测试demo
public static void main(String[] args) { HelloDao helloDao = new HelloDapImpl() ; // 实例化InvocationHandler HelloHandler invocationHandler = new HelloHandler(helloDao); // 根据目标对象生成代理对象 HelloDao proxy = (HelloDao) invocationHandler.getProxy(); // 调用代理对象的方法 proxy.eat(); }
看到运行的结果是不是感觉很像AOP对方法进行前置和后置,这里是可以这么理解,但是使用jdk的动态代理只能基于接口,后面我们回到Mybatis的上面来,跟着我一起继续
2. Mybatis实现
a. 书写实体类
public class Student { private Integer id ; private String name ; /** *省略get、set */
b. 实现InvocationHandler ,重写invoke方法
public class StudentHandler implements InvocationHandler { private String sql ; public StudentHandler(String sql) { this.sql = sql; } public StudentHandler() { } public String getSql() { return sql; } public void setSql(String sql) { this.sql = sql; } //"select *from student" @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { MyExecutor ex = new MyExecutorImpl() ; Student query = ex.query(getSql()); return query ; } }
c. 数据库工具类
public class DbUtils { static String URL = "jdbc:mysql://localhost:3308/test_demo"; static String USERNAME = "root" ; static String PASSWORD = "123123" ; public <T> T query(String statement) { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try { conn = DriverManager.getConnection(URL, USERNAME, PASSWORD); String sql = statement; ps = conn.prepareStatement(sql); rs = ps.executeQuery(); Student stu = new Student(); if (rs.next()) { stu.setId(rs.getInt("id")); stu.setName(rs.getString("name")); } return (T) stu; } catch (SQLException e) { e.printStackTrace(); } finally { close(conn,ps); } return null; } private void close(Connection conn,PreparedStatement ps){ if (ps != null) { try { ps.close(); } catch (SQLException e) { e.printStackTrace(); } } if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
d. 动态构造实现类
public <T> T getDao(Class<T> clz){ //获取这个类的名字 String name = clz.getSimpleName(); String sql = "select *from student" ; T t = (T)Proxy.newProxyInstance(clz.getClassLoader() ,new Class[]{clz},new StudentHandler(sql)); return t; } ``` e. 测试demo ``` public static void main(String[] args) { StudentTest session = new StudentTest(); //根据传入的接口获取对应的动态生成的代理类对象 StudentDao dao = session.getDao(StudentDao.class); Student one = dao.findOne(); System.out.println(one.toString()); }
运行成功,读者可能有疑问了,你sql是在代码里写死的,不是通过配置文件读取的,我们可以回到getDao()这个方法,对这个方法加以改造,如下
增加perperties文件
selectOne=select *from student
public <T> T getDao(Class<T> clz) throws FileNotFoundException { //获取这个类的名字 String name = clz.getSimpleName(); String file = "D:\\tools\\idea\\work_space\\WebMagicDemo\\src\\main\\resources\\"+name+".properties" ; //"D:\\tools\\idea\\work_space\\WebMagicDemo\\src\\main\\resources\\"+name+".properties" InputStream is = new FileInputStream(new File(file)) ; Properties prop = new Properties(); try { //读取xxx.txt文件,读取其中的sql prop.load(is); //取出其中的sql String sql = prop.getProperty("selectOne"); T t = (T)Proxy.newProxyInstance(clz.getClassLoader() ,new Class[]{clz},new StudentHandler(sql)); return t; } catch (IOException e) { e.printStackTrace(); } return null; }
这样是不是就实现了从配置文件中读取sql了呢,当然现在的代码仍然不完善,因为它没办法读取到参数,参数的读取在下片文章中会具体的讲解, 这篇文章是一个简化版的,便于理解动态代理在Mybatis中的应用,Mybatis做的工作不仅仅是这些,涉及到的很多,但是核心无非也是围绕着这个进行扩展的, 文章如理解有误请在下方纠正,一起交流
参考博客:
http://rejoy.iteye.com/blog/1627405
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)