Java反射案例:用反射机制调用某个对象的指定方法
- 一. 背景
- 1. 反射机制有什么用?
- 2. 反射机制的相关类在哪个包下?
- 3. 反射机制相关的类有哪些?
- 4.为什么要通过反射来造对象? ★
- 二. 案例
- 1. 需求
- 2. JDBC 连接测试类
- 3. 连接大数据环境工具类
- 4. JDBC连接工具类(反射调用)
- 5.大数据类(华为和cdh)
一. 背景
1. 反射机制有什么用?
- 通过Java语言中的反射机制可以操作字节码文件,类似于黑客(可以读和修改字节码.class文件)
- 可以让程序变得更加灵活
2. 反射机制的相关类在哪个包下?
在 java.lang.reflect.*
下
3. 反射机制相关的类有哪些?
java.lang.class
代表整个字节码,代表整个类,包括了以下的方法、构造方法、属性。 (必须先获取)
java.lang.reflect.Method
代表字节码中的方法字节码,代表类中的方法。
java.lang.reflect.Constructor
代表字节码中的构造方法字节码,代表类中的构造方法。
java.lang.reflect.Filed
代表字节码中的属性字节码,即成员变量(静态变量+实例变量)
注意:
- Class类没有公共的构造方法,无法通过new 运算符实例化;只能通过对象
.getClass
方法,或是通过Class.forName(…)
来获得实例。 Class.forname()
方法会导致类加载!导致静态代码块执行!
4.为什么要通过反射来造对象? ★
因为反射创造对象能体现 动态性 / 灵活性 !
Java代码只需要写一遍,在不改变Java源代码的基础之上,可以做到不同对象的实例化!符合OCP原则!
而 User u=new User 这种方法把代码写死了,只能创建一个User类型的对象!
二. 案例
1. 需求
在使用JDBC 连接大数据环境的Hive时,只修改一个类名,指定调用类的 getConnection方法,就能创建不同类型的 connection!
2. JDBC 连接测试类
ConnGenrate.getBigdataConn()
方法参数内,
传入 HwDatasourceManageService.Class
即连接 华为 的Hive,
传入 CdhDatasourceManageService.class
则连接 cdh 的Hive!
public class JdbcTest {public static void main(String[] args) {Statement stmt = null;String sql = args[0];DatasourceEntity dm = new DatasourceEntity();dm.setDatabaseType(DbType.HIVE.getDescp());dm.setAuthSchema(AuthType.KERBEROS.getCode());dm.setPrincipal("username");dm.setKeytabFilePath("/tmp/user.keytab");dm.setLinkInfo("jdbc:hive2:连接串");dm.setZkPrincipal("zookeeper/hadoop.hadoop.com@HADOOP.COM");dm.setConfigFilePath("/tmp/");
// Boolean status = ConnCheck
// .checkBigdataConnection(HwDatasourceManageService.class.getName(), dm);
// System.out.println("连接状态:" + status);Connection conn;try {conn = (Connection) ConnGenrate.getBigdataConn(HwDatasourceManageService.class.getName(), dm);conn = (Connection) ConnGenrate.getBigdataConn(CdhDatasourceManageService.class.getName(), dm);if (conn != null) {stmt = conn.createStatement();int count = stmt.executeUpdate(sql);
// stmt.execute(sql);
// ResultSet rs = stmt.getResultSet();
// while (rs.next()){
// System.out.println(rs.getObject(1).toString());
// }} else {System.out.println("获取连接失败!");}conn.close();} catch (Exception e) {try {} catch (Exception e2) {System.out.println("Error: " + e2.getMessage());}System.out.println("Error:" + e.getMessage());}}
}
3. 连接大数据环境工具类
将大数据类名传入该方法,并指定调用类中的 “getConnection” 方法!
public class ConnGenrate {public static Object getBigdataConn(String clazzName, Object...params){String methodName = "getConnection"; // 指定调用大数据类的哪一个方法return DataSourceUtil.invoke(clazzName, methodName, params);}
}
4. JDBC连接工具类(反射调用)
①加载大数据类,获取字节码
②示例化大数据类
③遍历字节码拿到大数据类的所有方法
④找到所有方法中的那个指定方法 “getConnection”
⑤通过反射调用大数据对象的 “getConnection” 方法!
public class DataSourceUtil {public static Object invoke(String clazzName, String methodName, Object...params){try {Class<?> clazz=Class.forName(clazzName); // 加载大数据类!获取字节码Object obj=clazz.newInstance(); // 实例化大数据类!Method[] methods = clazz.getDeclaredMethods(); // 遍历反射拿到类的所有方法!Method callMethod=null;for(Method method:methods){if(method.getName().equals(methodName)){callMethod=method;break;}}callMethod.setAccessible(true);return (Object) callMethod.invoke(obj, new Object[]{params});} catch (Exception e) {LOGGER.error(e.getMessage());e.printStackTrace();}return null;}
}
5.大数据类(华为和cdh)
最终调用的是大数据类中的 “getConnection” 方法!
了解思路即可,具体内容不予以展示;
public class HwDatasourceManageService{public Object getConnection(Object... params) throws Exception {...}
}
public class CdhDatasourceManageService{public Object getConnection(Object... params) throws Exception {...}
}