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 {...}
}