代理
代理是指通过代理对象来代替对真实对象(real object)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。就相当于客户租房,房东没时间带客户看房,于是出租中介,中介去带客户看房租房。
1. 静态代理
元素组成
接口:定义行为和规范
被代理类:是目标对象
代理类:进行功能增强
1.1 静态代理实现
接口:
/**
* 接口
*/
public interface IHouseServer {
String address(String address);
}
目标类:
/**
* 房东类为目标类
*/
public class Landlord implements IHouseServer{
@Override
public String address(String address) {
System.out.println("我有一个房子要出租,它的地址是:"+address);
return null;
}
}
代理类:
/**
* 中介类为代理类
*/
public class Intermediary implements IHouseServer{
private Landlord landlord;
//获取被代理的目标
public Intermediary(Landlord landlord) {
this.landlord = landlord;
}
@Override
public String address(String address) {
//增强操作
System.out.println("与租户进行联系,并对租房者介绍房子");
//目标操作
landlord.address(address);
//增强操作
System.out.println("我需要收取一个月中介费");
return null;
}
}
1.2 静态代理存在的问题
- 不利于代码拓展,接口中新建方法,每个实现类都要去添加方法
- 代理对象需要创建好多,设计比较麻烦
2. 动态代理
2.1jak动态代理
接口:
/**
* 接口
*/
public interface IHouseServer {
String address(String address);
}
目标类:
/**
* 房东类为目标类
*/
public class Landlord implements IHouseServer{
@Override
public String address(String address) {
System.out.println("我有一个房子要出租,它的地址是:"+address);
return null;
}
}
动态生成代理及调用:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class TestjdkAgent {
public static void main(String[] args) {
IHouseServer proxy = (IHouseServer) Proxy.newProxyInstance(TestjdkAgent.class.getClassLoader(), Landlord.class.getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("与租户进行联系,并对租房者介绍房子"); //功能增强
Object ret = method.invoke(new Landlord(),args);
System.out.println("我要收取一个月的中介费"); //功能增强
return ret;
}
}
);
proxy.address("房子的地址是xx市,某某区");
}
}
以上动态代理的实现完成
-
Proxy:代理实例,可以通过newProxyInstance创建代理实例
- getClassLoader类加载器,可以通过任意一个类进行获取
- Class[],目标类所实现的接口
- InvocationHandler:方法拦截器,可以在里面实现方法(功能增强)
-
Method:通过反射的方式执行目标方法
-
args:参数数组
字节码生成:
import sun.misc.ProxyGenerator;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class TestjdkAgent {
public static void main(String[] args) throws Exception {
IHouseServer proxy = (IHouseServer) Proxy.newProxyInstance(Landlord.class.getClassLoader(), Landlord.class.getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("与租户进行联系,并对租房者介绍房子");
Object ret = method.invoke(new Landlord(),args);
saveProClass("D:\\Code\\javaCode\\ProxyDemo\\src\\");
return ret;
}
}
);
proxy.address("房子的地址是xx市,某某区");
}
/**
* 使用来生成字节码
* @param path
*/
private static void saveProClass(String path) throws Exception {
byte[] $proxy1s = ProxyGenerator.generateProxyClass("$Proxy1",Landlord.class.getInterfaces());
FileOutputStream out = new FileOutputStream(new File(path+"$Proxy1.class"));
out.write($proxy1s);
if(out != null){
out.flush();
out.close();
}
}
}
生成的代码字节码反编译
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy1 extends Proxy implements IHouseServer {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
public $Proxy1(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 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 String address(String var1) throws {
try {
return (String)super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
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"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("IHouseServer").getMethod("address", Class.forName("java.lang.String"));
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
- 文字说明:
- 通过实现接口,获取到接口里面的方法
- 通过Proxy创建代理类实例
- 通过反射机制,获取到一个个的方法对象
- 调用InvocationHandler接口中的invoke方法,从而实现业务的增强
2.2CGLIB动态代理
接口:
package org.example;
public interface IHouseServer {
String address(String address);
}
目标类:
package org.example;
public class Landlord implements IHouseServer{
@Override
public String address(String address) {
System.out.println("我有一个房子要出租,它的地址是:"+address);
return null;
}
}
调用及生成目标代理类:
package org.example;
import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
//TIP To <b>Run</b> code, press <shortcut actionId="Run"/> or
// click the <icon src="AllIcons.Actions.Execute"/> icon in the gutter.
public class Main {
public static void main(String[] args) {
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"D:\\Code\\javaCode\\Cglib_Proxy\\src\\main\\java\\org\\example\\");
//使用CGLIB框架生成目标类的子类(代理类)实现增强
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Landlord.class);
//
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("与租户进行联系,并对租房者介绍房子");
Object ret = methodProxy.invokeSuper(o,objects);
System.out.println("我要收取一个月的中介费");
return ret;
}
});
Landlord iHouseServer = (Landlord)enhancer.create();
iHouseServer.address("房子的地址是xx市,某某区");
}
}
- 文字说明
- 通过继承的方式去获取到目标对象的方法
- 通过传递方法拦截器MethodInterceptor实现方法拦截,在里面做具体增强
- 调用生成的代理类对象具体执行重写的save方法,直接去调用方法拦截器里面的intercept方法
- 前后加上增强操作,从而实现了不修改代码实现业务增强
代理类型 | 实现机制 | 回调方式 | 使用场景 | 效率 |
---|---|---|---|---|
JDK动态代理 | 通过实现接口,通过反射机制获取到接口里面的方法,并且自定义InvocationHandler接口,实现方法拦截 | 调用 invoke 方法实现增强 | 目标类有接口实现 | 1.8高于CGLIB |
CGLIB动态代理 | 继承机制,通过继承重写目标方法,使用Methodlnterceptor 调用父类的目标方法从而实现代理 | 调用interceptor方法 | 不能使用final修饰的类和方法 | 第一次调用生成字节码比较耗时间,多次调用性能还行 |
学习链接:06-cglib 动态代理_哔哩哔哩_bilibili
| 1.8高于CGLIB |
| CGLIB动态代理 | 继承机制,通过继承重写目标方法,使用Methodlnterceptor 调用父类的目标方法从而实现代理 | 调用interceptor方法 | 不能使用final修饰的类和方法 | 第一次调用生成字节码比较耗时间,多次调用性能还行 |