大家好,我是
方圆
,小小的代理模式
一、 到底啥是代理模式?
用官方的话说,代理模式就是为目标对象提供另外一种访问方式,通过访问代理对象来间接访问目标对象。
我们来打个比方,简单点儿描述,比如我是房东,我要出租房屋,以前呢我直接租给住户,这样就是没有代理。但是现在我觉得我直接找客户出租房屋很麻烦,所以我就把房子交给中介,让中介帮我出租房子,我只管提供房子,中介帮我做带客户看房啊、收费等其他事物,这样,房东有了代理,这就是代理模式。
从这也能看出代理模式的一点好处,让房东专注于提供房子,其他事物由代理做,反映到程序中,就是,能让service层专注于提供服务,采用代理模式来实现其他事物,在不改变service层代码的情况下,提供了其他的功能。
二、静态代理模式
我们还是拿租房这个简单的例子来讲解
这是一个接口,房东实现这个接口,来提供租房子的业务
//租房
public interface Rent {
void RentHouse();
}
这个是房东类,在程序中就位于service层
//房东
public class Host implements Rent{
public void RentHouse() {
System.out.println("房东出租房屋给客户");
}
}
//我是代理,房屋中介
public class Proxy implements Rent{
private Host host;
public void setHost(Host host) {
this.host = host;
}
public void RentHouse() {
host.RentHouse();
}
}
这个就是客户类
//客户,要租房子的人
public class Client {
public static void main(String[] args) {
//在没有中介的时候,直接找房东租房
Host host = new Host();
host.RentHouse();
}
}
,房东直接租房子给客户。
下面,房东要找代理了。
public class Client {
public static void main(String[] args) {
//在没有中介的时候,直接找房东租房
Host host = new Host();
//这里是一个代理
Proxy proxy = new Proxy();
proxy.setHost(host);//房东把房子交给中介
//中介代替房东出租房屋,调用出租房的方法
//理论上还是房东出租给客户房屋,只不过这件事情被中介给做了
proxy.RentHouse();
}
}
我们这里没有用房东直接调用租房的方法,而是中介调用,同样实现了租房的功能,这样就实现了静态代理模式。
我们这里总结一下代理模式的好处
- 可以让service层专注于实现自己的业务,也就是房东只专注于提供房子,中介负责向客户出租和一些细枝末节的事情,我们同样可以在中介代码中,添加一下其他方法,并不影响房东的代码
- 要对业务就行扩展时,可修改代理的代码进行添加,而不需要修改service层源码
但是缺点也显而易见,静态嘛,不够灵活,代码冗余,一个service就需要一个代理,使代码翻倍。
为了解决这个缺点就出现了动态代理
三、动态代理模式
我们同样还是需要以上的Rent接口,和Host类
但是这次我们需要创建一个动态代理的类,ProxyInvocationHandler
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyInvocationHandler implements InvocationHandler {
//这个了实现了 InvocationHandler 接口
//每个代理的实例需要实现这个接口,从而来调用处理程序的实现
//invoke handler:翻译为中文就是调用处理程序
//我们需要实现租房子的这个接口,所以定义一个变量
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
//生成代理类的方法
public Object getProxy(){
//newProxyInstance() 创建代理实例方法
// 这个方法中,第一个参数为Invocation类的类加载器
//第二个参数,为要让代理实现的类的接口,也就是要实现租房子的接口
//第三个参数,是Invocation类本身
Object proxyInstance = Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(), this);
return proxyInstance;
}
//这个invoke方法,官方介绍中说:
//每一个代理实例Proxy都由一个关联的调用处理程序invoke,
//当在代理实例上调用方法时,方法调用将被编码并分配到其调用处理程序的invoke方法
//也就是说,当用代理调用方法的时候,这个invoke方法就会帮代理实现方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//在这里,invoke会帮助Proxy代理实例来实现方法
//其中参数 method就是要实现的方法
//方法调用invoke(rent,args)来返回结果
//其中参数rent是要被实现方法的接口,args默认填写
Object result = method.invoke(rent, args);
return result;
}
}
下面我们就用客户类来实现一下这个动态代理
public class Client {
public static void main(String[] args) {
//这里还是有一个房东准备要出租房子
Host host = new Host();
//创建ProxyInvocationHandler对象,用该对象的方法getProxy()方法创建代理实例
//并且该对象实现了InvocationHandler接口,就由了调用处理程序实现的功能,也就是invoke()方法
ProxyInvocationHandler handler = new ProxyInvocationHandler();
handler.setRent(host); //这里把房东传值给handler中的rent对象,也就是房东把房子交给中介
//利用handler对象,调用其中我们写好的getProxy方法,来实例代理,也就是中介
Rent proxy = (Rent) handler.getProxy();
//这里中介就帮房东出租房子了,也就实现了我们的代理模式
proxy.RentHouse();
}
}
动态代理解决了静态代理代码冗余的缺点
如果我们将动态代理类中的代码进行修改
将其中这段代码改为
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
如下
private Object object;
public void setObject(Object object) {
this.object = object;
}
那么,这样它就成了一个万能的代理,能传入任何类型的接口,那么他就什么都能代理了。
四、 cglib动态代理代码示例
用cglib我们需要导包,如下
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.12</version>
</dependency>
cglib动态代理与JDK动态代理的区别:cglib无需强制实现接口,其生成的代理类是被代理类的子类
我们创建一个需要被代理的类Rent
public class Rent {
public void rentHouse(){
System.out.println("出租房屋");
}
}
随后我们创建cglib动态代理,实现的是MethodInterceptor接口
import java.lang.reflect.Method;
public class RentCglib implements MethodInterceptor {
//被代理的对象
private Object service;
//注入被代理的对象
public void setService(Object service) {
this.service = service;
}
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//可以在这里写上增加的功能
System.out.println("代理带房客看房");
return method.invoke(service, objects);
}
}
最后我们写一个测试类,进行测试
import net.sf.cglib.proxy.Enhancer;
public class Test {
public static void main(String[] args) {
//创建租房服务
Rent rent = new Rent();
//注入租房的类
RentCglib rentCglib = new RentCglib();
rentCglib.setService(rent);
//创建增强器,用来创建动态代理实例
Enhancer enhancer = new Enhancer();
//注入动态代理要代理的类
enhancer.setSuperclass(rent.getClass());
//设置回调
enhancer.setCallback(rentCglib);
//创建动态代理实例
Rent rentService = (Rent) enhancer.create();
rentService.rentHouse();
}
}
输出结果如下
参考文献
经过一次修改,可读性比之前好了,但是还需要自己写出来才能掌握