Java之动态代理,动态代理与静态代理的区别

JDK动态代理是JRE提供的类库,可以直接使用,不依赖第三方。


动态代理

先了解下静态代理

静态代理的缺点:由于代理类实现了抽象角色的接口,导致代理类无法通用。
一旦接口增加方法,目标对象与代理对象都要进行修改。

静态代理的优点:接口增加方法,代理对象无需进行修改。

基于接口的动态代理:

如静态代理的内容所描述的,静态代理受限于接口的实现。
动态代理就是通过使用反射,动态地获取抽象接口的类型,从而获取相关特性进行代理。
因动态代理能够为所有的委托方进行代理。

动态代理与静态代理的区别

  • 静态代理需要自己写代理类并一一实现目标方法,且代理类必须实现与目标对象相同的接口。
  • 动态代理不需要自己实现代理类,JDK动态代理是JRE提供的类库,可以直接使用,不依赖第三方。动态地在内存中构建代理对象(需要我们传入被代理类),并且默认实现所有目标方法。

1. 首先,有个程序员接口,里面包含敲代码和改bug方法。

package proxy;

public interface Programmer {
    
    
    void typeCodes();// 敲代码

    void fixBug();// 改BUG
}

2. 现在我们来一个实现类:程序员小周

package proxy;

public class ProgrammerZhou implements Programmer {
    
    
    @Override
    public void typeCodes() {
    
    
        System.out.println("我再写Java代码。");
    }

    @Override
    public void fixBug() {
    
    
        System.out.println("好舒服,又可以改BUG了。");
    }
}

虽然 程序员小周 实现了接口,但是他并不是代理类,因为他没有设置一个中间代理来控制访问原目标对象。


3. 接下来创建一个程序员的代理类,它不需要实现程序员接口,但是他却可以为程序员小周服务

package proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProgrammerProxy implements InvocationHandler {
    
    
    //目标类,被代理对象
    private Object target;


    // 第一个参数为 Proxy 类类型实例,如匿名的 $proxy 实例
    // 第二个参数为委托类的方法对象
    // 第三个参数为委托类的方法参数
    // 返回类型为委托类某个方法的执行结果
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
        //这里可以做增强
        System.out.println("我除了会改Bug,我还会写Bug。");
        Object result = method.invoke(target, args);
        return result;
    }

    //生成代理类
    public Object getProxyedObj(Object target) {
    
    
        this.target = target;
        // 第一个参数,是类的加载器
        // 第二个参数是委托类的接口类型,证代理类返回的是同一个实现接口下的类型,保持代理类与抽象角色行为的一致
        // 第三个参数就是代理类本身,即告诉代理类,代理类遇到某个委托类的方法时该调用哪个类下的invoke方法
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }
}

4. 最后我们写一个客户端类(测试类)

package proxy;

public class Client {
    
    
    public static void main(String[] args) {
    
    
        ProgrammerProxy proxy = new ProgrammerProxy();
        Programmer programmer = (Programmer) proxy.getProxyedObj(new ProgrammerZhou());

        programmer.fixBug();
        System.out.println("-----------------------");
        programmer.typeCodes();
    }
}

5. 运行结果:

在这里插入图片描述


总结

  • 必须实现 InvocationHandler 接口,表明该类是一个动态代理执行类。
  • InvocationHandler 接口内有一实现方法如下: public Object invoke(Object proxy, Method method, Object[] args) 。使用时需要重写这个方法
  • 获取代理类,需要使用 Proxy.newProxyInstance 这个方法去获取Proxy对象(Proxy 类类型的实例)
  • 再来看看 invoke 方法,用户调用代理对象的什么方法,实质上都是在调用处理器的 invoke 方法,通过该方法调用目标方法,它也有三个参数:
    // 第一个参数为 Proxy 类类型实例,如匿名的 $proxy 实例
    // 第二个参数为委托类的方法对象
    // 第三个参数为委托类的方法参数
    // 返回类型为委托类某个方法的执行结果
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
    // ...
    }
  •   动态代理就是要生成一个包装类对象,由于代理的对象是动态的,所以叫动态代理。
      由于我们需要增强,这个增强是需要留给开发人员开发代码的,
      因此代理类不能直接包含被代理对象,而是一个InvocationHandler,
      该InvocationHandler包含被代理对象,并负责分发请求给被代理对象,
      分发前后均可以做增强。从原理可以看出,JDK动态代理是“对象”的代理。
    

猜你喜欢

转载自blog.csdn.net/I_r_o_n_M_a_n/article/details/114902921
今日推荐