静态代理类:
- 由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
动态代理类:
- 在程序运行时,运用反射机制动态创建而成。
场景先举个例子:
假如你是一个大房东(被代理人),你有很多套房子想要出租,而你觉得找租客太麻烦,不愿意自己弄,因而你找一个人来代理你(代理人),帮打理这些东西,而这个人(代理人也就是中介)在帮你出租房屋的时候对你收取一些相应的中介费(对房屋出租的一些额外操作)。对于租客而言,中介就是房东,代理你做一些事情。
以上,就是一个代理的例子,而他为什么叫动态代理,“动态”两个字体现在什么地方?
我们可以这样想,如果你的每一套房子你都请一个代理人帮你打理,每当你想再出租一套房子的时候你得再请一个,这样你会请很多的代理人,花费高额的中介成本,这可以看作常说的“静态代理”。
但假如我们把所有的房子都交给一个中介来代理,让他在多套房子之间动态的切换身份,帮你应付每一个租客。这就是一个“动态代理”的过程。动态代理的一大特点就是编译阶段没有代理类在运行时才生成代理类。
房屋出租的操作
/**
*定义一个借口
**/
public interface RentHouse {
void rent();//房屋出租
void charge(String str);//出租费用收取
}
房东
public class HouseOwner implements RentHouse {
public void rent() {
System.out.println("I want to rent my house");
}
public void charge(String str) {
System.out.println("You get : " + str + " RMB HouseCharge.");
}
}
中介
public class DynamicProxy implements InvocationHandler {
// 这个就是我们要代理的真实对象,即房东
private Object subject;
// 构造方法,给我们要代理的真实对象赋初值
public DynamicProxy(Object subject) {
this.subject = subject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在代理真实对象前我们可以添加一些自己的操作,中介收取中介费
System.out.println("before "+method.getName()+" house");
System.out.println("Method:" + method.getName());
// 如果方法是 charge 则中介收取100元中介费
if (method.getName().equals("charge")) {
method.invoke(subject, args);
System.out.println("I will get 100 RMB ProxyCharge.");
} else {
// 当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
method.invoke(subject, args);
}
// 在代理真实对象后我们也可以添加一些自己的操作
System.out.println("after "+method.getName()+" house");
return null;
}
}
客人
public class Client {
public static void main(String[] args)
{
// 我们要代理的真实对象--房东
HouseOwner houseOwner = new HouseOwner();
// 我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的
InvocationHandler handler = new DynamicProxy(houseOwner);
/*
* 通过Proxy的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数
* 第一个参数 handler.getClass().getClassLoader() ,我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象
* 第二个参数realSubject.getClass().getInterfaces(),我们这里为代理对象提供的接口是真实对象所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了
* 第三个参数handler, 我们这里将这个代理对象关联到了上方的 InvocationHandler 这个对象上
*/
RentHouse rentHouse = (RentHouse) Proxy.newProxyInstance(handler.getClass().getClassLoader(), houseOwner
.getClass().getInterfaces(), handler);//一个动态代理类,中介
System.out.println(rentHouse.getClass().getName());
rentHouse.rent();
rentHouse.charge("10000");
}
}
输出结果
com.sun.proxy.$Proxy0
before rent house
Method:rent
I want to rent my house
after rent house
before charge house
Method:charge
You get : 10000 RMB HouseCharge.
I will get 100 RMB ProxyCharge.
after charge house
Process finished with exit code 0