定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
作用:**不改变原类的代码,而增强原类对象的功能,可选择前置、后置、环绕、异常处理增强。

静态代理

由程序员创建或由特定工具自动生成代理类源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。

  1. public interface Animals {
  2. void eat();
  3. void run();
  4. }
//众多实现子类之一
public class Dog implements Animals {

    public void eat() {
        System.out.println("狗吃");
    }

    public void run() {
        System.out.println("狗跑");
    }

}

在动物执行吃或者跑的方法前加上 发出命令 和 获得奖励(此类不适合曝光在大众面前,一般采用代理的方式执行)

package com.dongnaoedu.network.设计思想.代理;


/**
 * 代理类具体的执行逻辑
 */
public class AnimalsStaticProxy implements Animals {

    private Animals animals;

    public AnimalsStaticProxy(Animals animals) {
        this.animals = animals;
    }

    @Override
    public void eat() {
        before();
        animals.eat();
        after();

    }

    @Override
    public void run() {
        before();
        animals.run();
        after();
    }

    public void before(){
        System.out.println("主人发出命令");//前置
    }

    public void after(){
        System.out.println("获得奖励");//后置
    }

    public static void main(String[] args) {
        Animals animals = new AnimalsStaticProxy(new Dog());
        animals.eat();
        animals.run();
    }

}

image.png
但是静态代理有个缺点:

  1. 子类众多时,它们都不想曝光于大众,这样你使用静态代理就必须每个子类都要去实现一个xx代理类
  2. 当子类的方法很多时,你每个方法都要去加上前置或者后置增加,不灵活有点僵硬。

    动态代理:

    在运行期间为不同的类对象创建代理,增强功能。灵活扩展

    JDK动态代理

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

/**

  • 代理类具体的执行逻辑 */ public class AnimalsProxyInvocationHandler implements InvocationHandler {

    private Object target;//众多不愿意暴露的子类

    public AnimalsProxyInvocationHandler(Object target) {

     this.target = target;
    

    }

    public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {

     before();
     Object invoke = method.invoke(target,args);//返回执行方法的结果
     after();
     return invoke;
    

    }

    public void before(){

     System.out.println("主人发出命令");//前置
    

    }

    public void after(){

     System.out.println("获得奖励");//后置
    

    }

    public static void main(String[] args) {

     //目标类必须实现接口否则会抛出类转化异常
     Animals dogTarget = new Dog();
     //类加载器、代理类的接口数组(Dog类实现接口的数组)、代理业务类
     Animals proxy = (Animals)Proxy.newProxyInstance(dogTarget.getClass().getClassLoader(), dogTarget.getClass().getInterfaces(),
             new AnimalsProxyInvocationHandler(dogTarget));
     //重新生成一个子类进行接口方法的调用
     proxy.eat();
    

    }

}

