定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
作用:**不改变原类的代码,而增强原类对象的功能,可选择前置、后置、环绕、异常处理增强。
静态代理
由程序员创建或由特定工具自动生成代理类源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
public interface Animals {
void eat();
void run();
}
//众多实现子类之一
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();
}
}
但是静态代理有个缺点:
- 子类众多时,它们都不想曝光于大众,这样你使用静态代理就必须每个子类都要去实现一个xx代理类
- 当子类的方法很多时,你每个方法都要去加上前置或者后置增加,不灵活有点僵硬。
动态代理:
在运行期间为不同的类对象创建代理,增强功能。灵活扩展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();
}
}
}
生成的代理文件:
//
// 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