一、代理模式
代理模式是我们工作中比较常用的设计模式之一了,主要用于隐藏具体实现类的实现细节或者对实现类的行为进行增强,即对具体实现的前后做些特殊逻辑。
既然说是代理,那就要对客户端隐藏真实实现,由代理来负责客户端的所有请求。当然,代理只是个代理,它不会完成实际的业务逻辑,而是一层皮而已,但是对于客户端来说,它必须表现得就是客户端需要的真实实现。
但是对于客户端来说,它必须表现得就是客户端需要的真实实现
:代理类和目标类需要实现相同的接口
代理模式根据实现方式的不同和原理的不同可分为静态代理模式和动态代理模式,两者各有优缺点。
总结来说:目标类和代理类实现了相同的接口,在代理类中依赖了目标类,代理类的方法中调用了目标类的方法,并做了一些增强性的工作。
二、不同的代理实现
2.1 静态代理
静态代理采用的方式就是我们手动的将这些行为换进去,然后让编译器帮我们编译,同时也就将字节码在原有类的基础上加入一些其他的东西或者替换原有的东西,产生一个新的与原有类接口相同却行为不同的类型
2.1.1 举个🌰
租赁行为接口
package proxy.staticproxy;
public interface Rent {
void rent();
}
目标类 : 房东类
完成出租房子的行为:房东出租房子一般会把房源给到中介,由中介帮忙出租。房东只是提供房源,其他的事情(找房客、看房、签合同等等)由中介完成
ackage proxy.staticproxy;
public class Houser implements Rent{
@Override
public void rent() {
System.out.println("房东提供房源");
}
}
代理类 : 中介类
完成出租房子的行为:中介获取到房东提供的房源,在房源的基础上完成找房客、看房、签合同等等行为才可以出租房子。
在出租房子的行为中,房东提供房源才是行为的基础,中介只是起到增强的行为。
package proxy.staticproxy;
public class ProxyRent implements Rent{
private Rent rent;
public ProxyRent(Rent rent) {
this.rent = rent;
}
@Override
public void rent() {
seeHouse();
rent.rent();
ding();
}
public void seeHouse(){
System.out.println("看房间");
}
public void ding(){
System.out.println("签订合同");
}
}
测试
package proxy.staticproxy;
public class Test {
public static void main(String[] args) {
Houser houser = new Houser();
ProxyRent proxyRent = new ProxyRent(houser);
proxyRent.rent();
}
}
静态代理是死的,不会在运行时动态创建,因为我们相当于在编译期,也就是你按下CTRL+S的那一刻,就给被代理的对象生成了一个不可动态改变的代理类
静态代理对于这种,被代理的对象很固定,我们只需要去代理一个类或者若干固定的类,数量不是太多的时候,可以使用,而且其实效果比动态代理更好,因为动态代理就是在运行期间动态生成代理类,所以需要消耗的时间会更久一点。
但是上面这个例子中中介是很多的,不可能一个中介创建一个类吧。所以我们需要动态的创建代理类
2.2 动态代理
动态代理指的是:在程序的执行过程中,使用jdk的反射机制,创建代理对象,并动态的指定代理的目标类
动态代理的实现方式常用有两种:
- 使用JDK代理
- 通过CDLIB代理
2.2.1 jdk动态代理
jdk动态代理是基于Java的反射机制实现的,使用jdk反射包下的Proxy和InvocationHandler实现代理对象的动态创建
(jdk动态代理要求目标对象必须实现接口)
2.2.2 举个🌰
租赁行为接口
package proxy.staticproxy;
public interface Rent {
void rent();
}
目标类 : 房东类
完成出租房子的行为:房东出租房子一般会把房源给到中介,由中介帮忙出租。房东只是提供房源,其他的事情(找房客、看房、签合同等等)由中介完成
ackage proxy.staticproxy;
public class Houser implements Rent{
@Override
public void rent() {
System.out.println("房东提供房源");
}
}
动态创建代理类生成器
package proxy.dynamicproxy;
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(ClassLoader loader, Class<?>[] interfaces,
InvocationHandler h) {
return Proxy.newProxyInstance(loader, interfaces, h);
}
// 使用反射,调用被代理类的方法 method.invoke(rent, objects)
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
seeHouse();
Object res = method.invoke(rent, objects);
ding();
return res;
}
public void seeHouse(){
System.out.println("看房子");
}
public void ding(){
System.out.println("签协议");
}
}
测试
package proxy.dynamicproxy;
public class Test {
public static void main(String[] args) {
//目标类
Houser houser = new Houser();
//动态代理类生成器
ProxyInvocationHandler handler = new ProxyInvocationHandler(houser);
//生成代理类
Rent proxy = (Rent) handler.getProxy(this.getClass().getClassLoader(),
rent.getClass().getInterfaces(),
handler);
//执行代理方法
proxy.rent();
}
}