博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
代理模式(Proxy Pattern)
阅读量:5824 次
发布时间:2019-06-18

本文共 10266 字,大约阅读时间需要 34 分钟。

代理模式:为另一个对象提供一个替身或占位符以控制对这个对象的访问。

 

一般代理模式类图:

 

远程代理:Java RMI

RMI:远程方法调用,提供客户辅助对象和服务辅助对象,为客户辅助对象创建和服务对象相同的方法。RMI的好处在于不必亲自写任何网络或I/O代码。客户程序调用远程方法(真正的服务)就和在运行在客户自己本地JVM上对对象进行正常方法调用一样。

RMI的查找服务可以用来寻找和访问远程对象。

 

RMI调用模型: 

 外部观察RMI过程:

1.运行服务器,服务器实现类会去实例化一个服务的实例,并将这个服务注册到RMI registry。注册之后,这个服务就可以供客户调用了。

2.运行客户端,客户端通过查找服务(lookup service),根据服务的名字,找到对应的服务。

3.现在在客户端就可以调用远程服务器的方法了。

在外部观察RMI的过程,并不能知道其实是代理在背后起作用。

 

内部观察RMI过程:

1.服务器实例化服务实例的同时,实例化一个RMI Skeleton代理和RMI Stub代理

2.当客户端通过查找服务,找到该服务,服务器将Stub通过网络传给客户,此时是二进制流,客户端需反序列成Stub

3.客户调用客户对象的方法会调用Stub的同名方法,Stub代理打包调用信息,通过网络转给Skeleton,Skeleton把信息解包,找出被调用的方法(以及方法在哪个对象内),然后调用真正的服务对象上的真正方法

4.服务对象上的方法被调用,将结果返回给Skeleton

5.Skeleton把方法返回信息打包,然后通过网络转给Stub

6.Stub将信息解包,返回给客户对象

 

一个简单的RMI例子:

服务器端:

public interface MyRemote extends Remote {//Remote接口是jdk提供的一个接口    public String sayHello() throws RemoteException;}public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote {//实现UnicastRemoteObject是创建远程对象的最容易方法,由jdk提供                                               protected MyRemoteImpl() throws RemoteException {        super();        // TODO Auto-generated constructor stub    }    @Override    public String sayHello() throws RemoteException {        return "Server says, 'Hey'";    }        public static void main(String[] args) {        // TODO Auto-generated method stub        try {            MyRemote service = new MyRemoteImpl();            Registry registry = LocateRegistry.createRegistry(1099);//端口号1099            registry.bind("RemoteHello", service);//注册服务对象,服务名字为RemoteHello        } catch(Exception e) {            e.printStackTrace();        }    }}

客户端:

public class Client {    public static void main(String[] args) {        // TODO Auto-generated method stub        try {            MyRemote service = (MyRemote) Naming.lookup("rmi://127.0.0.1:1099/RemoteHello");//127.0.0.1代表本机,RemoteHello是服务的名字                        String s = service.sayHello();//在客户端调用远程对象的方法,返回一个String            System.out.println(s);将方法返回值打印出来        } catch(Exception e) {            e.printStackTrace();        }            }}

测试结果:

一个小问题:为了在网络传输,远程方法的返回值都必须是可序列化的,所以需要实现Serializable接口,例子中的返回值是String,所以没有问题,如果是自定义的对象,那么需要实现Serializable接口才能正常运行。

 

RMI类图模型:

 

 

 

虚拟代理:

