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

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

hot3.png

      代理模式指的是一个可以用来控制对某个对象访问的模式,其地位类似于现实世界中的经纪人,我们每次对重要对象的调用都需要经过经纪人的处理才能进行,如果遇到不合法或者不安全的访问,经纪人就会对其进行拒绝。代理模式主要有三种表现形式:远程代理,虚拟代理和安全代理。

      远程代理指的是Java RMI访问,服务端将需要暴露的对象注册于RMI registry中,但是通常需要暴露的对象中不仅仅包含需要暴露的信息,还包含很多额外的信息,因而不能直接将其暴露给客户端,而是使用一个代理,客户端调用该代理的方法,代理会将方法的调用转接给真正执行的对象,客户端的调用感觉就像是直接调用服务端的方法一样。

      远程代理服务端需要将代理的对象继承UnicastRemoteObject,并且继承一个代理接口。这里需要注意的有两点:①需要代理的对象中的重要属性需要使用transient来描述,以防止其被客户端获取;②需要代理的对象需要实现Serializable接口,以供远程对象传输,不过UnicastRemoteObject已经实现了Serializable接口,因而代理对象不需要显示实现该接口。其次,服务端需要将被代理对象注册到RMI registry中,以供客户端访问。而客户端则需要下载服务端的代理接口,通过该接口客户端可以进行其所需的操作,并且客户端需要在RMI registry中查找远程传输过来的对象,将其强转为代理对象类型。以下是远程代理的示例代码:

被代理对象:

public class GumballMachine extends UnicastRemoteObject implements GumballMachineRemote {    private State soldOutState;    private State noQuarterState;    private State hasQuarterState;    private State soldState;    private State winnerState;    private String location;    private State state;    private int count = 0;    public GumballMachine(String location, int numberGumballs) throws RemoteException {        soldOutState = new SoldOutState(this);        noQuarterState = new NoQuarterState(this);        hasQuarterState = new HasQuarterState(this);        soldState = new SoldState(this);        winnerState = new WinnerState(this);        this.location = location;        this.count = numberGumballs;        if (numberGumballs > 0) {            state = noQuarterState;        }    }    public void insertQuarter() {        state.insertQuarter();    }    public void ejectQuarter() {        state.ejectQuarter();    }    public void turnCrank() {        state.turnCrank();        state.dispense();    }    public void setState(State state) {        this.state = state;    }    public void releaseBall() {        System.out.println("A gumball comes rolling out the slot...");        if (count != 0) {            count--;        }    }    public String getLocation() {        return location;    }    public State getSoldOutState() {        return soldOutState;    }    public State getNoQuarterState() {        return noQuarterState;    }    public State getHasQuarterState() {        return hasQuarterState;    }    public State getSoldState() {        return soldState;    }    public State getWinnerState() {        return winnerState;    }    public State getState() {        return state;    }    public int getCount() {        return count;    }}

服务端RMI注册类:

