代理模式

为什么要学习代理模式? 因为这就是SpringAOP的底层!

1. 代理模式的分类

  • 静态代理
  • 动态代理
graph LR
id1[真实的人<br/>租房的人]
id2[代理角色<br/>中介]
id3[真实角色<br/>房东]
id4[共同的目标<br/>租房]

id1 --> id2
id2 --> id3
id2 --> id4
id3 --> id4

2. 静态代理

1. 角色分析

  • 抽象角色: 一般会使用接口或者抽象类来解决
  • 真实角色: 被代理的角色
  • 代理角色; 代理真实角色, 代理真实角色后, 我们一般会做一些附属操作
  • 客户: 访问代理对象的人

2. 代码步骤

  1. 接口
package com.wang.demo01;

//租房
public interface Rent { void rent();
}
  1. 真实角色
package com.wang.demo01;

//房东
public class Host implements Rent{ @Override
public void rent() {
System.out.println("房东要出租房子!");
}
}
  1. 代理角色
package com.wang.demo01;

public class Proxy implements Rent{

    private Host host;

    public Proxy() {

    }
public Proxy(Host host) {
this.host = host;
} @Override
public void rent() {
host.rent();
seeHouse();
fee();
contract();
} //看房
public void seeHouse() {
System.out.println("中介带你看房!");
} //收中介费
public void fee() {
System.out.println("收中介费!");
} //签租赁合同
public void contract() {
System.out.println("签合同!");
}
}
  1. 客户端访问代理角色
package com.wang.demo01;

public class Client {
public static void main(String[] args) {
//房东要租房子
Host host = new Host();
//代理, 中介要帮房东租房子, 代理角色一般会有一些附属操作
Proxy proxy = new Proxy(host);
//你不用面对房东,直接面对中介租房即可
proxy.rent();
}
}

3. 代理的好处

  • 可以使真实角色的操作更加纯粹, 不用去关注一些公共的业务!
  • 公共业务交给代理模式! 实现了业务的分工!
  • 公共业务发生拓展的时候, 方便集中管理!

缺点

  • 一个真实角色就会产生一个代理角色: 代码量会翻倍 --> 开发效率会变低

4. 进一步理解

package com.wang.demo02;

public interface UserService {
void add();
void delete();
void update();
void query();
}
package com.wang.demo02;

//真实对象
public class UserServiceImpl implements UserService{
@Override
public void add() {
System.out.println("增加了一个用户");
} @Override
public void delete() {
System.out.println("删除了一个用户");
} @Override
public void update() {
System.out.println("修改了一个用户");
} @Override
public void query() {
System.out.println("查询了一个用户");
}
}
package com.wang.demo02;

public class UserServiceProxy implements UserService{

    private UserServiceImpl userService;

    public void setUserService(UserServiceImpl userService) {
this.userService = userService;
} @Override
public void add() {
log("add");
userService.add();
} @Override
public void delete() {
log("delete");
userService.delete();
} @Override
public void update() {
log("update");
userService.update();
} @Override
public void query() {
log("query");
userService.query();
} //日志方法
public void log(String msg) {
System.out.println("[debug] " + "使用了" + msg + "方法");
}
}
package com.wang.demo02;

public class Client {
public static void main(String[] args) {
UserServiceImpl userService = new UserServiceImpl();
UserServiceProxy userServiceProxy = new UserServiceProxy();
userServiceProxy.setUserService(userService);
userServiceProxy.add();
}
}

在不破坏原有代码的情况下添加新的功能!

3. 动态代理

1. 角色分析

  • 动态代理和静态代理角色一样!

  • 动态代理的代理类是动态生成的, 不是我们直接写好的!

  • 动态代理分为两大类:

    • 基于接口的动态代理: JDK的动态代理
    • 基于类的动态代理: cglib
    • java字节码实现: javassist

2. 对动态代理的两个关键类的理解

需要了解两个类: Proxy 代理, InvocationHandler 调用处理程序

Proxy ==> 生成动态代理的实例

invoke ==> 返回动态代理的结果: 包含接口的方法以及代理中添加的方法

注意:

  • 代理类不是我们定义的类,而是Proxy创建的$proxy类

  • 通过使用Proxy.newProxyInstance返回得到的动态代理的实例会被处理成\(Proxy0,\)Proxy0在调用接口方法时会调用invoke方法!

3. 动态代理的实现

package com.wang.demo04;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; //我们会用这个类, 自动生成代理类
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 { log(method.getName());
//动态代理的本质, 就是使用反射机制实现
Object result = method.invoke(target, args); return result;
} public void log(String msg){
System.out.println("执行了" + msg + "方法");
} }
package com.wang.demo04;

import com.wang.demo02.UserService;
import com.wang.demo02.UserServiceImpl; public class Client {
public static void main(String[] args) { //真实角色
UserServiceImpl userService = new UserServiceImpl(); //代理角色,不存在
ProxyInvocationHandler pih = new ProxyInvocationHandler();
//设置要代理的对象
pih.setTarget(userService);
//动态生成代理类
UserService proxy = (UserService) pih.getProxy(); proxy.add();
}
}

4. 动态代理的好处

  • 可以使真实角色的操作更加纯粹, 不用去关注一些公共的业务!
  • 公共业务交给代理模式! 实现了业务的分工!
  • 公共业务发生拓展的时候, 方便集中管理!
  • 一个动态代理中代理的是一个接口, 一般就是对应的一类业务
  • 一个动态代理类可以代理多个类, 只要是实现了同一个接口即可

