反射与JDK动态代理QAQ

170 阅读3分钟

反射

含义

反射 (Reflection) 是 Java 的特征之一,它允许运行中的 Java 程序获取自身的类的信息,并且可以操作类或对象的内部属性。

作用

  • 实例化对象
  • 属性注入
  • 方法调用
  • 获取类信息

例子

代理模式

  • 含义:当一个对象不能直接使用,可以在客户端和目标对象直接创建一个中介,这个中介就是代理

  • 作用

    • 控制访问:在代理中是否可以调用目标对象的方法

    • 功能增强:可以在完成目标对象的调用时,附加一些格外的功能,这些格外的功能叫做功能增强

      • 缺点:目标类比较多的时候,会产生大量的代理类;当接口改变时,影响目标类
  • 实现方式

    • 静态代理:代理类是手工实现的Java文件,代理的对象是确定的

    • 动态代理:利用反射机制,在运行时创建代理类对象,解决了静态代理的痛点:不用创建代理类且可以给不同目标随时创建代理

      • java.lang.reflect反射包的三个类
      • InvocationHandler
      • Method
      • Proxy

jdk动态代理工具类的实现

  • 元素

    • 目标类接口(targetInterface)

    • InvocationHandeler的实现类

      • invoke()方法完成代理类的功能
      • 后续工具类中使用到了函数回调的思想
    • 使用Proxy类的静态方法,创建代理对象

目标类接口

public interface targetInterface {
   int method1(int a,int b);
   void method2();
}

目标类

public class target implements targetInterface {
    @Override
    public int method1(int a, int b) {
        System.out.println("I'm method1");
        return 0;
    }
​
​
    public void method2(){
        System.out.println("I'm method2");
    }
}

完善代理的invoke()方法

public class MyInvocationHandler implements InvocationHandler {
​
   private Object target;
​
​
   public MyInvocationHandler(Object target){
      this.target = target;
   }
​
​
   @Override
   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
​
      System.out.println("before invoking bar()");
​
      Object result = method.invoke(target, args);
​
      System.out.println("after invoking bar()");
​
​
      return result;
   }
}

调用方法

        //方法一
        targetInterface target = new target();
        InvocationHandler invocationHandler = new MyInvocationHandler(target);
        targetInterface proxy = (targetInterface) Proxy.newProxyInstance(test.class.getClassLoader(),target.getClass().getInterfaces(),invocationHandler);
        proxy.method1(1,1);
        proxy.method2();

代理工具类

public class ProxyUtil<T> {
​
    private Callback callback;
    private T target;
​
    public ProxyUtil(T target,Callback callback ) {
        this.callback = callback;
        this.target = target;
    }
​
    /**
     * 获取代理对象
     * @return 代理对象
     * @param
     */
    public T getProxy(){
        //这边不知道如何确定用户创建的实现类,那我们就使用一个匿名的内部实现类来实现
        InvocationHandler invocationHandler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if (callback!=null){
                    callback.before(method.getName(),args);
                }
                //result 接收方法返回值
                Object result = method.invoke(target, args);
                if (callback!=null){
                    callback.after(method.getName(),args);
                }
                return result;
            }
        };
        return (T) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),target.getClass().getInterfaces(),invocationHandler);
    }
​
​
}
//函数反转
interface Callback{
    void before(String methodName,Object... args);
    void after(String methodName,Object... args);
}

调用工具类

        ProxyUtil<targetInterface> targetInterfaceProxyUtil = new ProxyUtil<targetInterface>(target,new Callback(){
​
            @Override
            public void before(String methodName, Object... args) {
                System.out.println(methodName);
                System.out.println("方法前处理");
            }
​
            @Override
            public void after(String methodName, Object... args) {
                System.out.println(methodName);
                System.out.println("方法后处理");
            }
        });
        //获取代理对象
        targetInterface proxy1 = targetInterfaceProxyUtil.getProxy();
        proxy1.method1(1,2);
        proxy1.method2();

Spring的Bean配置(扩展点)

  • 文件名:spring_config.xml

  • 通过main方法:

    • 调用ClassPathXmlApplicationContext("spring_config.xml")来加载配置文件
    <bean id="apple" class="org.example.factory.Apple" scope="prototype">
        <!-- collaborators and configuration for this bean go here -->
    </bean>
  • Spring框架使用了代理模式来管理Bean的创建和生命周期,并通过反射来辅助实现依赖注入的过程。

    • 调用了invoke方法(DelegatingMethodAccessorImpl 类的 invoke)

          ApplicationContext applicationContext = new ClassPathXmlApplicationContext("sp.xml");
          Apple apple = applicationContext.getBean("apple", Apple.class);
          apple.eat();    
      
    • ApplicationContext使用BeanDefinition来保存对象信息

      • Bean的类名
      • 作用域
      • 构造函数参数
      • 属性值
      • 依赖关系等
    • Spring容器解析配置文件或者扫描注解的时候,会根据配置信息创建响应的BeanDefinition对象,并保存在内部的数据结构中,通常是一个注册表(类似于一个对象工厂,能够根据Bean的名称或者类型获取对应的Definition对象)

    • 在 Spring 的 ApplicationContext 中,getBean() 方法用于从容器中获取指定名称或类型的 Bean 实例

    public class DefaultApplicationContext implements ApplicationContext {
        // ...
    ​
        @Override
        public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
            // 根据名称从容器中获取 BeanDefinition 对象
            BeanDefinition beanDefinition = beanRegistry.getBeanDefinition(name);
    ​
            // 根据 BeanDefinition 中的类名使用反射创建对象实例
            Class<?> beanClass = beanDefinition.getBeanClass();
            T beanInstance;
            try {
                beanInstance = requiredType.cast(beanClass.getDeclaredConstructor().newInstance());
            } catch (Exception ex) {
                throw new BeansException("Error creating bean instance", ex);
            }
    ​
            // 执行依赖注入等初始化操作
            // ...
    ​
            return beanInstance;
        }
    ​
        // ...
    }
    ​
    
    • requiredType.cast()

      • Java 中的一个强制类型转换方法,用于将对象转换为指定的类型。
    • getDeclaredConstructor().newInstance()

      • 动态地实例化对象