静态代理
首先定义一个接口,声明一个方法,代表一类抽象角色(房屋出租)
//抽象角色,租房
public interface Rent {
public void rent();
}
房屋出租这个抽象角色,代表一类真实的角色,这里指房主
//真实角色,房东,出租房子
public class Host implements Rent{
public void rent(){
System.out.println("房屋出租");
}
}
代理角色,中介,代理房主出租房屋
//代理角色,中介
public class Proxy implements Rent{
private Host host;
public Proxy() {
}
public Proxy(Host host) {
this.host = host;
}
//租房
public void rent(){
seeHouse();
host.rent();
fare();
}
//收中介费
private void fare() {
System.out.println("收中介费");
}
//看房
private void seeHouse() {
System.out.println("带房客看房");
}
}
客户通过中介租到房子
//客户类,一般客户都会找代理
public class Client {
public static void main(String[] args) {
//房东租房
Host host = new Host();
//中介帮助房东租房
Proxy proxy = new Proxy(host);
//找中介
proxy.rent();
}
}
动态代理
动态代理代理接口Rent,即代理了一类抽象角色Rent,而不是上面静态代理中的真实角色host。内部通过反射机制,根据传入的真实角色host,动态生成对应的代理类。
package invocationHandler_test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyInvocationHandler implements InvocationHandler {
private Rent rent;
public void setRent(Rent rent){
this.rent = rent;
}
//生成代理类,第二个参数就是要代理的抽象角色(代表一类角色)
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
seeHouse();
//使用反射实现的
Object result = method.invoke(rent, args);
fare();
return result;
}
//看房
public void seeHouse(){
System.out.println("带房客看房");
}
//收中介费
public void fare(){
System.out.println("收中介费");
}
}
客户租房,传入host,动态的生成代理类进行代理
package invocationHandler_test;
public class Client {
public static void main(String[] args) {
//真实角色
Host host = new Host();
//代理实例的调用处理程序
ProxyInvocationHandler pih = new ProxyInvocationHandler();
pih.setRent(host);//放入真实角色
Rent proxy = (Rent) pih.getProxy();//动态生成代理类
proxy.rent();
}
}
动态代理和静态代理区别
静态代理与动态代理的区别主要在:
- 静态代理在编译时就已经实现,编译完成后代理类是一个实际的class文件
- 动态代理是在运行时动态生成的,即编译完成后没有实际的class文件,而是在运行时动态生成类字节码,并加载到JVM中
特点: - 动态代理对象不需要实现接口,但是要求目标对象必须实现接口,否则不能使用动态代理。(因为JDK代理需要用构造方法动态获取具体的接口信息,如果不实现接口的话,没法初始化)
参考:
https://mp.weixin.qq.com/s?__biz=Mzg2NTAzMTExNg==&mid=2247484130&idx=1&sn=73741a404f7736c02bcdf69f565fe094&scene=19#wechat_redirect
https://segmentfault.com/a/1190000011291179