JAVA设计模式之代理模式(Proxy)
这里只是简单的介绍下最基本的代理的使用。
代理,通俗点说 :就是一个人或者一个机构代表另一个人或者另一个机构采取行动。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之前起到中介的作用。
代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。
UML图

从上面的图我们能看到代理涉及的角色:
抽象对象角色:声明了目标对象和代理对象的共同接口,这样一来在任何可以使用目标对象的地方都可以使用代理对象。
目标对象角色:定义了代理对象所代表的目标对象。(也就是要代理的是谁)
代理对象角色:代理对象内部含有目标对象的引用,从而可以在任何时候操作目标对象;代理对象提供一个与目标对象相同的接口,以便可以在任何时候替代目标对象。代理对象通常在客户端调用传递给目标对象之前或之后,执行某个操作,而不是单纯地将调用传递给目标对象。
我们在这里演示一个房东,中介和客户之间的关系(中介就是代理)
1,我们需要一个抽象的对象角色:(接口)
public interface IRenter { public abstract void rent(); }2,我们需要的目标对象:(就是实现的接口的类)
public class Renter implements IRenter{ @Override public void rent() { System.out.println("我是房东,开始收费咯咯"); } }3,代理对象的角色(就是我们的代理)
我们需要用到这个Java中代理使用的类
Object o =Proxy.newProxyInstance(loader, interfaces, h)public class Client { @Test public void Test2(){ final Renter r =new Renter();//被代理的对象 //o是中介代理之后的对象 Object o =Proxy.newProxyInstance(Client.class.getClassLoader(), new Class[]{IRenter.class},new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //从这里开始就是开始拦截要控制的内容了,如if(method.getName.equals('rent')){将方法名为rent的函数,做出你想要的事情} // System.out.println("aaaa");//这里只是简单的每个方法之前输出 System.out.println("收点费用"); return method.invoke(r, args); //return method.invoke(要代理的对象, 参数传进来什么参数就放出什么参数,这里相当于全部放开); } } ); IRenter ir =(IRenter) o;//最后在使用的时候需要 将对象 强转为接口类型的 ir.rent(); } }
通过上面的简单介绍,能发现,一个代理类的所有方法或函数,都要经过代理之后,才会进行操作,指定操作的方法做我们想做的事情,没有指定的直接放行。
上面的只是一个简单的介绍例子,下面介绍一个在实际中的使用例子。
我们在连接数据库的时候,都是采用的链接池的方式,但是链接池里面的连接都是有限个的,所以我们需要每个用完之后就将其放回池中,但是单独去写一个函数将其放回池中,不太好用,所以,我们就将 con.close()关闭连接的时候,不去关,而是直接的放回池中,让其他的线程来调用,也就是需要拦截con里面的close方法。
所需要的三个角色:
1, 接口对象 connection接口
2,实现对象 Connection con=DriverManager.getConnection(url, user, password);//在进行连接的时候可以。
3,需要我们的代理类。
下面这是整个连接池的代码:
public class hibernateFactory2 { private static final int NUM=3; private static List<Connection> pool =new ArrayList<Connection>(); static{ //读取配置文件 Properties p =new Properties(); try { p.load(hibernateFactory.class.getClassLoader().getResourceAsStream("jdbc.properties")); //读取里面的值,一直修改配置文件即可 String driver=p.getProperty("driver"); String url=p.getProperty("url"); String user=p.getProperty("username"); String password=p.getProperty("password"); System.out.println(driver+url+user+password); Class.forName(driver); for(int i=0;i<NUM;i++){ final Connection con=DriverManager.getConnection(url, user, password); //采用动态代理开始进行对connection接口实现代理,对con.close,实现换回去 Object o =Proxy.newProxyInstance(hibernateFactory2.class.getClassLoader(), new Class[]{Connection.class}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if(method.getName().equals("close")){ //拦截close方法 pool.add((Connection)(proxy));//将连接还回池 System.out.println("换回来了。。。"); return null; } return method.invoke(con, args);//其余的全部放行 } }); pool.add((Connection)o); } // System.out.println("初始化完毕"+con); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //下面是获取连接。 public static synchronized Connection getCon() throws Exception{ if(pool.size()<=0){ System.out.println("pool中已经没有连接"); return getCon() ; } System.out.println("使用一个。。"); return pool.remove(0); //两种方法都是可以的 // while(pool.size()<=0){ // System.out.println("池中已经乜有连接"); // Thread.sleep(1000); // } // return pool.remove(0); // } }}在上面的基础上,我们写了一个通用的版本
public class proxyUtils { public static Object getProxy(final Object srcobj){ Object o = Proxy.newProxyInstance(proxyUtils.class.getClassLoader(), srcobj.getClass().getInterfaces(), //这句可以修改 new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("被拦击了。。。。");//这里采用拦截 return method.invoke(srcobj, args);//返回值我们也可以进行一些列的操作 } } ); return o; } } 但是我们在调用的这个工具的时候,必须传进来一个实例对象,也就是实现了的类如 IA 为接口 A 为实现类
A a =new A();
IA ia =(IA)proxyUtils.getProxy(a);
通过ia 的对象调用方法就可以。
上面方法的另一种实现形式
public class proxyUtils2 implements InvocationHandler{ private Object srcobj; public proxyUtils2(Object srcobj) { this.srcobj=srcobj; } public static Object getProxy(final Object srcobj){ Object o = Proxy.newProxyInstance(proxyUtils2.class.getClassLoader(), srcobj.getClass().getInterfaces(), //这句可以修改 ,在不知道的情况下,这种方法最好 new proxyUtils2(srcobj)); return o; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("在这里采用拦截"); Object obj =method.invoke(srcobj, args);//在这里我们还可以进行对返回的值进行操作,这也是代理带来的好处 return obj; } }上面的这些都是采用代理设计模式实现的,其实 代理模式就相当于一个秘书,能帮你做你想做的事情。
代理应用方面(从别人哪里看到的)
代理模式的应用形式
(1)远程代理(Remote Proxy) -可以隐藏一个对象存在于不同地址空间的事实。也使得客户端可以访问在远程机器上的对象,远程机器可能具有更好的计算性能与处理速度,可以快速响应并处理客户端请求。
(2)虚拟代理(Virtual Proxy) – 允许内存开销较大的对象在需要的时候创建。只有我们真正需要这个对象的时候才创建。
(3)写入时复制代理(Copy-On-Write Proxy) – 用来控制对象的复制,方法是延迟对象的复制,直到客户真的需要为止。是虚拟代理的一个变体。
(4)保护代理(Protection (Access)Proxy) – 为不同的客户提供不同级别的目标对象访问权限
(5)缓存代理(Cache Proxy) – 为开销大的运算结果提供暂时存储,它允许多个客户共享结果,以减少计算或网络延迟。
(6)防火墙代理(Firewall Proxy) – 控制网络资源的访问,保护主题免于恶意客户的侵害。
(7)同步代理(SynchronizationProxy) – 在多线程的情况下为主题提供安全的访问。
(8)智能引用代理(Smart ReferenceProxy) - 当一个对象被引用时,提供一些额外的操作,比如将对此对象调用的次数记录下来等。
(9)复杂隐藏代理(Complexity HidingProxy) – 用来隐藏一个类的复杂集合的复杂度,并进行访问控制。有时候也称为外观代理(Façade Proxy),这不难理解。复杂隐藏代理和外观模式是不一样的,因为代理控制访问,而外观模式是不一样的,因为代理控制访问,而外观模式只提供另一组接口。
相关热词:
本站内容来源于网络,如有侵权请与我们联系,我们会及时删除,我们深感抱歉!
注:本站所有信息仅供用于网络技术学习参考,学习中请遵循相关法律法规!
本文地址: https://v30.fanwenzhu.com/jiaob/java/10231.shtml
相关文章
热门TAG
win10 ecshop 主机 阿里云 解决 配置 C# C++ 解析 SQL语句 命令 Go语言 方法 CSS3 HTML5 CSS win7 MSSQL 服务器配置 IIS7.5 IIS7 IIS6 IIS CentOS 7 Linux oracle数据库 oracle phpcms discuz discuz教程最新文章
-
Fitness fitness){ /*double X1=m
时间:2021-01-21
-
所以这里也是需要注意的
时间:2021-01-21
-
hadoop上传文件成果实例代
时间:2021-01-15
-
hadoop负责按key值将map的输
时间:2021-01-15
-
记得勾选springconfig.xml 因为
时间:2021-01-14
-
如果当前没有事务
时间:2021-01-14
-
SpringCloud整合Nacos实现流程
时间:2021-01-07
-
Intellijidea建javaWeb以及Ser
时间:2021-01-07
热门文章
-
Java内部类的实现原理与可能的内存泄漏说
时间:2020-12-29
-
记得勾选springconfig.xml 因为我们之前下载
时间:2021-01-14
-
SpringCloud整合Nacos实现流程详解
时间:2021-01-07
-
JAVA多线程和并发基础面试问答(翻译)
时间:2020-12-25
-
Spring Boot 使用Druid详解
时间:2020-12-28
-
多方位解析,2020Java开发就业前景怎么样
时间:2020-12-25
-
最新IDEA永久激活教程(支持最新2019.2版本
时间:2020-12-25
-
Fitness fitness){ /*double X1=min+0.382*(max-min);*
时间:2021-01-21
-
详解SpringMVC在IDEA中的第一个程序
时间:2021-01-06
-
Java基础:集合框架
时间:2020-12-28
