Java常见设计模式之代理模式
指由一个代理主题来操作真实主题,真实主题执行具体的业务操作,而代理主题负责其它相关业务的处理。比如生活中的通过代理访问网络,客户通过网络代理连接网络(具体业务),由代理服务器完成用户权限和访问限制等与上网相关的其他操作(相关业务)。代理的思想在我们日常生活中无处不在。下面我通过一个简单的代码先大致了解一下代理的相关内。
示例代码如下:
package com.yonyou.test; /**
* 创建一个上网的接口
* @author 小浩
* @创建日期 2015-4-6
*/
public interface Network {
//用户真正的上网需求
void browse();
}
package com.yonyou.test; /**
* 真正的上网需求类,实现Network接口
* @author 小浩
* @创建日期 2015-4-6
*/
public class Real implements Network{ @Override
public void browse() {
System.out.println("您好,当前用户正在上网操作~~~");
} }
package com.yonyou.test; /**
* 创建一个代理接口
* @author 小浩
* @创建日期 2015-4-6
*/
public class Proxy implements Network{
Network network=null;
//初始化被代理对象
public Proxy(Network network){
this.network=network;
}
//模式权限检查的操作
public void check(){
// 模拟权限检查
System.out.println("您好,我们正在检查当前用户是否有上网的权限...");
} @Override
public void browse() {
//增强操作,模拟权限检查
check();
//用户真正的操作
network.browse();
} }
package com.yonyou.test; /**
* TreeSet测试类
* @author 小浩
* @创建日期 2015-4-3
*/
public class Test{
public static void main(String[] args) {
//创建代理类
Network network=new Proxy(new Real());
network.browse();
}
}
一般在哪些地方需要使用代理:
1 创建目标对象的开销比较大,而且在当前程序中,还有可能使用不到目标对象的全部方法
2 需要对目标对象进行增强处理
下面对常见的代理方式进行讲解。
1、静态代理(static proxy)
因为静态代理比较简单,下面我们就直接上例子:
package com.xiaohao.proxystatic; /** 定义电脑的通用接口 */
public interface Computer {
//定义电脑开机的接口
public void power();
}
package com.xiaohao.proxystatic; public class ComputerProxy implements Computer{ private Computer computer; public ComputerProxy(Computer computer){
this.computer=computer;
} @Override
public void power() {
//增强处理的方法,before
System.out.println("您好,系统正在加载中,请稍后.............");
//调用相应的原来的方法
computer.power();
//增强处理的方法,after
System.out.println("恭喜您,您已经成功开机,Congratulation~~~~~~~"); } }
package com.xiaohao.proxystatic; public class Hp implements Computer{ @Override
public void power() {
System.out.println("您好,欢迎使用惠普电脑~~~~~"); } }
package com.xiaohao.proxystatic; public class Lenovo implements Computer{ @Override
public void power() {
System.out.println("您好,欢迎您使用联想电脑~~~~~~~~"); } }
package com.xiaohao.proxystatic; public class Test { public static void main(String[] args) {
//创建惠普电脑对象
Hp hp=new Hp(); //创建联想电脑对象
Lenovo lenovo=new Lenovo(); //创建电脑的代理类,使相应的电脑的方法得到相应的加强
ComputerProxy computerProxyHp=new ComputerProxy(hp);
ComputerProxy computerProxyLenovo=new ComputerProxy(lenovo); computerProxyHp.power(); System.out.println("-------------------------------------------------------------------"); computerProxyLenovo.power(); System.out.println("-------------------------------------------------------------------");
} }
2、动态代理(dynamic proxy)
观察代码可以发现每一个代理类只能为一个接口服务,这样一来程序开发中必然会产生过多的代理,而且,所有的代理操作除了调用的方法不一样之外,其他的操作都一样,则此时肯定是重复代码。解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成。常见的动态代理有两种方式,一种为jdk动态代理,一种为cglib动态代理。下面我们分别来介绍一下它们。
JDK动态代理:
package com.xiaohao.proxydynamic; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; public class ComputerProxy implements InvocationHandler{ //创建被代理的对象
private Object computer; //绑定需要代理的对象
public Object bind(Computer computer){
this.computer=computer;
return Proxy.newProxyInstance(computer.getClass().getClassLoader(),
computer.getClass().getInterfaces()
,this);
} @Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//增强处理的方法,before
System.out.println("您好,系统正在加载中,请稍后.............");
//调用相应的原来的方法
Object result=method.invoke(computer,args);
//增强处理的方法,after
System.out.println("恭喜您,您已经成功开机,Congratulation~~~~~~~"); return result;
}
}
package com.xiaohao.proxydynamic; public class Test { public static void main(String[] args) {
//创建惠普电脑对象
Hp hp=new Hp(); //创建联想电脑对象
Lenovo lenovo=new Lenovo(); //创建电脑的代理类,使相应的电脑的方法得到相应的加强
ComputerProxy computerProxy=new ComputerProxy(); Computer computer=(Computer) computerProxy.bind(hp); computer.power(); System.out.println("-------------------------------------------------------------------"); computer=(Computer) computerProxy.bind(lenovo); computer.power(); System.out.println("-------------------------------------------------------------------");
} }
对于jdk动态代理而言,我们需要被代理的目标类实现相应的接口。对于jdk动态代理的原理的讲解可以参考:
http://www.cnblogs.com/xiohao/p/4397359.html
cglib动态代理:
针对于jdk动态代理需要在被代理类实现相应的接口,但是针对于某些没有实现指定接口的类,就显得无能为力了。
这时我们可以使用第三方插件cglib,来实现对目标对象的增强处理。(在使用的过程中需要导入cglib的相关包)。
具体的使用格式请看下面的内容吧。
package com.xiaohao.proxycglib; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy; //import org.aopalliance.intercept.MethodInterceptor;
//import org.aopalliance.intercept.MethodInvocation; public class ComputerProxy implements MethodInterceptor{ //创建被代理对象
private Object computer; public Object bind(Object computer){
this.computer=computer;
Enhancer enhancer=new Enhancer();
//设置要代理的类,使代理类作为被代理类的父类
enhancer.setSuperclass(this.computer.getClass());
//回调相应的方法
enhancer.setCallback(this);
//创建相应的代理对象,并返回相应的代理对象
return enhancer.create(); } // 回调方法
@Override
public Object intercept(Object arg0, Method arg1, Object[] arg2,
MethodProxy arg3) throws Throwable {
System.out.println("您好,系统正在加载中,请稍后.............");
arg3.invokeSuper(arg0,arg2);
System.out.println("恭喜您,您已经成功开机,Congratulation~~~~~~~");
return null;
} }
package com.xiaohao.proxycglib; public class Test { public static void main(String[] args) { //创建被代理对象
Hp hp=new Hp();
//创建被代理对象
Lenovo lenovo=new Lenovo(); ComputerProxy computerProxy=new ComputerProxy(); //绑定相应的目标代理类
hp=(Hp) computerProxy.bind(hp);
lenovo=(Lenovo) computerProxy.bind(lenovo); hp.power(); System.out.println("-------------------------------------------------------------------"); lenovo.power(); System.out.println("-------------------------------------------------------------------");
} }
下面是Spring整合cglib后的一种使用方式,原理差不多,感兴趣的可以简单的看一下:
package com.xiaohao.proxycgli; import java.lang.reflect.Method; import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy; //import org.aopalliance.intercept.MethodInterceptor;
//import org.aopalliance.intercept.MethodInvocation; public class ComputerProxy implements MethodInterceptor{ @Override
public Object intercept(Object arg0, Method arg1, Object[] arg2,
MethodProxy arg3) throws Throwable {
//增强处理的方法,before
System.out.println("您好,系统正在加载中,请稍后.............");
//调用相应的原来的方法
Object result=arg3.invokeSuper(arg0, arg2);
//增强处理的方法,after
System.out.println("恭喜您,您已经成功开机,Congratulation~~~~~~~");
return result;
} // @Override
// public Object invoke(MethodInvocation arg0) throws Throwable {
// //增强处理的方法,before
// System.out.println("您好,系统正在加载中,请稍后.............");
// //调用相应的原来的方法
// Object result=arg0.proceed();
// //增强处理的方法,after
// System.out.println("恭喜您,您已经成功开机,Congratulation~~~~~~~");
// return result;
// } }
Java常见设计模式之代理模式的更多相关文章
- Java基础-设计模式之-代理模式Proxy
代理模式是对象的结构模式.代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用. 代理模式是常用的Java 设计模式,它的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理 ...
- Java常见设计模式之工厂模式
工厂模式在我们日常的应用中应当算是比较广泛的一种设计模式了.今天让我们一起来学习一下,工厂的设计模式. 工厂模式在<Java与模式>中分为三类: 1)简单工厂模式(Simple F ...
- 基于JAVA的设计模式之代理模式
概念 王宝强有一个经纪人叫宋喆,这个经纪人很吊,可以代理王宝强做一系列的事情,与粉丝活动.王宝强的微博维护.安排王宝强的行程以及什么什么等等.如果王宝强一个人做岂不是累死.通过这个代理人为王宝强节省了 ...
- Java设计模式之代理模式(静态代理和JDK、CGLib动态代理)以及应用场景
我做了个例子 ,需要可以下载源码:代理模式 1.前言: Spring 的AOP 面向切面编程,是通过动态代理实现的, 由两部分组成:(a) 如果有接口的话 通过 JDK 接口级别的代理 (b) 如果没 ...
- 夜话JAVA设计模式之代理模式(Proxy)
代理模式定义:为另一个对象提供一个替身或者占位符以控制对这个对象的访问.---<Head First 设计模式> 代理模式换句话说就是给某一个对象创建一个代理对象,由这个代理对象控制对原对 ...
- Java设计模式:代理模式(转)
代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.这里使用到编程中的一 ...
- java设计模式6——代理模式
java设计模式6--代理模式 1.代理模式介绍: 1.1.为什么要学习代理模式?因为这就是Spring Aop的底层!(SpringAop 和 SpringMvc) 1.2.代理模式的分类: 静态代 ...
- C#设计模式(13)——代理模式(Proxy Pattern)
一.引言 在软件开发过程中,有些对象有时候会由于网络或其他的障碍,以至于不能够或者不能直接访问到这些对象,如果直接访问对象给系统带来不必要的复杂性,这时候可以在客户端和目标对象之间增加一层中间层,让代 ...
- Java 反射 设计模式 动态代理机制详解 [ 转载 ]
Java 反射 设计模式 动态代理机制详解 [ 转载 ] @author 亦山 原文链接:http://blog.csdn.net/luanlouis/article/details/24589193 ...
随机推荐
- Java语言实现简单FTP软件------>上传下载管理模块的实现(十一)
1.上传本地文件或文件夹到远程FTP服务器端的功能. 当用户在本地文件列表中选择想要上传的文件后,点击上传按钮,将本机上指定的文件上传到FTP服务器当前展现的目录,下图为上传子模块流程图 选择好要上传 ...
- spring属性注入方式
一.使用有参构造注入属性 配置文件 constructor-arg标签是需注入属性的名字 User类 生成了User的有参构造函数 测试类 结果 打印出了name属性的值 二.使用set方法注入属性 ...
- python+NLTK 自然语言学习处理八:分类文本一
从这一章开始将进入到关键部分:模式识别.这一章主要解决下面几个问题 1 怎样才能识别出语言数据中明显用于分类的特性 2 怎样才能构建用于自动执行语言处理任务的语言模型 3 从这些模型中我们可以学到那些 ...
- java基础入门之数组循环初始化
/* Name:数组循环化 Power by Stuart Date:2015-4-23 */public class ArrayTest02{ public static void main (St ...
- ABAP--关于字符串String到XString XString to String转换代码
转自http://guanhuaing.iteye.com/blog/1498891 代码如下 report zrich_0001. data: s type string, h(1) type x, ...
- Docker alpine 设置东八时区
FROM alpine:3.8 RUN echo 'http://mirrors.ustc.edu.cn/alpine/v3.5/main' > /etc/apk/repositories &a ...
- leetcode 901. Online Stock Span
Write a class StockSpanner which collects daily price quotes for some stock, and returns the span of ...
- 【三】MongoDB文档的CURD操作
一.插入文档 使用insert方法插入文档到一个集合中,如果集合不存在创建集合,有以下几种方法: db.collection.insertOne({}):(v3.2 new) #插入一个文档到集合中 ...
- zabbix实现mysql数据库的监控(三)
上面一章“zabbix实现mysql数据库的监控(二)”使用MPM来监控mysql,但是遇到安装问题始终解决不了,这里改用percona-monitoring-plugins进行zabbxi上监控my ...
- HDFS常见问题
在HDFS里面,data node上的块大小默认是64MB(或者是128MB或256MB) 问题: 为什么64MB(或128MB或256MB)是最优选择? 为什么不能远少于64MB(或128MB或25 ...