目录
代理模式
静态代理
代理模式的场景
代理模式的两个简单场景
1、租房
2、结婚
代理模式角色分析
抽象角色:一般会使用接口或者抽象类来解决
真实角色:被代理的角色
代理角色:代理真实角色,代理真实角色后,我们一般会做一些附属操作
客户:访问代理对象的人
个人理解
个人对代理模式的理解:以租房为例
1、有个抽象类或者接口:Rent 有个抽象方法:租房
2、房东:房东要租房:实现这个接口 ,房东就可以租房了,(这我可以直接找房东租房)
3、中介:中介帮房东租房,所以中介也要实现接口或者抽象方法Rent ,中介帮房东租房,所以在中介的属性中有一个引用属性,房东,此外,中介在租房的过程中可以做租房的其他手续,比如:中介带你去看房,签订租赁合同,收中介费用
静态代理代码
Rent:
public interface Rent {
void rentHouse();
}
Host:
public class Host implements Rent {
@Override
public void rentHouse() {
System.out.println("房东出租房子");
}
}
HostProxy:
public class HouseProxy implements Rent {
private Host host = new Host();
@Override
public void rentHouse() {
seeHouse();
writeProtocol();
host.rentHouse();
receiveProxyMoney();
}
private void seeHouse() {
System.out.println("中介帶你去看房");
}
private void writeProtocol() {
System.out.println("签订租聘合同");
}
private void receiveProxyMoney() {
System.out.println("收取代理费用");
}
}
Customer
public class Customer {
public static void main(String[] args) {
// 客户找中介即可
HouseProxy proxy = new HouseProxy();
proxy.rentHouse();
}
}
代理模式的优点
1、可以使真实角色的操作更加纯粹,不用去关注一些公共的业务(房东什么都不用管,就可以租房)。
2、公共的业务也就交给代理角色!实现了业务的分工(中介租房还会可以做其他手续)。
3、公共业务发生拓展时,方便集中管理。
代理模式的缺点
一个真实的角色就会产生一个代理角色;代码量会翻倍,开发效率会变低。
使用代理模式的四大步骤
1、接口
2、真实角色
3、代理角色
4、客户端
代理模式场景:
公司给了一个任务,在实现某一个任务的前面增加一个日志,如果这个实现类有几个方法还比较好理解,那么如果实现的方法有n个呢,那么你是不是要去每个实现的方法中中写n行代码,修改原来的代码,代码量及其高,在七大原则中有一个原则:尽量不要去改变原有的代码,所以在不改变原有的代码的模式下给他做一个增强,那么使用代理模式就可以了
记住:改动原有的业务代码,在公司中是大忌
以上的模拟场景用Service和ServiceImpl来实现
静态代理可以用平常的代码就可以实现,而动态代理的话:底层都是用反射来实现的
动态代理
- 动态代理和静态代理的角色是一样的,都是抽象类或者接口,真实角色,代理角色,客户
- 动态代理的代理类是动态生成的,不是我们直接写好的
- 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
——基于接口----------JDK动态代理【我们在这里使用】
——基于类------------cglib
——Java字节码实现—Javasist
我们先来写一个基于JDK API动态代理来理解一下动态代理:这个主要是用到了一个InvocationHandler接口,这里需要注意的是,在这个handler重写了invoke的方法,这个方法是执行这个处理器需要真正执行的方法,我们在这个方法中传入我们被代理的接口然后参数即可,这个方法会在我们获取到我们根据这个handler动态得到的代理类后调用这个代理类的方法的时候调用,如果需要扩展,我们也是在这个XXXInvocationHandler中拓展。
动态代理代码
RentInvocationHandler :
// 动态代理底层使用了反射机制
// 用这个类,自动生成代理对象
// 该类的作用:
// 1、代理谁
// 2、生成代理类
// 3、调用代理程序的一些执行方法
public class RentInvocationHandler implements InvocationHandler {
// 被代理的接口
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
// 生成得到代理类
public Rent getProxy() {
return (Rent) 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);
receiveFree();
return result;
}
public void seeHouse() {
System.out.println("中介带你看房子");
}
public void receiveFree() {
System.out.println("中介收中介费");
}
}
Customer:
public class Consumer {
public static void main(String[] args) {
// 真实角色
Host host = new Host();
// 代理角色不存在,找他它的处理程序去动态生成代理角色
RentInvocationHandler proxyInvocationHandler = new RentInvocationHandler();
proxyInvocationHandler.setRent(host); // 设置要代理的对象
Rent proxy = proxyInvocationHandler.getProxy();
proxy.rentHouse();
}
}
结果:
接下来我们写一个万能的动态代理类
ProxyInvocationHandler:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 用这个类,自动生成代理对象
// 该类的作用:
// 1、代理谁
// 2、生成代理类
// 3、调用代理程序的一些执行方法
public class ProxyInvocationHandler implements InvocationHandler {
// 被代理的接口
private Object target;
public void setTarget(Object 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 {
Object result = method.invoke(target, args);
return result;
}
}
Customer:
public class Consumer {
public static void main(String[] args) {
// 真实角色
Host host = new Host();
// 代理角色不存在,找他它的处理程序去动态生成代理角色
ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler();
proxyInvocationHandler.setTarget(host);
Rent proxy = (Rent) proxyInvocationHandler.getProxy();
proxy.rentHouse();
}
}
结果:
使用动态代理模式的好处
- 可以使真实角色的操作更加纯粹,不用去关注一些公共的业务(房东什么都不用管,就可以租房)
- 公共的业务也就交给代理角色!实现了业务的分工(中介租房还会可以做其他手续) 公共业务发生拓展时,方便集中管理
- 一个动态代理类代理的是一个接口,一般就是对应的一类业务
- 一个动态代理类可以代理多个类,只要是实现了同一个接口即可
万能的动态代理工具类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler() {
}
public void setTarget(Object target) {
this.target = target;
}
public Object getInstance() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(target, args);
}
}
特定的动态代理
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MySecondInvocationHandler implements InvocationHandler {
private Rent rent;
public MySecondInvocationHandler() {
}
public void setRent(Rent rent) {
this.rent = rent;
}
public Rent getProxy() {
return (Rent) Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(rent, args);
}
}