java设计模式6——代理模式
java设计模式6——代理模式
1、代理模式介绍:
1.1、为什么要学习代理模式?因为这就是Spring Aop的底层!(SpringAop 和 SpringMvc)
1.2、代理模式的分类:
- 静态代理
- 动态代理
1.3、代理模式关系图(以租房子为例)

2、静态代理
2.1、角色分析:
- 抽象角色:一般会使用接口或者抽象类来解决
- 真实角色:被代理的角色
- 代理客户:代理真实角色。代理真实角色后,我们一般会做一些附属的操作
- 客户:访问代理对象的人
2.2、例1(租房子演示)
2.2.1、抽象角色实现(房东抽象类)
package com.xgp.company.结构性模式.代理模式.静态代理.Demo1;
/**
- 租房
*/
public interface Rent {
void rent();
}
2.2.2、真实角色实现(房东的实现类)
package com.xgp.company.结构性模式.代理模式.静态代理.Demo1;
/**
- 房东
*/
public class Host implements Rent {
@Override
public void rent() {
System.out.println("房东要出租房子!");
}
}
2.2.3、不通过代理进行租房
package com.xgp.company.结构性模式.代理模式.静态代理.Demo1;
public class Client {
public static void main(String[] args) {
//直接找房东
Host host = new Host();
host.rent();
}
}
运行结果:
房东要出租房子!
2.2.4、弊端
- 在实际的生活场景中,房东可能只卖房,而不负责租房
- 如果要提高租房子的成功率,必然还需要一些其他的服务,如:看房、谈价钱、签合同等,而这些房东并不想参与,因此产生了中介,也就是代理。
2.2.5、代理出现
package com.xgp.company.结构性模式.代理模式.静态代理.Demo1;
public class Proxy implements Rent {
private Host host;
public Proxy() {
}
public Proxy(Host host) {
this.host = host;
}
@Override
public void rent() {
seeHouse();
host.rent();
fare();
hetong();
}
//看房
public void seeHouse() {
System.out.println("中介代理看房");
}
//收中介费
public void fare() {
System.out.println("收中介费");
}
public void hetong() {
System.out.println("签合同");
}
}
2.2.6、通过代理来租房子
package com.xgp.company.结构性模式.代理模式.静态代理.Demo1;
public class Client {
public static void main(String[] args) {
/* //直接找房东
Host host = new Host();
host.rent();*/
//通过代理去租房子
//房东要租房子
Host host = new Host();
//代理
//中介帮房东租房子,但是,中介一半都会有一些附属操作
Proxy proxy = new Proxy(host);
proxy.rent();
}
}
运行结果:
中介代理看房
房东要出租房子!
收中介费
签合同
2.3、分析:
代理模式的好处
- 可以使真实角色的操作更加纯粹,不用去关注一些公共的业务。
- 公共的业务交给了代理角色去完成,实现了业务的分工。
- 公共业务发生扩展的时候,方便集中管理。
缺点:
- 一个真实角色就会产生一个代理的角色,代码量翻倍,开发效率变低。
2.4、例1(增删改查业务的演示)
2.4.1、编写service的抽象类
package com.xgp.company.结构性模式.代理模式.静态代理.Demo2;
public interface UserService {
void add();
void del();
void update();
void query();
}
2.4.2、编写service的实现类
package com.xgp.company.结构性模式.代理模式.静态代理.Demo2;
/**
- 真实对象
*/
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("增加了一个用户");
}
@Override
public void del() {
System.out.println("删除了一个用户");
}
@Override
public void update() {
System.out.println("更新了一个用户");
}
@Override
public void query() {
System.out.println("查询了一个用户");
}
}
2.4.3、如果此时想不改变原有的代码,而增加方法日志打印的功能,此时代理诞生
package com.xgp.company.结构性模式.代理模式.静态代理.Demo2;
/**
- 代理角色,增加日志的功能
*/
public class UserServiceProxy implements UserService {
private UserService userService;
public void setUserService(UserService userService) {
this.userService = userService;
}
@Override
public void add() {
userService.add();
log("add");
}
@Override
public void del() {
userService.del();
log("del");
}
@Override
public void update() {
userService.update();
log("update");
}
@Override
public void query() {
userService.query();
log("query");
}
public void log(String msg) {
System.out.println("使用了" + msg + "方法!");
}
}
2.4.4、编写客户端类,使用service的方法,并打印日志
package com.xgp.company.结构性模式.代理模式.静态代理.Demo2;
public class Client {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
UserServiceProxy proxy = new UserServiceProxy();
proxy.setUserService(userService);
proxy.add();
proxy.del();
proxy.update();
proxy.query();
}
}
运行结果:
增加了一个用户
使用了add方法!
删除了一个用户
使用了del方法!
更新了一个用户
使用了update方法!
查询了一个用户
使用了query方法!
2.5、反思:在实际的业务中,横向开发的好处