 虚拟代理作为创建开销大的对象的代表。虚拟代理经常直到我们真正需要一个对象的时候才创建它。当对象在创建前和创建中,由虚拟代理来扮演对象的替身。对象创建后,代理就会将请求直接委托给对象。

 

现在有一个应用是从网站取得图像,然后显示出来,限制在于带宽和网络负载,下载需要一些时间,但是在等待图像加载的时候,应该显示一些东西。我们不希望等待图像的时候整个应用被挂起,一旦加载完成,刚才显示的东西应该消失,图像显示出来。

 

设计类图:

public class ImageComponent extends JComponent {    private Icon icon;        public ImageComponent(Icon icon) {        this.icon = icon;    }        public void setIcon(Icon icon) {        this.icon = icon;    }        public void paintComponent(Graphics g) {        super.paintComponent(g);        int w = icon.getIconWidth();        int h = icon.getIconHeight();        int x = (800 - w)/2;        int y = (600 - h)/2;        icon.paintIcon(this, g, x, y);    }}public class ImageProxy implements Icon {    ImageIcon imageIcon;    URL imageURL;    Thread retrievalThread;    boolean retrieving = false;        public ImageProxy(URL url) {        imageURL = url;    }        @Override    public void paintIcon(Component c, Graphics g, int x, int y) {        if(imageIcon != null) {//如果已经加载出来,即imageIcon实例化了            imageIcon.paintIcon(c, g, x, y);//将请求转给真正的对象        } else {            g.drawString("Loading, please wait...", x+300, y+190);//否则显示一个提示字符串            if(!retrieving) {//这个变量的目的是只开一个线程去实例化真正的对象                retrieving = true;                retrievalThread = new Thread(new Runnable() {//如果未加载出来,开一个新线程加载,避免程序被挂起                    @Override                    public void run() {                        try {                            imageIcon = new ImageIcon(imageURL, "CD Cover");                            c.repaint();                        } catch(Exception e) {                            e.printStackTrace();                        }                                            }                                    });                retrievalThread.start();            }        }    }    @Override    public int getIconWidth() {        if(imageIcon != null) {            return imageIcon.getIconWidth();        } else {            return 800;        }    }    @Override    public int getIconHeight() {        if(imageIcon != null) {            return imageIcon.getIconHeight();        } else {            return 600;        }    }}public class Test {    ImageComponent imageComponent;    JFrame frame = new JFrame("CD Cover View");    JMenuBar menuBar;    JMenu menu;    Hashtable cds = new Hashtable();        public Test() throws Exception {        cds.put("Ambient:Music for Airports", "http://images.amazon.com/images/P/B000003S2L.01.LZZZZZZZ.jpg");        cds.put("Ima", "http://images.amazon.com/images/P/B000005IRM.01.LZZZZZZZ.jpg");                URL initialURL = new URL((String)cds.get("Ima"));        menuBar = new JMenuBar();        menu = new JMenu("Favorite CDs");        menuBar.add(menu);        frame.setJMenuBar(menuBar);        for(Enumeration e = cds.keys(); e.hasMoreElements();) {            String name = (String)e.nextElement();            JMenuItem menuItem = new JMenuItem(name);            menu.add(menuItem);            menuItem.addActionListener(new ActionListener() {                @Override                public void actionPerformed(ActionEvent e) {                    imageComponent.setIcon(new ImageProxy(getCDUrl(e.getActionCommand())));                    frame.repaint();                }            });        }        Icon icon = new ImageProxy(initialURL);        imageComponent = new ImageComponent(icon);        frame.getContentPane().add(imageComponent);        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);        frame.setSize(800, 600);        frame.setVisible(true);    }        URL getCDUrl(String name) {        try {            return new URL((String)cds.get(name));        } catch(MalformedURLException e) {            e.printStackTrace();            return null;        }    }        public static void main(String[] args) throws Exception {        Test t = new Test();    }}

测试结果:

图像还未加载成功:

图像加载成功:

 

保护代理:

