目录
代理模式说明
静态代理
租房动作-接口
房东实现租房动作-实现类
中介代理房东处理租房-实现类
静态代理示例-中介出租房屋-Demo
执行结果
优缺点
动态代理
用户服务方法-接口
实现用户服务功能-实现类
代理工具类
动态代理示例-代理类代理用户实现类执行相应方法-Demo
执行结果
优缺点
动静态代理的区别
通过代理模式,我们可以抽取出核心业务和辅助业务,避免程序冗余许多重复的辅助业务代码。
package com.example.sgg.gof.proxy.staticproxy;
/**
* 租房
* Created by 奔跑的蜗牛 on 2022/5/19 0019.
* 每天学习一点点,每天进步一点点
*/
public interface Rent {
void rent();
}
package com.example.sgg.gof.proxy.staticproxy;
/**
* 房东
* Created by 奔跑的蜗牛 on 2022/5/19 0019.
* 每天学习一点点,每天进步一点点
*/
public class Landlord implements Rent {
@Override
public void rent() {
System.out.println("(房东)出租房子");
}
}
package com.example.sgg.gof.proxy.staticproxy;
/**
* 中介
* Created by 奔跑的蜗牛 on 2022/5/19 0019.
* 每天学习一点点,每天进步一点点
*/
public class MiddleMan implements Rent {
private Landlord landlord;
public MiddleMan(Landlord landlord) {
this.landlord = landlord;
}
@Override
public void rent() {
seeHouse();
talkPrice();
/**
* 拥有真实角色的功能
*/
landlord.rent();
sign();
}
/**
* 中介自带能力(公共业务,可扩展)
*/
private void seeHouse() {
System.out.println("(中介)带租客看房子");
}
/**
* 中介自带能力(公共业务,可扩展)
*/
private void talkPrice() {
System.out.println("(中介)租客跟中介讲价格");
}
/**
* 中介自带能力(公共业务,可扩展)
*/
private void sign() {
System.out.println("(中介)租客跟中介房屋租赁签合同");
}
}
package com.example.sgg.gof.proxy.staticproxy;
/**
* 静态代理示例(代理模式)
* Created by 奔跑的蜗牛 on 2022/5/19 0019.
* 每天学习一点点,每天进步一点点
*/
public class StaticProxyDemo {
public static void main(String[] args) {
System.out.println("房东自己出租");
Landlord landlord = new Landlord();
landlord.rent();
System.out.println("房东自己出租成功");
System.out.println("-----------------------------------");
System.out.println("中介代理房东出租");
Rent middleMan = new MiddleMan(landlord);
middleMan.rent();
System.out.println("中介代理房东出租成功");
}
}
房东自己出租
(房东)出租房子
房东自己出租成功
-----------------------------------
中介代理房东出租
(中介)带租客看房子
(中介)租客跟中介讲价格
(房东)出租房子
(中介)租客跟中介房屋租赁签合同
中介代理房东出租成功
Process finished with exit code 0
优点:
可以使真实角色的操作更加纯粹,不用去关注一些公共的业务(比如看房、签合同)
公共业务都交给代理角色,实现了业务的分工。
公共业务发生扩展的时候,方便集中管理。
缺点:
一个真实角色就会产生一个代理角色,代码量会翻倍,开发效率会降低。(从代码的角度来理解,创建中介对象的时候会传入一个房东对象,体现出了静态代理)
动态代理中的各个角色和静态代理是一致的。但是动态代理的代理类是动态生成的,不是我们直接写好的。
动态代理分为两大类:基于接口的动态代理和基于类的动态代理。主要实现方式如下:
基于接口:JDK动态代理
基于类:cglib
Java字节码实现:JAVAsist
动态代理的Java实现:
动态代理中两个重要的类和接口:Proxy(类)和InvocationHandler(接口)
1、InvocationHandler接口里面只有一个invoke()方法,该方法是proxy代理实例的调用处理程序。每一个proxy代理实例都有一个关联的调用处理程序;代理实例调用方法时,方法调用被编码分派到调用处理程序的invoke方法。
package com.example.sgg.gof.proxy.dynamicproxy;
/**
* 用户服务接口
* Created by 奔跑的蜗牛 on 2022/5/19 0019.
* 每天学习一点点,每天进步一点点
*/
public interface UserService {
void add();
void del();
void edit();
void list();
}
package com.example.sgg.gof.proxy.dynamicproxy;
/**
* 用户操作实现类
* Created by 奔跑的蜗牛 on 2022/5/19 0019.
* 每天学习一点点,每天进步一点点
*/
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("新增");
}
@Override
public void del() {
System.out.println("删除");
}
@Override
public void edit() {
System.out.println("编辑");
}
@Override
public void list() {
System.out.println("查询列表");
}
}
package com.example.sgg.gof.proxy.dynamicproxy;
import java.lang.reflect.Proxy;
/**
* 代理工具类,使用饿汉式单例
* 动态代理的体现:
* 通过Proxy的静态方法Proxy.newProxyInstance()来动态生成代理对象,而不是直接写好的。
* 对于方法调用,代理对象调用接口中的方法时,是将方法分派到调用处理器InvocationHandler的invoke()方法。
* 个人理解:
* 1、代理模式主要体现于代理将被代理的功能执行以外,提供了其他公共操作
* 2、无需像静态代理那样,对于每个真实角色都要写一个代理角色,避免重复代码
* Created by 奔跑的蜗牛 on 2022/5/19 0019.
* 每天学习一点点,每天进步一点点
*/
public class ProxyUtil {
private static ProxyUtil proxyUtil = new ProxyUtil();
private ProxyUtil() {
}
public static ProxyUtil getInstance() {
return proxyUtil;
}
/**
* 动态获取代理对象
*
* @param target 被代理对象
* @return
*/
public Object getProxy(Object target) {
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), (proxy, method, args) -> {
System.out.println("进入代理");
//关键点:就是在处理真实角色的功能外,包装了自己的公共处理逻辑,
//例如可以做:耗时,QPS,过滤,返回结果转换等操作
System.out.println("before invoke... operation of User");
Object invoke = method.invoke(target, args);
System.out.println("after invoke... operation of User");
System.out.println("代理处理完毕");
System.out.println("------------------------");
return invoke;
});
}
}
package com.example.sgg.gof.proxy.dynamicproxy;
/**
* 动态代理示例
* Created by 奔跑的蜗牛 on 2022/5/19 0019.
* 每天学习一点点,每天进步一点点
*/
public class DynamicProxyDemo {
public static void main(String[] args) {
UserService proxy = (UserService) ProxyUtil.getInstance().getProxy(new UserServiceImpl());
proxy.add();
proxy.del();
proxy.edit();
proxy.list();
}
}
进入代理
before invoke... operation of User
新增
after invoke... operation of User
代理处理完毕
------------------------
进入代理
before invoke... operation of User
删除
after invoke... operation of User
代理处理完毕
------------------------
进入代理
before invoke... operation of User
编辑
after invoke... operation of User
代理处理完毕
------------------------
进入代理
before invoke... operation of User
查询列表
after invoke... operation of User
代理处理完毕
------------------------
Process finished with exit code 0
动态代理的好处:
一个动态代理类代理的是一个接口,接口对应的是某一类业务,比如:房屋租赁业务。
一个动态代理类可以代理多个类,这些类实现同一个接口即可。
关于上面两点形象地解释:静态代理中,一个中介和一个房东是绑定的,相当于所有的房子都是一对一服务,这肯定是不现实的。动态代理中,一个房屋中介可以管理一大片的房东,因为这些房东都有出租房子的需求,代码层面就是都实现了租房的接口,所以中介可以管理所有这些房东,只要他的资金允许的话。这就很能理解动态代理的好处了
静态代理:一个代理只能服务于一种类型的对象,当有1000个业务时,需要1000个静态代理,不利于业务的扩展。
动态代理:一个代理类可以服务于所有的业务对象。
动态代理和静态代理相比较,最大的好处就是接口中声明的所有的方法都被转移到一个集中的方法中去处理,就是invocke()方法.这样在接口中声明的方法比较多的情况下我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。