Java基础-反射-反射常见应用场景

Java工程师知识树 / Java基础


反射常见应用场景

  • 反射实现驱动加载
  • 反射实现配置文件加载
  • 反射实现工厂模式
  • 反射实现静态代理
  • 反射实现动态代理

反射实现驱动加载

public static void main(String[] args) throws Exception {
    // 注册 JDBC 驱动
    // 把Driver类装载进JVM 
    Class.forName("com.mysql.cj.jdbc.Driver");
    try (
            Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/myData", "root", "");
            Statement stmt = conn.createStatement();
    ) {
        // 打开链接
        System.out.println("连接数据库...");
        // 执行查询
        System.out.println(" 实例化Statement对...");
        String sql = "SELECT * FROM xtb";
        ResultSet rs = stmt.executeQuery(sql);
        while (rs.next()) {
            // 通过字段检索
            int id = rs.getInt("user_id");
            String name = rs.getString("user_name");
            // 输出数据
            System.out.print("ID: " + id);
            System.out.print(", 名字: " + name);
            System.out.print("\n");
        }
        // 完成后关闭
        rs.close();
    } catch (Exception e) {
        // 处理 Class.forName 错误
        e.printStackTrace();
    }
    System.out.println("jdbc_test_end!");
}

反射实现配置文件加载

import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Properties;  
  
/* 
 * 我们利用反射和配置文件,可以使:应用程序更新时,对源码无需进行任何修改 
 * 我们只需要将新类发送给客户端,并修改配置文件即可
 * dto.txt内容:
         className = com.wechat.management.reflection.TestInvoke
         methodName = invokeMethod
 */  
public class Demo {  
    public static void main(String[] args) throws Exception {  
        //1.通过反射获取Class对象
        Class stuClass = Class.forName(getValue("className"));//"com.wechat.management.reflection.TestInvoke"
        //2.获取invokeMethod()方法
        Method method = stuClass.getMethod(getValue("methodName"));//invokeMethod
        //3.创建对象
        TestInvoke testInvoke = (TestInvoke) stuClass.newInstance();
        //3.调用invokeMethod()方法
        String retrunStr = (String) method.invoke(testInvoke, null);
        System.out.println("获取方法执行后的返回值:"+retrunStr);

    }  
      
    //此方法接收一个key,在配置文件中获取相应的value  
    public static String getValue(String key) throws IOException{  
        Properties pro = new Properties();//获取配置文件的对象  
        FileReader in = new FileReader("E:\\projects\\management\\src\\main\\resources\\dto.txt");//获取输入流
        pro.load(in);//将流加载到配置文件对象中  
        in.close();  
        return pro.getProperty(key);//返回根据key获取的value值  
    }  
} 

反射实现工厂模式

//动物接口
interface Animal {
    public void speak();
}

//人实现类
class Man implements Animal {
    @Override
    public void speak() {
        System.out.println("是人会说话:哈哈哈!!!");
    }
}

//狗实现类
class Dog implements Animal {
    @Override
    public void speak() {
        System.out.println("是狗不会说话:汪汪汪!!!");
    }
}

//工厂类,多个对象都实现了相同的接口,工厂模式是把这些对象做一个整合,可以通过工厂类获取指定的对象
class Factory {
    /**
     * 采用反射机制的简单工厂模式,即使增加动物接口的实现也不用改该工厂类的方法
     */
    public Object getAnimal(String className) throws Exception {
        Class cls = Class.forName(className);
        return cls.newInstance();
    }

    /**
     * 简单工厂模式,增加动物接口的实现就要在该方法中做兼容处理
     */
    public Object getAnimalByType(String type) {
        if("com.wechat.management.reflection.Man".equals(type)){
            return new Man();
        }
        if("com.wechat.management.reflection.Dog".equals(type)){
            return new Dog();
        }
        return null;
    }
}

//测试类
public class ReflectFactory {
    public static void main(String[] args) throws Exception {
        Factory factory = new Factory();
        Animal man = (Animal) factory.getAnimal("com.wechat.management.reflection.Man");
        man.speak();
        Animal dog = (Animal) factory.getAnimalByType("com.wechat.management.reflection.Dog");
        dog.speak();
    }
}

执行结果:

是人会说话:哈哈哈!!!
是狗不会说话:汪汪汪!!!

反射实现静态代理

静态代理模式与简单工厂模式的区别

package com.wechat.management.reflection;

//动物接口
interface Animal {
    public void speak();
}

//人实现类
class Man implements Animal {
    @Override
    public void speak() {
        System.out.println("是人会说话:哈哈哈!!!");
    }
}

//狗实现类
class Dog implements Animal {
    @Override
    public void speak() {
        System.out.println("是狗不会说话:汪汪汪!!!");
    }
}

//工厂类,多个对象都实现了相同的接口,工厂模式是把这些对象做一个整合,可以通过工厂类获取指定的对象
class Factory {
    /**
     * 采用反射机制的简单工厂模式
     */
    public Object getAnimal(String className) throws Exception {
        Class cls = Class.forName(className);
        return cls.newInstance();
    }