需要知道的一点就是生成的代理对象Animals proxy = (Animals)Proxy.newProxyInstance(...)是运行期间存在我们JVM当中的,一般是美元符号+Proxy+数字如:$Proxy0
<a name="C26Do"></a>
#### 查看 Proxy 的 $ProxyX.class文件
方法一:在运行方法加上,这样在运行代码的时候就会在项目的根目录(或者指定目录)下生成 com.sun.proxy.$ProxyX.class 了,我们可以通过反编译来理解 Proxy 的处理过程。
```java
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

方法二:使用原生JDK生成的字节数组,拷贝生成到硬盘
注意:千万不要以中文来命名包名,否则方式二会提示文件找不到的错误,因为中文相对于resource解析后是加密的路径,不存在于我们磁盘中

 public static void main(String[] args) throws Exception{
        //方式一
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        Animals dogTarget = new Dog();
        //类加载器、代理类的接口数组(Dog类实现接口的数组)、代理业务类
        Animals proxy = (Animals)Proxy.newProxyInstance(dogTarget.getClass().getClassLoader(), dogTarget.getClass().getInterfaces(),
                new AnimalsProxyInvocationHandler(dogTarget));
        //重新生成一个子类进行接口方法的调用
        proxy.eat();
        //方式二
        ProxyUtils.generateClassFile(proxy.getClass().getName(),dogTarget.getClass().getInterfaces());
    }
package com.dongnaoedu.network.design.proxy;

import sun.misc.ProxyGenerator;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

public class ProxyUtils {

    /**
     * 将根据类信息 动态生成的二进制字节码保存到硬盘中,
     * @param proxyName 为动态生成的代理类的名称 $Proxy0
     * @param classes 需要生成动态代理类的类
     */
    public static void generateClassFile(String proxyName,Class<?>[] interfaces) throws IOException {
        // 根据类信息和提供的代理类名称,生成字节码
        byte[] classFile = ProxyGenerator.generateProxyClass(proxyName, interfaces);
        ProxyUtils.writeToFile(interfaces[0], classFile, proxyName);
    }

    public static void writeToFile(Class<?> interfaces, byte[] classFile, String proxyName) throws IOException {
        String path = interfaces.getResource(".").getPath()  + proxyName + ".class";
        System.out.println(path);
        // 保留到硬盘中  文件不存在
        File file = new File(path);
        try(FileOutputStream fos = new FileOutputStream(file)) {
            fos.write(classFile);
            fos.flush();
            System.out.println("代理类class文件写入成功");
        } catch (Exception e) {
            System.out.println("写文件错误");
            e.printStackTrace();
        }
    }

}

生成的代理文件:
image.png

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.sun.proxy;

import com.dongnaoedu.network.design.proxy.Animals;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy implements Animals {
    private static Method m1;
    private static Method m3;
    private static Method m4;
    private static Method m2;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void run() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void eat() throws  {
        try {
            super.h.invoke(this, m4, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m3 = Class.forName("com.dongnaoedu.network.design.proxy.Animals").getMethod("run");
            m4 = Class.forName("com.dongnaoedu.network.design.proxy.Animals").getMethod("eat");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

Cglib动态代理

地址:https://github.com/cglib/cglib/wiki
定义:一个高层次的java字节码生成和转换的api库,在运行期为类、接口生成动态代理对象。以达到不改动原类代码而实现功能增强的目的
介绍:Enhancer可能是CGLIB中最常用的一个类,和Java1.3动态代理中引入的Proxy类差不多(如果对Proxy不懂,可以参考这里)。和Proxy不同的是,Enhancer既能够代理普通的class,也能够代理接口。Enhancer创建一个被代理对象的子类并且拦截所有的方法调用(包括从Object中继承的toString和hashCode方法)。Enhancer不能够拦截final方法,例如Object.getClass()方法,这是由于Java final方法语义决定的。基于同样的道理,Enhancer也不能对fianl类进行代理操作。这也是Hibernate为什么不能持久化final class的原因。

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.2.6</version>
</dependency>

```java package com.dongnaoedu.network.design.proxy;

import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class AnimalsProxyMethodInterceptor implements MethodInterceptor {

private Object target;//目标对象  众多不愿意暴露的子类

public AnimalsProxyMethodInterceptor(Object target) {
    this.target = target;
}

public void before(){
    System.out.println("主人发出命令");//前置
}

public void after(){
    System.out.println("获得奖励");//后置
}

@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
    System.out.println("**************** " + method.getName());
    before();
    Object invoke = method.invoke(target,args);//返回执行方法的结果
    after();
    return invoke;
}

public static void main(String[] args) throws Exception{
    //对类生成代理
    Enhancer enhancer = new Enhancer();//类似Proxy类
    enhancer.setCallback(new AnimalsProxyMethodInterceptor(new Dog()));
    enhancer.setSuperclass(Dog.class);//也可以写父类
    Dog proxyAnimals = (Dog) enhancer.create();
    proxyAnimals.eat();

    Enhancer enhancer2 = new Enhancer();
    enhancer2.setCallback(new AnimalsProxyMethodInterceptor(new Dog()));
    enhancer.setInterfaces(new Class[]{Animals.class});//接口代理
    Animals proxyAnimals2 = (Animals) enhancer.create();
    proxyAnimals2.eat();
}

} ``` 可以参考我csdn的一片文章:https://blog.csdn.net/qq_40826106/article/details/104046518