Java反射案例:用反射机制调用某个对象的指定方法

一. 背景

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方法,就能创建不同类型的 JDBC连接!

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 { // 以下二选一!通过传入不同类名,建立不同类型的 JDBC连接!
            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连接工具类(反射调用)

①加载大数据类,通过 Class.forName() 方法获取字节码;
②通过 newInstance() 方法实例化大数据类;
③通过 getDeclaredMethods() 拿到大数据类的所有方法;
④找到所有方法中的那个指定方法 “getConnection”;
⑤通过 Methodinvoke() 方法,反射调用大数据对象的 “getConnection” 方法!最终建立了大数据类对应的 JDBC 连接;

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 {...}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值