静态代理和动态代理

1.为什么要用代理

  可以在不改变原方法的前提下改变方法体的内容,不会影响其他功能

2.静态代理

  首先定义了一个接口 Calculator 

public interface Calculator {
    int add(int a,int b);
    int sub(int a,int b);
    void print(String str);
}

  然后有一个接口的实现类 CalculatorImpl

public class CalculatorImpl implements Calculator {
    
    public int add(int a, int b) {
        System.out.println(a+b);
        return a+b;
    }

    public int sub(int a, int b) {
        System.out.println(a-b);
        return a-b;
    }

    public void print(String str) {
        System.out.println("print "+str);
    }
}

  定义一个代理类,和实现类 CalculatorImpl 实现相同的接口,保证方法一致,我们可以在代理类中随意增加方法逻辑,同时不改变原实现类的逻辑,以下代码就在原实现类上增加了一个打印

public class CalculatorImplProxy implements Calculator {

    private CalculatorImpl calculator;

    public CalculatorImplProxy(){
        this.calculator=new CalculatorImpl();
    }

    public int add(int a, int b) {
        System.out.println("正在执行a+b");
        return calculator.add(a,b);
    }

    public int sub(int a, int b) {
        System.out.println("正在执行a-b");
        return calculator.sub(a,b);
    }

    public void print(String str) {
        System.out.println("正在执行打印");
        calculator.print(str);
    }
}

  在接口有很多实现类时,如果用静态代理,就需要每个实现类都有一个代理类,就比较麻烦,可以使用动态代理

3.动态代理

Proxy.newProxyInstance()

  要实现动态代理必须要有接口的,动态代理是基于接口来代理的(实现接口的所有方法),如果没有接口的话我们可以考虑cglib代理。cglib代理也叫子类代理,从内存中构建出一个子类来扩展目标对象的功能

  可以不用写代理类,直接使用接口生成代理对象,Jdk提供了 InvocationHandler 接口和 Proxy 类,借助这两个工具可以达到我们想要的效果

  首先介绍一下InvocationHandler接口,它只有一个invoke方法,这个方法非常重要,方法参数如//Object proxy,代理对象//Method method,被代理对象的方法

//Object[] args,方法所需的参数

public interface InvocationHandler {

  public Object invoke(Object proxy, Method method, Object[] args)
    throws Throwable;
}

  Proxy类,它里面有一个很重要的方法 newProxyInstance,参数如下

//ClassLoader loader,被代理对象的类加载器
//Class<?>[] interfaces,被代理类所实现的全部接口
//InvocationHandler h,实现InvocationHandler 接口的对象
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
        throws IllegalArgumentException{
  ...
}

  接下来看一下动态代理的代码,新建一个类实现 InvocationHandler 接口,用来生成代理对象,接口 Calculator 和实现类 CalculatorImpl 不变

public class ProxyHandler implements InvocationHandler {
private Object target;

public Object getProxyInstance(Object target){
this.target=target;
//target.getClass().getClassLoader():被代理对象的类加载器
//target.getClass().getInterfaces():被代理对象的实现接口
//this 当前对象,该对象实现了InvocationHandler接口,所以有invoke方法,通过invoke方法可以调用被代理对象的方法
Object proxy= Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),this);
return proxy;
}

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("正在进行"+method.getName()+"操作");
//利用反射,执行 method对象的invoke方法
return method.invoke(target,args);
}

public static void main(String[] args) {
ProxyHandler proxyHandler=new ProxyHandler();
CalculatorImpl calculator=new CalculatorImpl();
Calculator proxy= (Calculator) proxyHandler.getProxyInstance(calculator);
proxy.add(1,2);
//打印一下动态生成的代理类
System.out.println(proxy.getClass());
}
}
  结果如下
正在进行add操作
3
class com.sun.proxy.$Proxy0

  可以看到,动态代理是有生成代理类的

  动态代理将被代理的对象作为参数传入就可以执行里面的任意方法,所有的方法调用都通过invoke来完成。不用对每个方法进行处理

  代理模式的定义:代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用,通俗的来讲代理模式就是我们生活中常见的中介,动态代理和静态代理的区别在于静态代理我们需要手动的去实现目标对象的代理类,而动态代理可以在运行期间动态的生成代理类

  

  参考:https://www.zhihu.com/question/20794107/answer/811250346

posted @ 2019-12-03 11:04  hjy1995  阅读(133)  评论(0编辑  收藏  举报