《代理模式》
代理模式:为对象提供一种代理以控制这种对象的访问。在Java中有静态代理和动态代理两种实现方式。
静态代理:
拿日本动漫《棋魂》举例,佐为只是灵魂,它要下棋必须通过阿光这个“代理”,我们用代码实现一下:
//Subject
public interface WeiQi {
void playWeiQi();
}
//RealSubject
public class ZuoWei implements WeiQi {
@Override
public void playWeiQi() {
System.out.println("佐为下围棋");
}
}
//Proxy
public class Guang implements WeiQi {
private WeiQi zuoWei;
public Guang() {
zuoWei = new ZuoWei();
}
@Override
public void playWeiQi() {
System.out.println("阿光才是真正操作棋子的");
zuoWei.playWeiQi();
}
}
//测试
public static void main(String[] args) {
//客户端调用代理类
WeiQi guang = new Guang();
guang.playWeiQi();
}
再使用动态代理实现上面的例子:
//RealSubject
public class ZuoWei implements WeiQi {
@Override
public void playWeiQi() {
System.out.println("佐为下围棋");
}
public static void main(String[] args) {
WeiQi zuoWei = new ZuoWei();
WeiQi weiQi = (WeiQi) Proxy.newProxyInstance(zuoWei.getClass().getClassLoader(), new Class[]{WeiQi.class}, new WeiQiInvocationHandler(zuoWei));
weiQi.playWeiQi();
}
}
class WeiQiInvocationHandler implements InvocationHandler{
private WeiQi weiQi;
public WeiQiInvocationHandler(WeiQi weiQi) {
this.weiQi = weiQi;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("阿光才是真正操作棋子的");
method.invoke(weiQi);
return null;
}
}
动态代理之所以被称为动态,就是因为运行时才将它的类创建出来。代码开始执行时,还没有proxy类,它时根据传入的接口而创建的。
代理模式的应用场景
1.远程代理:可以作为另一台虚拟机上的本地代表,调用代理的方法,会被代理利用网络和IO转换成远程调用服务,并将结果再通过网络返回给客户端。
//服务接口
public interface Hello extends Remote {
String sayHello()throws RemoteException;
}
//服务实现类
public class SayHello extends UnicastRemoteObject implements Hello {
protected SayHello() throws RemoteException {
//该构造器只是为了抛出异常
super();
}
@Override
public String sayHello() throws RemoteException {
return "hello brother";
}
}
//启动服务
public class MyServer {
//用于启动服务
public static void main(String[] args) {
try {
Hello hello = new SayHello();
//设置端口
LocateRegistry.createRegistry(6601);
Context namingContext = new InitialContext();
//向rmi注册服务
namingContext.rebind("rmi://127.0.0.1:6601/hello", hello);
System.out.println("服务器已经启动");
} catch (Exception e) {
e.printStackTrace();
}
}
}
//客户端
public class MyClient {
public static void main(String[] args) {
try {
//从rmi中获取服务
Hello hello = (Hello) Naming.lookup("rmi://127.0.0.1:6600/hello");
String str = hello.sayHello();
System.out.println(str);
} catch (MalformedURLException | RemoteException | NotBoundException e) {
e.printStackTrace();
}
}
}
2.虚拟代理:在创建开销比较大的对象时,使用虚拟代理替代该对象,只有当该对象被真正调用的时候才会被创建,提高了程序的启动速度。比如加载HTML页面时,图片是要一个一个下的,此时哪些未打开的图片框就是通过虚拟代理代替了图片。
3.安全代理:一般是通过动态代理来控制真实对象的访问权限。比如用动态代理作权限验证。
.....还有很多代理模式,这里就不列举了