可以保证原有代码的可行性,不会对软件原来的版本进行破坏,向过去兼容。
3、动态代理
3.1、动态代理的特点
- 动态代理和静态代理一样
- 动态代理的代理类是动态生成的,不是我们直接写的
3.2、动态代理实现方式的分类
- 基于接口——JDK动态代理(本节需要讲述的方式)
- 基于类:cglib
- java字节码实现:javasist
3.3、需要了解的两个类
- Proxy:代理类
- InvocationHandler:调用处理程序类
具体的使用参照java的api
3.4、例1——房东租房的例子
3.4.1、房东的接口和实现类不变
3.4.2、实现自动生成代理的类
package com.xgp.company.结构性模式.代理模式.动态代理.Demo1;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
- 等下我们会用这个类,自动生成代理类
*/
public class ProxyInvocationHandler implements InvocationHandler {
/**
- 被代理的接口
*/
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
/**
- 获得一个代理
- @return
*/
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this);
}
/**
- 处理代理实例,并放回结果
- @param proxy
- @param method
- @param args
- @return
- @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//用反射来执行方法
seeHouse(); //调用代理自身的方法
//动态代理的本质,就是使用反射机制来实现
Object result = method.invoke(rent, args);
fare();
hetong();
return result;
}
public void seeHouse() {
System.out.println("中介带看房子!");
}
//收中介费
public void fare() {
System.out.println("收中介费");
}
public void hetong() {
System.out.println("签合同");
}
}
3.4.3、实现客户端使用代理来租房子
package com.xgp.company.结构性模式.代理模式.动态代理.Demo1;
public class Client {
public static void main(String[] args) {
//真实角色
Host host = new Host();
//代理角色
ProxyInvocationHandler pih = new ProxyInvocationHandler();
//通过调用程序处理角色,来处理我们要调用的接口对象
pih.setRent(host);
//放回代理类
//这里的代理类就是动态生成的,我们并没有写他
Rent proxy = (Rent) pih.getProxy();
proxy.rent();
}
}
运行结果:
中介带看房子!
房东要出租房子!
收中介费
签合同
3.5、例2——增删改查的例子
3.5.1、先来实现一个万能的代理生成类
package com.xgp.company.结构性模式.代理模式.动态代理.Demo2;
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;
}
/**
- 获得一个代理
- @return
*/
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
/**
- 处理代理实例,并放回结果
- @param proxy
- @param method
- @param args
- @return
- @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//用反射来执行方法
//动态代理的本质,就是使用反射机制来实现
Object result = method.invoke(target, args);
log(method.getName());
return result;
}
public void log(String msg) {
System.out.println("使用了" + msg + "方法!");
}
}
也就是将上一个例子的具体实现类——房东类,替换成Object类
3.5.2、UserService的接口和实现类不变
3.5.3、编写客户端类使用代理调用增删改查方法
package com.xgp.company.结构性模式.代理模式.动态代理.Demo2;
public class Client {
public static void main(String[] args) {
//真实角色
UserService userService = new UserServiceImpl();
//代理角色
ProxyInvocationHandler pih = new ProxyInvocationHandler();
pih.setTarget(userService);
UserService proxy = (UserService) pih.getProxy();
proxy.add();
proxy.del();
proxy.update();
proxy.query();
}
}
运行结果:
增加了一个用户
使用了add方法!
删除了一个用户
使用了del方法!
更新了一个用户
使用了update方法!
查询了一个用户
使用了query方法!
3.6、弊端分析:
虽然使用动态代理能够节省代码量,并且实现静态代理的全部优点。但是,动态代理的核心是反射技术,通过反射技术调用方法效率较大,因此也可能影响系统效率。
3.7、动态代理的好处
一个动态代理的是一个接口,一般就是对应的一类业务。
java设计模式6——代理模式的更多相关文章
- Java设计模式之代理模式(静态代理和JDK、CGLib动态代理)以及应用场景
我做了个例子 ,需要可以下载源码:代理模式 1.前言: Spring 的AOP 面向切面编程,是通过动态代理实现的, 由两部分组成:(a) 如果有接口的话 通过 JDK 接口级别的代理 (b) 如果没 ...
- 夜话JAVA设计模式之代理模式(Proxy)
代理模式定义:为另一个对象提供一个替身或者占位符以控制对这个对象的访问.---<Head First 设计模式> 代理模式换句话说就是给某一个对象创建一个代理对象,由这个代理对象控制对原对 ...
- Java设计模式:代理模式(转)
代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.这里使用到编程中的一 ...
- Java 设计模式_代理模式(2016-08-19)
概念: 代理模式是对象的结构模式.代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用. 就是一个人或者机构代表另一个人或者机构采取行动.在一些情况下,一个客户不想或者不能够直接引用一 ...
- JAVA设计模式:代理模式&& 装饰模式区别
在前面学习了代理模式和装饰模式后,发现对两者之间有时候会混淆,因此对两者进行了区别和理解: 装饰模式你可以这样理解,就像糖一样,卖的时候商家大多要在外面包一层糖纸,其实原本还是糖. public in ...
- Java设计模式:代理模式(二)
承接上文 三.计数代理 计数代理的应用场景是:当客户程序需要在调用服务提供者对象的方法之前或之后执行日志或者计数等额外功能时,就可以用到技术代理模式.计数代理模式并不是把额外操作的代码直接添加到原服务 ...
- java设计模式之代理模式 ,以及和java 回调机制的区别
java 代理模式就是: 将自己要做的事交给别人去做(这个别人就是代理者,自己就是被代理者),为什么自己能做的要交给别人去做了?假如一个小学生小明,现在要写作业,但是又想玩游戏,他更想玩游戏,并且不想 ...
- Java设计模式之代理模式(Proxy)
前言: 最近在研究Retrofit开源框架的时候,其主要核心代码是通过注解标示参数,动态代理模式实现具体接口,反射机制进行参数解析,最终实现发送请求.其实之前在学习Xutils源码的时候,Xutils ...
- Java设计模式 之 代理模式
所谓的代理模式就是为其它类或对象提供一个代理以控制对这个对象的访问.那么常见的代理有远程代理,虚拟代理,保护代理,智能代理. 1. 远程代理:为一个不同地址空间的对象提供一个本地代理对象. 2. 虚拟 ...
随机推荐
- Spring Cloud Stream消息驱动@SendTo和消息降级
参考程序员DD大佬的文章,自己新建demo学习学习,由于需要消息回执,看到了@SendTo这个注解能够实现,下面开始学习demo,新建两个项目cloud-stream-consumer消费端 和 cl ...
- Salesforce LWC学习(十一) port 1717报错的处理
使用vs code开发lwc的步骤,通常为先创建项目(create project)然后授权一个org(authorize an org),授权以后我们通常便会download代码到本地或者Uploa ...
- vue 项目中运用到的插件 或者依赖安装
1.安装less ,less-load npm install less less-loader --save-dev 2.安装vux npm install vux --save npm insta ...
- 2018徐州现场赛A
题目链接:http://codeforces.com/gym/102012/problem/A 题目给出的算法跑出的数据是真的水 #include<iostream> #include&l ...
- Web测试中定位bug的方法
在web测试过程中,经常会遇到页面中内容或数据显示错误,甚至不显示,第一反应就是BUG,没错,确实是BUG.进一步了解这个BUG的问题出在那里,是测试人员需要掌握的,可以简单的使用浏览器自带开发者工具 ...
- Activiti邮件任务
Activiti邮件任务 作者:Jesai 会不会有那么一天,你会妒忌 Activiti有一种任务叫做邮件任务,顾名思义,就是流程办理到邮件任务的时候,系统就会自动的给你发送任务. Activiti所 ...
- Linux下利用Ant调用Jmeter脚本生成HTML测试报告
今天我们学习如何利用Ant调用Jmeter脚本,并将生成的 jtl 文件转换为 HTML 格式的测试报告. 准备工作 需要在Linux上提前安装好 JDK. Jmeter 和 Ant. 1,JDK(可 ...
- IDEA需要修改的配置
自动编译开关 忽略大小写开关 智能导包开关 如下图所示,将 自动导入不明确的结构 智能优化包 这两个选项勾上.那么有什么效果呢? 你在代码中,只要敲list,就会出现提示,自动导入java.util. ...
- CQBZOJ 【重庆市NOIP模拟赛】避难向导
题目描述 "特大新闻,特大新闻!全国爆发了一种极其可怕的病毒,已经开始在各个城市 中传播开来!全国陷入了巨大的危机!大量居民陷入恐慌,想要逃到其它城市以 避难!经调查显示,该病毒来自于C 市 ...
- 关于Xen
尝试了各种方法搭建xen,尝试过从xenserver入手,但似乎最近时间端不允许访问,感谢我的老师,叫我从kvm入手,暂时记下xen中种种的坑,以后有缘再战.欢迎交流