快速掌握反射和动态代理

反射

概念

官方定义:反射允许对成员变量,成员方法和构造方法的信息进行编程访问。

直白点说,就是能去类里直接取东西。比如 idea能提示一个实体类能调用什么方法:

反射从class字节码文件中获取

获取class的三种方式

public class ClassExample {
    public static void main(String[] args) {
        // 1. 使用类名直接获取
        Class<?> clazz1 = String.class;
        System.out.println("Class obtained by class name: " + clazz1.getName());

        // 2. 通过对象实例获取
        String str = "Hello, World!";
        Class<?> clazz2 = str.getClass();
        System.out.println("Class obtained by object instance: " + clazz2.getName());

        // 3. 通过全限定类名(字符串)获取(推荐)
        try {
            Class<?> clazz3 = Class.forName("java.lang.String");
            System.out.println("Class obtained by fully qualified name: " + clazz3.getName());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

从class 字节码文件中获取信息

获取构造方法
获取公共的构造方法 Construction<?>[] getConstructors()
获取所有的构造方法 Constructor<?>[] declaredConstructors
获取指定的公共的构造方法 Construction<?>[] getConstructor()
获取指定的所有的构造方法 Constructor<?>[] declaredConstructor
Class<?> clazz = Class.forName("com.java.practice.test.Actors");

//获取公共的构造方法 Construction<?>[] getConstructors()
Constructor<?>[] constructor = clazz.getConstructors();

// 获取所有的构造方法
Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();

// 获取无参构造方法
Constructor<?> declaredConstructor = clazz.getDeclaredConstructor();

// 获取指定的构造方法
Constructor<?> declaredConstructor1 = clazz.getDeclaredConstructor(int.class, String.class);

// 获取构造方法的权限修饰符 
int modifiers = declaredConstructor1.getModifiers();

modifiers的结果:

public 的值是 1。

private 的值是 2。

protected 的值是 4。

static 的值是 8。

final 的值是 16。

synchronized 的值是 32。

volatile 的值是 64。

transient 的值是 128。

native 的值是 256。

interface 的值是 512。

abstract 的值是 1024。

strictfp 的值是 2048。

获取成员变量
public class GetField {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class<?> clazz = Class.forName("com.java.practice.model.Student");

        // 获取所有的公共的成员变量:  Field[] getFields();
        Field[] fields = clazz.getFields();

        // 获取所有的成员变量
        Field[] declaredFields = clazz.getDeclaredFields();

        // 获取指定的公共的成员变量  public
        Field gender = clazz.getField("gender");

        // 获取指定的成员变量
        Field age = clazz.getDeclaredField("age");


    }
}
获取成员方法
public class GetMethod {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Class<?> clazz = Class.forName("com.java.practice.model.Student");
        // 获取所有公共的方法 (包括父类的方法)
        Method[] methods = clazz.getMethods();


        // 获取所有的方法 (不包括父类的)
        Method[] declaredMethods = clazz.getDeclaredMethods();


        // 获取指定的公共方法
        Method method = clazz.getMethod("getName");

        // 获取指定的方法
        Method getGender = clazz.getDeclaredMethod("getGender");

        Student s = new Student();

        getGender.setAccessible(true);
        // 运行方法
        // 参数1:表示方法的所在的类
        // 参数2: 传的参数(如果没有就不传)
        Object invoke = getGender.invoke(s);

        Method eat = clazz.getDeclaredMethod("eat", String.class);
        
        Object invoke1 = eat.invoke(s, "饭");

    }
}

动态代理

动态代理是一种设计模式,它允许在运行时创建一个实现了一组给定接口的新类。这个新类可以对原始类的方法调用进行拦截和增强,而不需要修改原始类的代码。

简单点说:无侵入式地给代码增加额外功能,避免破坏原有的代码结构(不会破坏原有的石山代码)

Spring AOP 是对动态代理的封装实现。

假如我们有业务类A:学编程类,想要在此基础上增加更多的业务(非核心),可以创建代理类B。
画板

代理类(B)如何知道要有被代理类(A)的方法代理?

方法1:被代理类实现代理类接口(JDK原生)

特点:需要实现代理接口

实体类
@Getter
@Setter
public class Learning implements ProxyInterface {
    private String preparedWork;

    public Learning() {}

    @Override
    public String learnReflect() {
        System.out.println("正在学反射");
        return "学会了反射";
    }

    @Override
    public String learnDynamicProxy(String preparedWork) {
        System.out.println("正在学动态代理");
        return "学会了动态代理";
    }

    @Override
    public void learningDynamicProxy(String preparedWork) {
        System.out.println("正在学动态代理");
    }

    public Learning(String preparedWork) {
        this.preparedWork = preparedWork;
    }

    @Override
    public String toString() {
        return "Learning{preparedWork=" + preparedWork + "}";
    }
}
代理接口
public interface ProxyInterface {
    String learnReflect();

    String learnDynamicProxy(String name);

    void learningDynamicProxy(String name);
}
代理实现
public class ProxyUtils {
    public static ProxyInterface createProxy(Learning learning) {
        // 创建代理对象
        ProxyInterface proxy = (ProxyInterface) Proxy.newProxyInstance(
                ProxyUtils.class.getClassLoader(),  // 指定类加载器
                new Class[]{ProxyInterface.class},  // 指定接口
                new InvocationHandler() {  // 处理代理方法的逻辑
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        if (method.getName().equals("learnReflect")) {
                            System.out.println("先刷比利比利");
                        } else if (method.getName().equals("learnDynamicProxy") || method.getName().equals("learningDynamicProxy")) {
                            System.out.println("先睡觉");
                        }
                        // 调用被代理方法
                        return method.invoke(learning, args);
                    }
                }
        );
        return proxy;
    }
}
测试类
public class Test {
    public static void main(String[] args) {
        // 获取代理对象
        Learning learning = new Learning("刷会比利比利");
        ProxyInterface proxy = ProxyUtils.createProxy(learning);

        // 调用学反射的方法
        System.out.println("今天想学反射");
        String result = proxy.learnReflect();
        System.out.println(result);

        // 调用学动态代理的方法
        System.out.println("今天想学动态代理");
        String dynamicProxyResult = proxy.learnDynamicProxy("准备学习动态代理");
        System.out.println(dynamicProxyResult);

        // 调用另一个学动态代理的方法
        System.out.println("今天想学动态代理");
        proxy.learningDynamicProxy("准备学习动态代理");

    }
}

执行结果:

今天想学反射

先刷比利比利

正在学反射

学会了反射

今天想学动态代理

先睡觉

正在学动态代理

学会了动态代理

今天想学动态代理

先睡觉

正在学动态代理

方法2: 用CGLIB实现

特点:通过生成被代理类的子类来实现代理功能,需要继承被代理类

代理实现
public class ProxyUtils {
    public static Learning createProxy(Learning learning) {
        // 创建 Enhancer 对象
        Enhancer enhancer = new Enhancer();
        
        // 设置要代理的目标类
        enhancer.setSuperclass(learning.getClass());
        
        // 设置回调方法
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
                if (method.getName().equals("learnReflect")) {
                    System.out.println("先刷比利比利");
                } else if (method.getName().equals("learnDynamicProxy") || method.getName().equals("learningDynamicProxy")) {
                    System.out.println("先睡觉");
                }
                // 调用被代理方法
                return proxy.invokeSuper(obj, args);
            }
        });
        
        // 创建代理对象
        Learning proxy = (Learning) enhancer.create();
        return proxy;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值