首先创建Dao层数据库的接口,为了理解Mybatis动态代理机制,简单的以下述方法为例进行 *** 作
package mymybatis; import com.cqupt.entity.User; import java.util.List; public interface UserMapper { public User findById(Integer id); public List2. 在对应的XML 中定义接口方法对应的 SQL 语句findAll(); }
第二步,创建与之对应的xml,注意
mybatis配置文件中配置数据源,与注册接口对应的Mapper.xml文件,Mapper.xml文件中的命名空间需要设置为其对应接口的全类名,使得生成代理对象的时候,能过通过接口的全类名找到对应的xml文件。
3. 根据 XML,通过 JDK 动态代理(反射)完成自定义接口的具体实现
JDK提供的实现动态代理相关的是一个接口InvocationHandler与动态代理类Proxy,实现的主要分为以下几个步骤
1、继承并实现一个InvocationHandler的实现类,该实现类的作用就是实现需要增强的业务逻辑
2、创建一个该接口的动态代理类,传入InvocationHandler实现类对象。
3、使用生成的动态代理实例调用接口的方法实现
package mymybatis; import com.mchange.v2.c3p0.ComboPooledDataSource; import org.dom4j.document; import org.dom4j.documentException; import org.dom4j.Element; import org.dom4j.io.SAXReader; import java.lang.reflect.*; import java.sql.*; import java.util.*; //实现InvocationHandler的对象 public class MyInvocationHandler implements InvocationHandler { //为目标对象创建动态代理对象 public Object getInstance(Class cls){ Object newProxyInstance = Proxy.newProxyInstance( cls.getClassLoader(),//第一个参数为类参加载器 new Class[]{cls},//第二个参数为需要代理的接口 this//第三个参数为InvocationHandler实例,调用代理对象的时候,会调用传递的InvocationHandler实例中的invoke方法。 ); return newProxyInstance;//返回生成的代理对象 } @Override //调用接口执行的部分参数分别为 代理对象,执行的方法,参数 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //1、读取xml文件中数据源的信息 Map4. 自动解析结果集,映射成 XML 中配置的 JavaBeandataSourceProperty = getDataSourceProperty(); //2、创建数据库连接对象 ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setDriverClass(dataSourceProperty.get("driver")); dataSource.setJdbcUrl(dataSourceProperty.get("url")); dataSource.setUser(dataSourceProperty.get("username")); dataSource.setPassword(dataSourceProperty.get("password")); Connection connection = dataSource.getConnection(); //3、执行 SQL,获取结果集 //获取方法对应的statement 解析获取到需要执行SQL语句的相关信息 Map sqlMap = parseSatement(method.getName()); String sql = sqlMap.get("sql"); String resultType = sqlMap.get("resultType"); String parameterType = sqlMap.get("parameterType"); //4、根据实体类解析结果集 结果集-Java对象 return createObj(connection,sql, resultType,parameterType,args); }
读取xml文件中数据源的信息,结果以Map的形式返回
public MapgetDataSourceProperty(){ Map maps = new HashMap<>(); //通过dom4j读取config.xml try { SAXReader reader = new SAXReader(); //这里为数据源文件的地址 document document = reader.read("src/main/resources/config.xml"); //获取配置文件中的数据 Element rootElement = document.getRootElement(); Iterator iterator = rootElement.elementIterator(); while (iterator.hasNext()) { Element next = iterator.next(); if("environments".equals(next.getName())){ Iterator iterator1 = next.elementIterator(); while (iterator1.hasNext()) { Element next1 = iterator1.next(); Iterator iterator2 = next1.elementIterator(); while (iterator2.hasNext()) { Element next2 = iterator2.next(); if("dataSource".equals(next2.getName())) { Iterator iterator3 = next2.elementIterator(); while (iterator3.hasNext()) { Element next3 = iterator3.next(); String name = next3.attributevalue("name"); String value = next3.attributevalue("value"); maps.put(name, value); } } } } } } } catch (documentException e) { e.printStackTrace(); } return maps; }
根据接口调用的方法获取对应的statement,并解析获取到需要执行SQL语句的相关信息,以Map形式返回结果,主要解析sql语句,返回值类型,参数类型
public MapparseSatement(String methodName){ Map maps = new HashMap<>(); //通过dom4j读取config.xml try { SAXReader reader = new SAXReader(); document document = reader.read("src/main/java/mymybatis/UserMapper.xml"); //获取配置文件中的数据 Element rootElement = document.getRootElement(); Iterator iterator = rootElement.elementIterator(); while (iterator.hasNext()) { Element next = iterator.next(); String id = next.attributevalue("id"); if(id.equals(methodName)){ String sql = next.getText(); maps.put("sql", sql); String parameterType = next.attributevalue("parameterType"); String resultType = next.attributevalue("resultType"); maps.put("resultType",resultType); maps.put("parameterType",parameterType); } } } catch (documentException e) { e.printStackTrace(); } return maps; }
根据实体类解析结果集 结果集-Java对象
public Object createObj(Connection connection,String sql,String resultType,String parameterType,Object[] args){ Object result = null; try { PreparedStatement preparedStatement = connection.prepareStatement(sql); //实现传入参数的替换SQL中的占位符 if(parameterType!=null){ switch (parameterType){ case "java.lang.Integer": preparedStatement.setInt(1,(Integer) args[0]); break; case "java.lang.String": // preparedStatement.setString(); break; } } ResultSet resultSet = preparedStatement.executeQuery(); //将结果集映射成 Java 对象 try { Class aClass = Class.forName(resultType); result = parseObject(resultSet, aClass); } catch (Exception e) { e.printStackTrace(); } } catch (SQLException throwables) { throwables.printStackTrace(); } return result; } //根据查询到的ResultSet完成Javabean的映射 public Object parseObject(ResultSet resultSet,Class aClass) throws SQLException { //多行数据,映射成集合 List list = new ArrayList(); ResultSetmetaData metaData = resultSet.getmetaData(); try { while (resultSet.next()) { String columnName = null; String columnTypeName = null; Object object = aClass.getConstructor(null).newInstance(null); Object value = null; for (int i = 1; i <= metaData.getColumnCount(); i++) { columnName = metaData.getColumnName(i); columnTypeName = metaData.getColumnTypeName(i); switch (columnTypeName){ case "INT": value = resultSet.getInt(columnName); break; case "VARCHAR": value = resultSet.getString(columnName); break; } //给object赋值 //获取方法 String methodName = "set"+columnName.substring(0,1).toUpperCase()+columnName.substring(1); //获取实体类属性 Field declaredField = aClass.getDeclaredField(columnName); Method method = aClass.getMethod(methodName, declaredField.getType()); method.invoke(object,value); } list.add(object); } } catch (Exception e) { e.printStackTrace(); } if(list.size()==0) return null; if(list.size() == 1) return list.get(0); return list; }5.动态代理的测试
package mymybatis; import com.cqupt.entity.User; import java.util.List; public class Test { public static void main(String[] args) { //创建handler对象 MyInvocationHandler myInvocationHandler = new MyInvocationHandler(); //传入需要代理的接口,生成其动态代理对象 UserMapper userMapper = (UserMapper) myInvocationHandler.getInstance(UserMapper.class); //调用代理对象的方法 Listall = userMapper.findAll(); for (User user : all) { System.out.println(user); } System.out.println("******************"); User byId = userMapper.findById(1); System.out.println(byId); } }
执行后的查询结果:通过接口代理的方式可以成功的从数据库中查询到结果,并完成对象的封装
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)