前言
其实之前写过类似一篇了,重新具体的总结一下
代理模式
为什么要学习代理模式?因为这就是SpringAOP的底层!【SpringAOP 和 SpringMVC】面试必定
代理模式的分欸:
- 静态代理
- 动态代理
代理的原型:

静态代理
角色分析:
- 抽象角色:一般会用接口或者抽象类来解决(这里指的是外卖平台和餐厅的共同目标"赚钱")
- 真实角色:被代理的角色(厨师、餐厅)
- 代理角色:代理真实角色,代理真实角色后,通常会进行一些附属操作...(外卖平台)
- 客户:访问代理对象的人!(这里指的是要吃饭的人)
代理模式的好处:
- 可以使真实角色的操作更加纯粹!,不用去关注一些公共的业务
- 公共业务就交给了代理角色!实现了业务的分工!
- 公共业务发生扩展的时候,方便集中管理!
缺点:
- 一个真实角色就会产生一个代理角色,代码量翻倍~开发效率会变低
- 缺点解决的办法就是动态代理
代码步骤
- 接口
java
// 卖吃的(赚钱)
public interface Sell {
public void sell();
}
- 真实角色
java
// 厨师:真实角色
public class Chef implements Sell{
@Override
public void sell() {
System.out.println("cike_y真实厨师:快来我这里点吃的吧");
}
}
- 代理角色
java
// 少用继承(局限性很大)、多用组合的方式
public class proxy implements Sell{
@Override
public void sell() {
System.out.println("外卖平台开始代理厨师的话:");
chef.sell();//帮真实角色(厨师)代理他说的话
// 下面是外卖平台(中介代理)的附属操作
System.out.println("外卖平台(中介代理)开始附属以下操作了:\n");
SeeRider();
SendOrder();
GiveMoney();
TakeCommission();
TakeRiderFee();
}
// 组合
private Chef chef;
public proxy() {
}
public proxy(Chef chef) {
this.chef = chef;
}
// setProxy(){..} 没必要set注入
// 代理可以做一些附属的事情
public void SeeRider(){// 找骑手
System.out.println("帮你寻找骑手中......");
}
// 收取佣金
public void TakeCommission(){
System.out.println("外卖平台收取佣金");
}
// 骑手费用
public void TakeRiderFee(){
System.out.println("给骑手小费");
}
// 发送客户订单
public void SendOrder(){
System.out.println("发送客户订单");
}
// 给餐厅钱
public void GiveMoney(){
System.out.println("给餐厅钱");
}
}
- 客户端访问代理角色
java
public class Client {
public static void main(String[] args) {
// 想点这家餐厅做的菜
Chef chef = new Chef();
// 外卖平台,帮你通知厨师做菜,但是外卖平台(代理)会做一些附属操作
proxy proxy = new proxy(chef);
// 你不用面对厨师、直接找外卖平台即可!
proxy.sell();
}
}

加深理解
在一个增删改查的业务
- 接口类(公共调用的方法)
java
public interface UserService {
public void add();
public void delete();
public void update();
public void query();
}
- 真实角色(业务实现类)
java
public class UserServiceImpl {
public void add() {
System.out.println("添加用户");
}
public void delete() {
System.out.println("删除用户");
}
public void update() {
System.out.println("修改用户");
}
public void query() {
System.out.println("查询用户");
}
}
- 代理角色(代理真实角色的类&横向扩展附属操作)
java
public class UserServiceProxy implements UserService{
public UserServiceProxy(UserServiceImpl userServiceImpl) {
this.userServiceImpl = userServiceImpl;
}
public void setUserServiceImpl(UserServiceImpl userServiceImpl) {
this.userServiceImpl = userServiceImpl;
}
private UserServiceImpl userServiceImpl;
@Override
public void add() {
debug("add");
userServiceImpl.add();
}
@Override
public void delete() {
debug("delete");
userServiceImpl.delete();
}
@Override
public void update() {
debug("update");
userServiceImpl.update();
}
@Override
public void query() {
debug("query");
userServiceImpl.query();
}
// 日志方法:横向扩展增增删改查业务
public void debug(String msg){
System.out.println("debug:"+msg+"方法执行了");
}
}
- 客户端访问代理角色(客户端想实现真实角色的类,只能通过访问代理角色)
java
public class Client {
public static void main(String[] args) {
UserServiceImpl userServiceImpl = new UserServiceImpl();
UserServiceProxy userServiceProxy = new UserServiceProxy(userServiceImpl);
userServiceProxy.add();
userServiceProxy.delete();
userServiceProxy.update();
userServiceProxy.query();
}
}

