动态代理
jdk代理--基于接口代理
cglib--基于类代理
javassist --基于字节码
一个jdk动态代理类代理的是一个接口,一般归属于一个业务。在不改动源代码的同时可以很方便的低成本的进行加工附属改造。
jdk代理主要是通过java.lang.reflect 包中的 Proxy类 和 InvacationHandler接口,实现的。首先看下这两个类的源码。
InvacationHandler interface
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
只有一个invoke 方法。这个方法是处理代理实例并返回结果。在里面要用反射方法调用,method.invoke(Object obj ,Object[] args) 第一个参数就是要代理的接口类。第二个就是对应方法有关的参数。
回到源代码,第一个参数理论上就是要代理的对象,但是实际上并没有用到,第二个就是接口中对应的方法,第三个就是对应的参数。
其次看Proxy类
里面包含着一个重要也是常用的方法
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
获得一个对应代理类的实例。通常要用这个方法动态的获得代理实例。
使用jdk代理的步骤
1.创建一个实现接口InvocationHandler的类,它必须实现invoke方法
2.创建被代理的类以及接口
3.通过Proxy的静态方法
newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)创建一个代理
4.通过代理调用方法
实现代码:
真实角色(要被代理的对象):
package com.heaboy.proxyExcise.JDkProxy;
/**
* @Author:XK
* @Date: Created in 11:23 2022/2/19
* @Description:
**/
public class Host implements Rent {
@Override
public void rent() {
System.out.println("房东出租房子");
}
@Override
public void run() {
System.out.println("房东跑了");
}
}
抽象角色(要被代理的接口)
package com.heaboy.proxyExcise.JDkProxy;
/**
* @Author:XK
* @Date: Created in 11:20 2022/2/19
* @Description:
**/
public interface Rent {
public void rent();
public void run();
}
继承InvacationHanler并动态生成代理对象的角色
package com.heaboy.proxyExcise.JDkProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @Author:XK
* @Date: Created in 15:45 2022/2/19
* @Description:
**/
public class RentProxy implements InvocationHandler {
private Rent target;
public RentProxy(Rent target) {
this.target = target;
}
//动态生成代理对象
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
}
//处理实例的方法,并且加以附属操作
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
seeHouse();
Object result=method.invoke(target,args);
fare();
return result;
}
public void seeHouse(){
System.out.println("中介带你去看房");
}
public void fare(){
System.out.println("中介带你收费");
}
}
客户角色;调用代理
package com.heaboy.proxyExcise.JDkProxy;
/**
* @Author:XK
* @Date: Created in 15:52 2022/2/19
* @Description:
**/
public class client {
public static void main(String[] args) {
Host host = new Host();
RentProxy rentProxy = new RentProxy(host);
Rent proxy = (Rent)rentProxy.getProxy();
//proxy.rent();
proxy.run();
}
}