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. 虚拟 ...
随机推荐
- SpringBoot2 整合 Zookeeper组件,管理架构中服务协调
本文源码:GitHub·点这里 || GitEE·点这里 一.Zookeeper基础简介 1.概念简介 Zookeeper是一个Apache开源的分布式的应用,为系统架构提供协调服务.从设计模式角度来 ...
- SpringBoot+Neo4j在社交电商中,讲述你是怎么被绑定为下线的
上两篇文章我们主要讲解了Neo4j的基本知识以及Neo4j的基本使用,这篇文章我们就以实例来深入的理解一下,我们以社交电商中的绑定关系为例,使用SpringBoot+Neo4j来实现. Neo4j文章 ...
- ArcEngine连接Oracle数据库
问题1: 最近写服务需要用ArcEngine连接Oracle数据库,以前连接数据库都会弹出一个窗体.然后填好之后就可以连接了,这样很麻烦. 代码如下: private bool ConnectToSd ...
- Java8 通关攻略
点赞+收藏 就学会系列,文章收录在 GitHub JavaEgg ,N线互联网开发必备技能兵器谱 Java8早在2014年3月就发布了,还不得全面了解下 本文是用我拙劣的英文和不要脸的这抄抄那抄抄,熬 ...
- Js字符串按数量分组
代码: function group(ss,step) { var r = []; function doGroup(s) { if (!s) return; r.push(s.substr(0, s ...
- mysql时间类型和格式转换
内容目录 简介mysql时间类型DATE_FORMAT()函数 简介 今天开发中,做一个功能需要对历史数据进行补充,相信大家也遇到过这样的情况,这个历史数据需要按月份和人的id进行区分,于是想到了my ...
- 递推 dp - 求有多少个序列符合题意
题目描述 小美有一个由n个元素组成的序列{a1,a2,a3,...,an},她想知道其中有多少个子序列{ap1,ap2,...,apm}(1 ≤ m ≤ n, 1 ≤ p1 < p2 , ...
- 百度DMA+小度App的蓝牙语音解决方案案例展示
前记 跟着百度也有一段时间了,经过一年多的努力,我们也做出了一些产品.下面就给大家秀一下我们做的产品.有类似需求的朋友可以多多交流. 智能语音耳机 这个是就是可以通过按键来调用小度app的运动 ...
- 解决jar包依赖冲突(idea)
在IDEA状态下查看项目依赖的关系 关系如下图 红色数据jar包冲突 在对应的依赖中出去去冲突依赖
- C#数字图像处理(十四)击中击不中变换 (Hit-miss)
击中击不中变换定义 击中击不中变换(HMT)需要两个结构元素B1和B2,合成一个结构元素对B=(B1,B2) 一个用于探测图像内部,作为击中部分;另一个用于探测图像外部,作为击不中部分.显然,B1和B ...