    /**
     * 简单工厂模式
     */
    public Object getAnimalByType(String type) {
        if("com.wechat.management.reflection.Man".equals(type)){
            return new Man();
        }
        if("com.wechat.management.reflection.Dog".equals(type)){
            return new Dog();
        }
        return null;
    }
}

//动物代理类,代理类与被代理对象实现相同的接口,代理模式只是隐藏某个对象的行为
class AnimalProxg implements Animal{

    //内部指定是哪个被代理的对象
    private Animal animalProxg;

    public AnimalProxg() {
        animalProxg = new Dog();//默认是条狗;外部调用AnimalProxg不知道它是Dog对象
    }

    //代理里使用工厂
    public AnimalProxg(String className) {
        try {
            Factory factory = new Factory();
            this.animalProxg = (Animal) factory.getAnimal(className);;//当狗or当人由外部决定
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void speak() {
        animalProxg.speak();//说话了
    }
}

//测试类
public class ReflectFactory {
    public static void main(String[] args) throws Exception {

        //----------工厂模式-------------
        System.out.println("----------工厂模式-------------");
        Factory factory = new Factory();
        Animal man = (Animal) factory.getAnimal("com.wechat.management.reflection.Man");
        man.speak();
        Animal dog = (Animal) factory.getAnimalByType("com.wechat.management.reflection.Dog");
        dog.speak();

        //----------代理模式-------------
        System.out.println("----------代理模式-------------");
        //使用默认值,即默认是条狗
        AnimalProxg animalProxg = new AnimalProxg();
        animalProxg.speak();

        //----------代理+工厂-------------
        System.out.println("----------代理+工厂-------------");
        //把它当成人了
        AnimalProxg animalProxg2 = new AnimalProxg("com.wechat.management.reflection.Man");
        animalProxg2.speak();
    }
}

执行结果:

----------工厂模式-------------
是人会说话:哈哈哈!!!
是狗不会说话:汪汪汪!!!
----------代理模式-------------
是狗不会说话:汪汪汪!!!
----------代理+工厂-------------
是人会说话:哈哈哈!!!

反射实现动态代理

动态代理步骤:

  1. 创建一个要调用的接口实现,获取接口实现的Class。
  2. 实现InvocationHandler接口并重写invoke方法,实例化InvocationHandler对象,用来处理 Proxy 的方法调用。
  3. 通过Proxy.newProxyInstance(classLoader, interfaces, proxyHandler);实例化一个 proxy 对象。

1.实现InvocationHandler接口并重写invoke方法:

每一个动态代理类都必须要实现 InvocationHandler 这个接口,并且每个代理类的实例都关联到了一个 Handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由 InvocationHandler 这个接口的 invoke 方法来进行调用。

为什么动态代理必须实现 InvocationHandler 这个接口呢?是因为可以通过实现 InvocationHandler 这个接口来规范动态代理调用方法时的规范。

/**
 * proxy - 代理的真实对象。具体是接口的一个实现。
 * method - 所要调用真实对象的某个方法的 Method 对象
 * args - 所要调用真实对象某个方法时接受的参数
 */
public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

实例化一个 proxy 对象:

//返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序InvocationHandler
public static Object newProxyInstance(ClassLoader loader, Class[] interfaces,InvocationHandler invocationHandler)

Proxy.newProxyInstance(classLoader, interfaces, proxyHandler);三个参数分别是什么作用

classLoader:类加载器,我们手动写的都是java文件,需要编译成class文件,这个是遵循JVM规范的二进制文件,然后通过classLoader将class文件加载进内存,生成我们需要的class对象,这个class对象通过反射就可以拿到类的所有信息。在这边的作用其实就是将Java动态生成的class文件进行加载得到动态代理的class对象,以便后面其他操作。

interfaces:这个就是接口,可以看出无论代理或者Man(Dog)都是实现同样的接口,Java替我们动态生成的class文件中的方法其实就是接口中的方法。这个其实也是Java动态代理的缺点,即使Man(Dog)中声明的方法,但是接口中没有声明该方法,那么在生成的代理中就没有,也就是动态生成的代理类中只有接口中的方法。

proxyHandler:一个 InvocationHandler 对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个 InvocationHandler 对象上。集成管理Proxy方法的调用映射到Man(Dog)中,主要就是在invoke中方法实现。

动态代理和静态代理最大的不同就是Java替我们动态生成了代理类代码,代理方法的调用最后都通过InvocationHandler映射到具体的实现类中。

动态代理实现代码:

package com.wechat.management.reflection;

import java.lang.reflect.Proxy;

//动物接口
interface Animal {
    public void speak();
}

//人实现类
class Man implements Animal {
    @Override
    public void speak() {
        System.out.println("是人会说话:哈哈哈!!!");
    }
}

//狗实现类
class Dog implements Animal {
    @Override
    public void speak() {
        System.out.println("是狗不会说话:汪汪汪!!!");
    }
}

//工厂类,多个对象都实现了相同的接口,工厂模式是把这些对象做一个整合,可以通过工厂类获取指定的对象
class Factory {
    /**
     * 采用反射机制的简单工厂模式
     */
    public Object getAnimal(String className) throws Exception {
        Class cls = Class.forName(className);
        return cls.newInstance();
    }

    /**
     * 简单工厂模式
     */
    public Object getAnimalByType(String type) {
        if("com.wechat.management.reflection.Man".equals(type)){
            return new Man();
        }
        if("com.wechat.management.reflection.Dog".equals(type)){
            return new Dog();
        }
        return null;
    }
}

//动物代理类,代理类与被代理对象实现相同的接口,代理模式只是隐藏某个对象的行为
class AnimalProxg implements Animal{

    //内部指定是哪个被代理的对象
    private Animal animalProxg;

    public AnimalProxg() {
        animalProxg = new Dog();//默认是条狗;外部调用AnimalProxg不知道它是Dog对象
    }

    //代理里使用工厂
    public AnimalProxg(String className) {
        try {
            Factory factory = new Factory();
            this.animalProxg = (Animal) factory.getAnimal(className);;//当狗or当人由外部决定
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void speak() {
        animalProxg.speak();//说话了
    }
}

//动态代理类,JDK动态代理:Proxy.newProxyInstance与InvocationHandler的接口实现,动态代理隐藏了对象的方法执行行为
class DynamicProxgHandler {
    // 入参:接口对应的Class对象,出参:执行动作(方法)的代理对象
    public static Object newProxgInstance(Object target) {
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), (proxy, method, args) -> {
            System.out.println("-----------------------");
            Object result = null;
            //eg:AOP编程
            System.out.println("调用"+target.getClass().getSimpleName()+"的"+method.getName() +"前执行");
            //传入参数 invoke(Object obj, Object... args)第一个参数为入参Class对象
            result = method.invoke(target, args);
            System.out.println("调用"+target.getClass().getSimpleName()+"的"+method.getName() +"后执行");
            return result;
        });
    }

}


//测试类
public class ReflectFactory {
    public static void main(String[] args) throws Exception {

        //----------工厂模式-------------
        System.out.println("----------工厂模式-------------");
        Factory factory = new Factory();
        Animal man = (Animal) factory.getAnimal("com.wechat.management.reflection.Man");
        man.speak();
        Animal dog = (Animal) factory.getAnimalByType("com.wechat.management.reflection.Dog");
        dog.speak();

        //----------代理模式-------------
        System.out.println("----------代理模式-------------");
        //使用默认值,即默认是条狗
        AnimalProxg animalProxg = new AnimalProxg();
        animalProxg.speak();

        //----------代理+工厂-------------
        System.out.println("----------代理+工厂-------------");
        //把它当成人了
        AnimalProxg animalProxg2 = new AnimalProxg("com.wechat.management.reflection.Man");
        animalProxg2.speak();

        //----------动态代理-------------

        System.out.println("----------动态代理-------------");
        Animal animal1 = new Dog();
        animal1.speak();//什么都不使用,直接调用方法
        Animal animalProxy = (Animal) DynamicProxgHandler.newProxgInstance(new Dog());
        animalProxy.speak();//通过动态代理,代理对象执行方法
    }
}

执行结果:

----------工厂模式-------------
是人会说话:哈哈哈!!!
是狗不会说话:汪汪汪!!!
----------代理模式-------------
是狗不会说话:汪汪汪!!!
----------代理+工厂-------------
是人会说话:哈哈哈!!!
----------动态代理-------------
是狗不会说话:汪汪汪!!!
-----------------------
调用Dog的speak前执行
是狗不会说话:汪汪汪!!!
调用Dog的speak后执行

带参数的方法实现

package com.wechat.management.reflection;

import java.lang.reflect.Proxy;

public class ReflectProxg {

    public static void main(String[] args) {
        People people = new Person();
        //创建动态代理对象
        People peopleProxg = (People) Proxy.newProxyInstance(
                people.getClass().getClassLoader(),
                people.getClass().getInterfaces(),
                (proxy, method, args1) -> {
                    System.out.println("---------AOP-----------");
                    return method.invoke(people, args1);
                });
        //调用接口方法,传入参数,执行结果会给People people
        peopleProxg.from("中国");
        System.out.println(people);
        peopleProxg.from("塞尔维亚");
        System.out.println(people);
        peopleProxg.from("巴基斯坦");
        System.out.println(people);
    }
}


interface People {
    public void from(String country);
}

class Person implements People{

    private String country;

    @Override
    public void from(String country) {
        this.country = country;
    }


    public String getCountry() {
        return country;
    }

    public void setCountry(String country) {
        this.country = country;
    }

    @Override
    public String toString() {
        return "我是" + country + '人';
    }
}

打印结果:

---------AOP-----------
我是中国人
---------AOP-----------
我是塞尔维亚人
---------AOP-----------
我是巴基斯坦人

你可能感兴趣的:(Java基础-反射-反射常见应用场景)