public class GumballMachineTestDrive {    public static void main(String[] args) {        int count = 100;        if (args.length < 2) {            System.out.println("GumballMachine 
"); System.exit(1); } try { GumballMachine gumballMachine = new GumballMachine("seattle.mightygumball.com", count); Naming.rebind("//seattle.mightygumball.com/gumballmachine", gumballMachine); } catch (RemoteException | MalformedURLException e) { e.printStackTrace(); } }}

代理接口:

public interface GumballMachineRemote extends Remote {    int getCount() throws RemoteException;    String getLocation() throws RemoteException;    State getState() throws RemoteException;}

客户端驱动类:

public class GumballMonitorTestDrive {    public static void main(String[] args) {        String[] location = {                "rmi://santafe.mightygumball.com/gumballmachine",                "rmi://boulder.mightygumball.com/gumballmachine",                "rmi://seattle.mightygumball.com/gumballmachine",        };        GumballMonitor[] monitors = new GumballMonitor[location.length];        try {            for (int i = 0; i < location.length; i++) {                GumballMachineRemote machine = (GumballMachineRemote) Naming.lookup(location[i]);                monitors[i] = new GumballMonitor(machine);                System.out.println(monitors[i]);            }        } catch (NotBoundException | MalformedURLException | RemoteException e) {            e.printStackTrace();        }        for (int i = 0; i < monitors.length; i++) {            monitors[i].report();        }    }}

客户端管理类:

public class GumballMonitor {    private GumballMachineRemote machine;    public GumballMonitor(GumballMachineRemote machine) {        this.machine = machine;    }    public void report() {        try {            System.out.println("Gumball Machine: " + machine.getLocation());            System.out.println("Current inventory: " + machine.getCount() + " gumballs");            System.out.println("Current state: " + machine.getState());        } catch (RemoteException e) {            e.printStackTrace();        }    }}

      虚拟代理指的是对一些创建消耗比较大或者比较耗时的对象的保护。比如在GUI界面中,图片的加载受到很多因素的影响,如果在加载图片的时候将客户端挂起的话会非常影响用户体验,因而在图片的加载就可以使用代理来进行,代理对象在图片还没有加载出来的时候将一个加载中的低耗图标返回给客户端,当图片加载完成之后代理对象就将真正的图片返回给客户。类似这样使用虚拟代理的场景还有使用时复制等。以下是使用虚拟代理加载图片的示例代码:

public class ImageProxy implements Icon {    private ImageIcon imageIcon;    private URL imageUrl;    private boolean retrieving;    private State state;    public ImageProxy(URL imageUrl) {        this.imageUrl = imageUrl;        this.state = new ImageNotLoaded();    }    @Override    public void paintIcon(Component c, Graphics g, int x, int y) {        if (!retrieving) {            retrieving = true;            new Thread(() -> {                try {                    imageIcon = new ImageIcon(imageUrl, "CD Cover");                    state = new ImageLoaded(imageIcon);                    c.repaint();                } catch (Exception e) {                    e.printStackTrace();                }            }).start();        }        state.printIcon(c, g, x, y);    }    @Override    public int getIconWidth() {        return state.getIconWidth();    }    @Override    public int getIconHeight() {        return state.getIconHeight();    }}

标志当前处于什么状态(加载中,加载完成)的接口:

public interface State {    int getIconWidth();    int getIconHeight();    void printIcon(Component c, Graphics g, int x, int y);}

加载中状态:

public class ImageLoaded implements State {    private ImageIcon imageIcon;    public ImageLoaded(ImageIcon imageIcon) {        this.imageIcon = imageIcon;    }    @Override    public int getIconWidth() {        return imageIcon.getIconWidth();    }    @Override    public int getIconHeight() {        return imageIcon.getIconHeight();    }    @Override    public void printIcon(Component c, Graphics g, int x, int y) {        imageIcon.paintIcon(c, g, x, y);    }}

加载完成状态:

public class ImageNotLoaded implements State {    private static final int DEFAULT_WIDTH = 800;    private static final int DEFAULT_HEIGHT = 600;    @Override    public int getIconWidth() {        return DEFAULT_WIDTH;    }    @Override    public int getIconHeight() {        return DEFAULT_HEIGHT;    }    @Override    public void printIcon(Component c, Graphics g, int x, int y) {        g.drawString("Loading CD cover, please wait...", x + 300, y + 190);    }}

      这里使用状态模式来标志当前是处于加载中状态还是加载完成状态。

      安全代理指的是使用代理模式来控制对象的访问,比如对某个对象的访问权限控制。在java中已经对这种代理模式提供了内置支持,其主要类是Proxy,其有如下静态方法用于创建代理对象:

public static Object newProxyInstance(ClassLoader loader,                                          Class
[] interfaces, InvocationHandler h) throws IllegalArgumentException;

该方法第一个参数是被代理对象的类加载器,第二个对象是被代理对象实现的接口数组,第三个对象则是被代理对象的一个调用处理器。其是一个接口,该接口有如下主要方法:

public Object invoke(Object proxy, Method method, Object[] args)        throws Throwable;

每次调用代理对象的方法时都会先调用该方法,通过该方法调用被代理对象的方法,因而在该方法中可以加入被代理对象的访问权限控制。该方法第一个参数是代理对象的实例,第二个参数是当前调用的被代理对象中的方法,第三个参数是调用时传入的参数列表。以下是使用安全代理的一个示例:

被代理对象接口:

public interface PersonBean {    String getName();    String getGender();    String getInterests();    int getHotOrNotRating();    void setName(String name);    void setGender(String gender);    void setInterests(String interests);    void setHotOrNotRating(int rating);}

被代理对象:

public class PersonBeanImpl implements PersonBean {    private String name;    private String gender;    private String interests;    private int rating;    private int ratingCount = 0;    @Override    public String getName() {        return name;    }    @Override    public void setName(String name) {        this.name = name;    }    @Override    public String getGender() {        return gender;    }    @Override    public void setGender(String gender) {        this.gender = gender;    }    @Override    public String getInterests() {        return interests;    }    @Override    public int getHotOrNotRating() {        return ratingCount == 0 ? 0 : rating / ratingCount;    }    @Override    public void setInterests(String interests) {        this.interests = interests;    }    @Override    public void setHotOrNotRating(int rating) {        this.rating += rating;        ratingCount++;    }}

代理工厂:

public final class ProxyFactory {    public static PersonBean getOwnerProxy(PersonBean person) {        return getProxy(person, new OwnerInvocationHandler(person));    }    public static PersonBean getNonOwnerProxy(PersonBean person) {        return getProxy(person, new NonOwnerInvocationHandler(person));    }    private static PersonBean getProxy(PersonBean person, InvocationHandler invocationHandler) {        return (PersonBean) Proxy.newProxyInstance(person.getClass().getClassLoader(), person.getClass().getInterfaces(), invocationHandler);    }}

代理处理器:

public class NonOwnerInvocationHandler implements InvocationHandler {    private 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().matches("^((get.+)|(setHotOrNotRating))$")) {                return method.invoke(person, args);            } else {                throw new IllegalAccessException();            }        } catch (InvocationTargetException e) {            e.printStackTrace();        }        return null;    }}
public class OwnerInvocationHandler implements InvocationHandler {    private 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().matches("^((get)|(set)).+")) {                return method.invoke(person, args);            } else if (method.getName().equals("setHotOrNotRating")) {                throw new IllegalAccessException("cannot invoke PersonBean.setHotOrNotRating method");            }        } catch (InvocationTargetException e) {            e.printStackTrace();        }        return null;    }}