Spring-代理模式的更多相关文章

  1. Spring代理模式及AOP基本术语

    一.代理模式: 静态代理.动态代理 动态代理和静态代理区别?? 解析:静态代理需要手工编写代理类,代理类引用被代理对象. 动态代理是在内存中构建的,不需要手动编写代理类 代理的目的:是为了在原有的方法 ...

  2. Spring 代理模式及AOP基本术语

    一.代理模式: 静态代理.动态代理 动态代理和静态代理区别?? 解析:静态代理需要手工编写代理类,代理类引用被代理对象. 动态代理是在内存中构建的,不需要手动编写代理类 代理的目的:是为了在原有的方法 ...

  3. Spring代理模式(jdk动态代理模式)

    有动态代理和静态代理: 静态代理就是普通的Java继承调用方法. Spring有俩种动态代理模式:jdk动态代理模式 和 CGLIB动态代理 jdk动态代理模式: 代码实现: 房东出租房子的方法(继承 ...

  4. Spring代理模式(CGLIB动态代理模式)

    jdk动态代理和CGLIB动态代理 没什么太大的区别,CGLIB动态代理不需要接口,但是需要导入jar包. 房东出租房子的方法: package com.bjsxt.proxy2; public cl ...

  5. spring代理模式 service远程调用,插件执行

    最近,研究了一下平台远程调用的过程,和service层插件执行的原理,记录一下. 1.远程service调用过程 首先看一下类的继承结构 封装调用处理过程 封装service调用接口 封装servic ...

  6. SPRING代理模式

    1.静态代理 主题对象:Student public interface Student { public String add(); } 目标对象:RealStudent public class ...

  7. Spring AOP /代理模式/事务管理/读写分离/多数据源管理

    参考文章: http://www.cnblogs.com/MOBIN/p/5597215.html http://www.cnblogs.com/fenglie/articles/4097759.ht ...

  8. 代理模式及其在spring与struts2中的体现

    代理模式 代理模式有三个角色组成: 1.抽象主题角色:声明了真实主题和代理主题的共同接口. 2.代理主题角色:内部包含对真实主题的引用,并且提供和真实主题角色相同的接口. 3.真实主题角色:定义真实的 ...

  9. Spring框架_代理模式(静态代理,动态代理,cglib代理)

    共性问题: 1. 服务器启动报错,什么原因? * jar包缺少.jar包冲突 1) 先检查项目中是否缺少jar包引用 2) 服务器: 检查jar包有没有发布到服务器下:                 ...

  10. spring设计模式_代理模式

    代理模式应该是Spring核心设计模式之一了 先说下代理模式特性: 1.有代理人和被代理人 2.对于被代理的人来说,这件事情是一定要做的,但是我又不想做,所有就找代理人来做. 3.需要获取到被代理人的 ...

随机推荐

  1. java 模拟斗地主发牌洗牌

    一 模拟斗地主洗牌发牌 1.案例需求 按照斗地主的规则,完成洗牌发牌的动作. 具体规则: 1. 组装54张扑克牌 2. 将54张牌顺序打乱 3. 三个玩家参与游戏,三人交替摸牌,每人17张牌,最后三张 ...

  2. C++输出错误信息perror、strerror以及全局变量errno

    头文件:#include<stdio.h>函数:perror.strerror,全局变量:errno.使用方法: FILE *fp; if((fp = fopen("test.t ...

  3. Quartz.Net的基础使用方法,多任务执行继续扩展

    前一篇随笔讲了Quartz多任务的简单实现 Quartz.Net的基础使用方法,多任务执行 这一篇,来简单对前一篇进行一下简单的扩展 看了前一篇的代码会发现,每次新增一个任务还要去GetJobs方法里 ...

  4. 技术分享丨数据仓库的建模与ETL实践技巧

    摘要:如何搭建数据仓库,在这个过程中都应该遵循哪些方法和原则,项目实践中有哪些技巧. 一.数据仓库的“心脏” 首先来谈谈数据模型.模型是现实世界特征的模拟和抽象,比如地图.建筑设计沙盘,飞机模型等等. ...

  5. Ubuntu18.04 安装 Fabric & 使用 Fabric 测试网络

    前言: 本文介绍在 Ubuntu 18.04 中安装 Fabric, 并对 官方文档中的一个小案例(Using the Fabric test network)进行测试. 目的: 初步了解 Fabri ...

  6. dotnet cli

    前言 dotnet cli (Command-Line Interface) .net 源代码和二进制文件管理工具.需要安装 .NET Core SDK. 终端执行 dotnet --info 可以打 ...

  7. Flutter FlatButton 按钮基本各种用法

    Flutter中给我们预先定义好了一些按钮控件给我们用,常用的按钮如下 RaisedButton :凸起的按钮,其实就是Android中的Material Design风格的Button ,继承自Ma ...

  8. Mybatis Log plugin 破解!!!

    前言 今天重新装了IDEA2020,顺带重装了一些插件,毕竟这些插件都是习惯一直在用,其中一款就是Mybatis Log plugin,按照往常的思路,在IDEA插件市场搜索安装,艹,眼睛一瞟,竟然收 ...

  9. 全国大学生信息安全竞赛初赛writeup

    本文首发于“合天智汇”公众号 作者:Fortheone WEB Babyunserialize 扫目录发现了 www.zip 下载下来发现似曾相识 之前wmctf2020的webweb出了f3的反序列 ...

  10. JAVA虚拟机故障诊断总结

    一.JAVA运行时数据区               1.堆(-Xmx与-Xms):所有线程共享.  目的:用来存放对象实例.所有对象实例和数组都要在堆上分配内存.JAVA堆是垃圾收集器管理的主要区域 ...