 例子代码:

public interface PersonBean {    String getName();    String getGender();    String getInterest();    int getHotOrNotRating();        void setName(String name);    void setGender(String gender);    void setInterest(String interests);    void setHotOrNotRating(int rating);}public class PersonBeanImpl implements PersonBean {    String name;    String gender;    String interest;    int rating;    int ratingCount = 0;        public PersonBeanImpl(String name, String gender, String interest) {        this.name = name;        this.gender = gender;        this.interest = interest;    }        @Override    public String getName() {        return name;    }    @Override    public String getGender() {        return gender;    }    @Override    public String getInterest() {        return interest;    }    @Override    public int getHotOrNotRating() {        if(ratingCount == 0) return 0;        return (rating/ratingCount);    }    @Override    public void setName(String name) {        this.name = name;    }    @Override    public void setGender(String gender) {        this.gender = gender;    }    @Override    public void setInterest(String interest) {        this.interest = interest;    }    @Override    public void setHotOrNotRating(int rating) {        this.rating += rating;        ratingCount++;    }}public class OwnerInvocationHandler implements InvocationHandler {    PersonBean person;        public OwnerInvocationHandler(PersonBean person) {        this.person = person;    }        @Override    public Object invoke(Object proxy, Method method, Object[] args)            throws IllegalAccessException {        try {            if(method.getName().startsWith("get")) {                return method.invoke(person, args);            } else if(method.getName().equals("setHotOrNotRating")) {                throw new IllegalAccessException();            } else if(method.getName().startsWith("set")) {                return method.invoke(person, args);            }        } catch(InvocationTargetException e) {            e.printStackTrace();        }        return null;    }}public class NonOwnerInvocationHandler implements InvocationHandler {    PersonBean person;        public NonOwnerInvocationHandler(PersonBean person) {        this.person = person;    }        @Override    public Object invoke(Object proxy, Method method, Object[] args)            throws IllegalAccessException {        try {            if(method.getName().startsWith("get") || method.getName().equals("setHotOrNotRating")) {                return method.invoke(person, args);            } else {                throw new IllegalAccessException();            }        } catch(InvocationTargetException e) {            e.printStackTrace();        }        return null;    }}public class TestDrive {    static PersonBean getOwnerProxy(PersonBean person) {        return (PersonBean)Proxy.newProxyInstance(person.getClass().getClassLoader(), person.getClass().getInterfaces(), new OwnerInvocationHandler(person));    }        static PersonBean getNonOwnerProxy(PersonBean person) {        return (PersonBean)Proxy.newProxyInstance(person.getClass().getClassLoader(), person.getClass().getInterfaces(), new NonOwnerInvocationHandler(person));    }        public static void main(String[] args) {        PersonBean joe = new PersonBeanImpl("joe", "male", "football");                PersonBean ownerProxy = getOwnerProxy(joe);        ownerProxy.setInterest("ping pong");        System.out.println("owner setInterest");        try {            ownerProxy.setHotOrNotRating(10);        } catch(Exception e) {            System.out.println("setHotOrRating faild");        }        System.out.println("rating:" + ownerProxy.getHotOrNotRating());                PersonBean nonOwnerProxy = getNonOwnerProxy(joe);        nonOwnerProxy.setHotOrNotRating(10);        try {            nonOwnerProxy.setInterest("basketball");        } catch(Exception e) {            System.out.println("setInterest faild");        }    }}

测试结果:

 

本文提到三个代理:远程代理、虚拟代理、保护代理。

在实际应用中,代理模式的变体有很多,如还有防火墙代理,写入时复制代理,缓存代理...

不变的是:它们都是为了控制对象的访问。

转载于:https://www.cnblogs.com/13jhzeng/p/5598093.html

你可能感兴趣的文章
Event事件的兼容性(转)
查看>>
我的2014-相对奢侈的生活
查看>>
zoj 2412 dfs 求连通分量的个数
查看>>
Java设计模式
查看>>
一文读懂 AOP | 你想要的最全面 AOP 方法探讨
查看>>
Spring Cloud 微服务分布式链路跟踪 Sleuth 与 Zipkin
查看>>
ORM数据库框架 SQLite 常用数据库框架比较 MD
查看>>
华为OJ 名字美丽度
查看>>
微信公众号与APP微信第三方登录账号打通
查看>>
onchange()事件的应用
查看>>
Windows 下最佳的 C++ 开发的 IDE 是什么?
查看>>
软件工程师成长为架构师必备的十项技能
查看>>
python 异常
查看>>
百度账号注销
查看>>
mysql-This version of MySQL doesn’t yet support ‘LIMIT & IN/ALL/ANY/SOME 错误解决
查看>>
BIEE Demo(RPD创建 + 分析 +仪表盘 )
查看>>
Cocos2dx 3.0开发环境的搭建--Eclipse建立在Android工程
查看>>
基本概念复习
查看>>
重构第10天:提取方法(Extract Method)
查看>>
Android Fragment使用(四) Toolbar使用及Fragment中的Toolbar处理
查看>>