测试驱动类:

public class MatchMarketingTestDrive {    public static void main(String[] args) {        new MatchMarketingTestDrive().drive();    }    public void drive() {        PersonBean joe = getPersonFromDatabase("Joe Javabean");        PersonBean ownerProxy = ProxyFactory.getOwnerProxy(joe);        System.out.println("Name is " + ownerProxy.getName());        ownerProxy.setInterests("bowling, go");        System.out.println("Interests set from owner proxy");        try {            ownerProxy.setHotOrNotRating(10);        } catch (Exception e) {            System.out.println("Can't set rating from owner proxy");        }        System.out.println("Rating is " + ownerProxy.getHotOrNotRating());        PersonBean nonOwnerProxy = ProxyFactory.getNonOwnerProxy(joe);        System.out.println("Name is " + nonOwnerProxy.getName());        try {            nonOwnerProxy.setInterests("bowling, go");        } catch (Exception e) {            System.out.println("Can't set interests from non owner proxy");        }        nonOwnerProxy.setHotOrNotRating(3);        System.out.println("Rating set from non owner proxy");        System.out.println("Rating is " + nonOwnerProxy.getHotOrNotRating());    }    private PersonBean getPersonFromDatabase(String name) {        PersonBean person = new PersonBeanImpl();        person.setName(name);        return person;    }}

 

转载于:https://my.oschina.net/zhangxufeng/blog/815874

你可能感兴趣的文章
针对ASP.NET页面实时进行GZIP压缩优化的几款压缩模块的使用简介及应用测试!(附源码)...
查看>>
IDEA常用快捷键
查看>>
input 回车提交
查看>>
xp创建***拨号连接
查看>>
win下一些常用的工具软件及网管管理系统
查看>>
Index.get_indexer 方法的含义
查看>>
从C#到TypeScript - Generator
查看>>
Exchange 2010 (一) 为多台CAS/HUB配置证书
查看>>
你有合并单元格我都不怕-Lookup特殊使用破合并单元格求值
查看>>
CSS代码格式化工具
查看>>
【开发笔记】单点登录CAS测试登录Invalid credentials无效凭据
查看>>
检查到apache有错误发送邮件
查看>>
3.4 usermod命令;3.5 用户密码管理;3.6 mkpasswd命令
查看>>
IBM中国研究院院长沈晓卫谈认知计算
查看>>
rhel6创建iso镜像
查看>>
Unix整理笔记-vi简介-里程碑M8
查看>>
Java中方法覆盖的约束
查看>>
用路由器做CA的基于数字证书的ipsec ***
查看>>
运维必须掌握的Linux面试题【转自CentOS中文站】
查看>>
poj1459 Power Network(最大流)
查看>>