动态代理与反射

想要更加透彻的理解动态代理,首先要熟悉下静态代理

为什么使用代理?

在平时我们写java代码的时候,是不是一个类都是只处理自己相关的业务,不会去处理多余的代码。每个类都尽量做到独立,这样才能做到高内聚低耦合,为了以后的代码维护和扩展。
那么问题来了,如果哪天我们需要在类里加上权限,日志等功能时,我们是不是需要修改每个类。这样不仅工作量巨大,严重影响代码质量。这时我们需要一个代理,让我们可以在不
改动原有代码的前提下,实现一些其他功能,即增强。我们在进入目标类之前,先进入代理类,在代理类中写我们需要的额外功能,这样原有类不动,不影响原有功能。

一、静态代理

总结来说:目标类和代理类实现了相同的接口,在代理类中依赖了目标类,代理类的方法中调用了目标类的方法,并做了一些增强性的工作。

1、实现静态代理(demo)

要求,在某个类执行类中的方法时,上下文添加一些日志记录

1)定义接口

public interface Calculate {

    int add(int num1,int num2);
}

2)定义委托类

public class Calculator implements Calculate {

    @Override
    public int add(int num1, int num2) {
        System.out.println(num1 + "+" + num2 + "=" + num1 + num2);
        return num1 + num2;
    }
}

3)定义代理类

public class CalculatorWithLog implements Calculate {

    private Calculator calculator;

    public CalculatorWithLog(Calculator calculator) {
        this.calculator = calculator;
    }


    @Override
    public int add(int num1, int num2) {
        System.out.println("add前添加一点日志");
        int sum = calculator.add(num1, num2);
        System.out.println("add后添加一点日志");
        return sum;
    }
}

2、静态代理的缺陷

程序员要手动为每一个目标类编写对应的代理类。如果当前系统已经有成百上千个类,工作量太大了
当接口改变时,所有的代理类都需要进行相应的变化,太过于耦合
所以,现在我们的努力方向是:如何少写或者不写代理类,却能完成代理功能?

二、动态代理

动态代理指的是:在程序的执行过程中,使用jdk的反射机制,创建代理对象,并动态的指定代理的目标类

动态代理的实现方式常用有两种:

  • 使用JDK代理
  • 通过CDLIB代理

1、jdk动态代理

jdk动态代理是基于Java的反射机制实现的,使用jdk反射包下的Proxy和InvocationHandler实现代理对象的动态创建
(jdk动态代理要求目标对象必须实现接口)

1)InvocationHandler接口
接口中就一个方法 :invoke()
你的代理类要完成的功能就写在invoke()中

代理类需要完成的功能:

调用目标类的方法
功能增强,在目标方法调用时,增加功能
方法原型:
Object proxy:jdk创建的代理对象,无需赋值
Method method:目标类中的方法
Object[] args:目标类中方法的参数
public Object invoke(Object proxy, Method method, Object[] args)

2)Method类
通过Method可以执行某个目标类的方法

3)proxy类
是最核心的一个类,使用静态方法 newProxyInstance() ,创建代理对象
方法原型:
ClassLoader loader:类加载器,负责向内存中加载对象(需要使用目标对象的类加载器)
Class<?>[] interfaces:目标对象实现的接口 InvocationHandler h:我们自己写的代理类需要实现的功能 返回值就是代理对象 public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,
InvocationHandler h)

4)动态代理的实现步骤

  • 创建接口,定义目标类要完成的功能
public interface Calculate {

    int add(int num1,int num2);
}

  • 创建目标类,实现该接口
public class Calculator implements Calculate {

    @Override
    public int add(int num1, int num2) {
        System.out.println(num1 + "+" + num2 + "=" + (num1 + num2));
        return num1 + num2;
    }
}

  • 创建 InvocationHandler 接口的实现类,在invoke()方法中完成代理类的功能
public class MyInvocationHandler implements InvocationHandler {

    private Object target = null;

    //动态代理,目标对象是活动的,不是固定的,需要传入进来
    public MyInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object res = method.invoke(target, args);
        System.out.println("代理对象中进行功能增强....");
        return res;
    }
}

  • 使用proxy类的newProxyInstance()方法,创建代理对象,并把返回值转成接口类型
public class Test {

    public static void main(String[] args) {

        //1、创建目标对象
        Calculator calculator = new Calculator();
        //2、创建invocationHandler对象
        InvocationHandler invocationHandler = new MyInvocationHandler(calculator);

        Calculate proxyInstance =(Calculate) Proxy.newProxyInstance(calculator.getClass().getClassLoader(), calculator.getClass().getInterfaces(),
                invocationHandler);
        proxyInstance.add(1, 3);
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值