代理模式

为什么要学习代理模式? 因为这就是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. 创建shell脚本文件

    简单来说脚本就是将需要执行的命令保存到文本中,按照顺序(由上往下执行),它是解释型的,不需要 编译 脚本格式 #!/bin/bash或者#!/bin/env bash开头 第一个shell脚本:hel ...

  2. Java Redis系列1 关系型数据库与非关系型数据库的优缺点及概念

    Java Redis系列1 关系型数据库与非关系型数据库的优缺点及概念 在学习redis之前我们先来学习两个概念,即什么是关系型数据库什么是非关系型数据库,二者的区别是什么,二者的关系又是什么? ** ...

  3. SpringBoot2 整合Ehcache组件,轻量级缓存管理

    本文源码:GitHub·点这里 || GitEE·点这里 一.Ehcache缓存简介 1.基础简介 EhCache是一个纯Java的进程内缓存框架,具有快速.上手简单等特点,是Hibernate中默认 ...

  4. C#LeetCode刷题之#13-罗马数字转整数(Roman to Integer)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3842 访问. 罗马数字包含以下七种字符: I, V, X, L, ...

  5. Spring Boot 2.x基础教程:使用集中式缓存Redis

    之前我们介绍了两种进程内缓存的用法,包括Spring Boot默认使用的ConcurrentMap缓存以及缓存框架EhCache.虽然EhCache已经能够适用很多应用场景,但是由于EhCache是进 ...

  6. dota2输入法无候选框?

    win10自带的微软拼音在dota2中不会显示候选框,或者说是选词框. 这种情况下只能选择其他输入法. 我选择的是搜狗输入法(此随笔添加时的最新版),在dota2中有选词框. 网上有些人说要改兼容性, ...

  7. 利用 Github Actions 自动更新 docfx 文档

    利用 Github Actions 自动更新 docfx 文档 Intro docfx 是微软出品一个 .NET API 文档框架,有一个理念是代码即文档,会根据项目代码自动生成 API 文档,即使没 ...

  8. 动态数组java实现

    数组是一种顺序存储的线性表,所有元素的内存地址是连续的. 动态数组相对于一般数组的优势是可以灵活地添加或删除元素.而一般数组则受限于固定的内存空间.只能有限的添加元素 动态数组(Dynamic Arr ...

  9. 关于Redis的工作模式

    1.哨兵模式 在redis3.0以前的版本要实现集群一般是借助哨兵sentinel工具来监控master节点的状态,如果master节点异常,则会做主从切换,将某一台slave作为master. 缺点 ...

  10. Storm与SparkStreaming对比

    Storm与SparkStreaming对比 ◆ Spark Streaming 批处理的性能比Storm高出几十倍.◆ Streaming采用小批量模式,Storm是一条消息一条消息的计算.◆ St ...