聊聊AOP:

动态代理
动态代理的底层都是反射
- 动态代理和静态代理角色一样
- 动态代理的代理类是动态生成的,不是我们直接写好的
- 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
- 基于接口的---JDK的动态代理【我们在这里使用】
- 基于类:cglib
- java字节码实现:javasist
需要了解的两个类:Proxy:代理,InvocationHandler:调用处理程序
Proxy
Proxy提供了创建动态代理类和实例的静态方法。
InvocationHandler
- 代理实例的_调用处理程序_实现的_接口_
代理类写法
- 继承InvocationHandler接口
java
public class ProxyInvocationHandler implements InvocationHandler
- 引用真实角色的接口
java
private Sell sell;
- 获取真实角色的共同继承的接口
java
public Object getProxy(){
// 获取被代理接口的所有方法
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
sell.getClass().getInterfaces(), this);
}
- 处理代理实例,并且执行方法返回结果
java
// 处理代理实例,并返回结果
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(sell, args); // 执行一个方法,执行完毕之后会获取一个结果
return result;
}
代码步骤
真实角色(厨师)
java
// 厨师:真实角色
public class Chef implements Sell {
@Override
public void sell() {
System.out.println("cike_y真实厨师:这里是Demo04案例,快来我这里点吃的吧");
}
}
外卖平台和厨师都要赚钱(共同接口)
java
public interface Sell {
public void sell();
}
外卖平台(动态代理类)
java
//等我们会用这个类自动生成代理类!
public class ProxyInvocationHandler implements InvocationHandler{
// 被代理的接口,解耦性强
private Sell sell;
public void setSell(Sell sell) {
this.sell = sell;
}
// Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
// new Class<?>[] { Foo.class },
// handler);
// 获取真实角色和代理角色公共的接口
public Object getProxy(){
// 获取被代理接口的所有方法
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
sell.getClass().getInterfaces(), this);
}
// 处理代理实例,并返回结果
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在执行目标对象的方法之前,可以进行一些自定义操作
Start();
Object result = method.invoke(sell, args); // 执行一个方法,执行完毕之后会获取一个结果
// 在执行目标对象的方法之后,可以进行一些自定义操作
SeeRider();
SendOrder();
GiveMoney();
TakeCommission();
TakeRiderFee();
return result;
}
// 代理的附属操作
public void Start(){
System.out.println("这里是外卖平台,开始代理:");
}
// 代理可以做一些附属的事情
public void SeeRider(){// 找骑手
System.out.println("帮你寻找骑手中......");
}
// 收取佣金
public void TakeCommission(){
System.out.println("外卖平台收取佣金");
}
// 骑手费用
public void TakeRiderFee(){
System.out.println("给骑手小费");
}
// 发送客户订单
public void SendOrder(){
System.out.println("发送客户订单");
}
// 给餐厅钱
public void GiveMoney(){
System.out.println("给餐厅钱");
}
}
用户(要吃饭的人:面对外卖平台)
java
public class Client {
public static void main(String[] args) {
// 真实角色
Chef chef = new Chef();
// 代理角色
ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler();
// 要代理的对象:指的是真实角色,设置代理的真实角色对象
proxyInvocationHandler.setTarget(chef);
// 代理角色(已经代理了真实角色了)获取接口
Sell proxy = (Sell) proxyInvocationHandler.getProxy();
// 直接面对外卖平台,不用找厨师
proxy.sell();
}

万能的写法
只需要改变动态代理的对象为Object对象就可以了,因为Java 中Object 类是所有类的父类,也就是说Java 的所有类都继承了Object,子类可以使用Object 的所有方法。
java
public class ProxyInvocationHandler implements InvocationHandler {
// 要代理的接口
private Object target;
public void setTarget(Object target) {
this.target = target;
}
// 官方写法:
// Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
// new Class<?>[] { Foo.class },
// handler);
// 获取真实角色的公共接口
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
}
// 处理代理实例,并返回结果
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(target, args); // 执行方法,返回结果
return result;
}
}
其余的:真实角色(厨师)、接口(外卖平台和厨师的共同目标)、用户(吃饭的人)写法都不需要变。
动态代理的好处:
- 可以使真实角色的操作更加纯粹!,不用去关注一些公共的业务
- 公共业务就交给了代理角色!实现了业务的分工!
- 公共业务发生扩展的时候,方便集中管理!
- 一个动态代理类代理的是一个接口,一般就是对应的一类业务
- 一个动态代理类可以代理多个类,只要是实现了同一个接口即可
参考文档:
plain
JDK-api-1.8_google