在解析动态代理模式之前,先简单看下整个代理模式。代理模式分为普通代理、强制模式、动态代理模式。其中动态代理模式主要实现方式为Java JDK提供的JDK动态代理,第三方类库提供的,例如CGLIB动态代理。
代理模式就是为其他对象提供一种代理以控制对这个对象的访问。
真实的角色就是实现实际的业务逻辑,不用关心其他非职责的事务,通过后期的代理完成一件事务,附带的结果就是编程简洁清晰。
具体主题角色是随时都会发生变化的,只要它实现了接口,甭管它如何变化,都逃不脱如来佛的手掌(接口),那我们的代理类完全就可以在不做任何修改的情况下使用。
一个类可以实现多个接口,完成不同任务的整合。也就是说代理类不仅可以实现主题接口,也可以实现其他接口完成不同的任务,而且代理的目的是在目标对象方法的基础上作增强,这种增强的本质通常就是对目标对象的方法进行拦截和过滤。
定义:普通代理就是我们要知道代理的存在,也就是类似的GamePlayerProxy这个类的存在,然后才能访问;在该模式下,调用者只知代理而不用知道真实的角色是谁,屏蔽了 真实角色的变更对高层模块的影响,真实的主题角色想怎么修改就怎么修改,对高层次的模 块没有任何的影响,只要你实现了接口所对应的方法,该模式非常适合对扩展性要求较高的 场合。当然,在实际的项目中,一般都是通过约定来禁止new一个真实的角色,这也是一个 非常好的方案。
#IGamePlayer接口:
public interface IGamePlayer {
void login();
void killBoss();
void upgrade();
}
# GamePlayer类
package com.zoujieli.design.mode.proxy.general;
public class GamePlayer implements IGamePlayer{
private String name = null;
public GamePlayer(IGamePlayer gamePlayer, String name) {
if (gamePlayer == null) {
throw new RuntimeException("不能创建真实对象");
}
this.name = name;
}
@Override
public void login() {
System.out.println(name + "登陆游戏了");
}
@Override
public void killBoss() {
System.out.println(name + "开始打BOSS了");
}
@Override
public void upgrade() {
System.out.println(name + "升级了");
}
}
#代理类
package com.zoujieli.design.mode.proxy.general;
//普通代理模式
public class GamePlayerProxy implements IGamePlayer{
private GamePlayer gamePlayer;
public GamePlayerProxy(String name) {
this.gamePlayer = new GamePlayer(this, name);
}
@Override
public void login() {
this.gamePlayer.login();
}
@Override
public void killBoss() {
this.gamePlayer.killBoss();
}
@Override
public void upgrade() {
this.gamePlayer.upgrade();
}
}
# 场景类 client
public class Client {
public static void main(String[] args) {
GamePlayerProxy proxy = new GamePlayerProxy("张三");
proxy.login();
proxy.killBoss();
proxy.upgrade();
}
}
强制代理则 是调用者直接调用真实角色,而不用关心代理是否存在,其代理的产生是由真实角色决定。
#业务接口类
public interface IGamePlayer {
void login();
void killBoss();
void upgrade();
IGamePlayer getProxy();
}
# 被代理类
public class GamePlayer implements IGamePlayer {
private String name = null;
private IGamePlayer proxy = null;
public GamePlayer(String name) {
this.name = name;
}
@Override
public void login() {
if (this.proxy == null) {
throw new RuntimeException("请使用代理者");
}
System.out.println(name + "登陆游戏了");
}
@Override
public void killBoss() {
if (this.proxy == null) {
throw new RuntimeException("请使用代理者");
}
System.out.println(name + "开始打BOSS了");
}
@Override
public void upgrade() {
if (this.proxy == null) {
throw new RuntimeException("请使用代理者");
}
System.out.println(name + "升级了");
}
@Override
public IGamePlayer getProxy() {
this.proxy = new GamePlayerProxy(this);
return this.proxy;
}
}
#代理类
//普通代理模式
public class GamePlayerProxy implements IGamePlayer, IProxy{
private GamePlayer gamePlayer;
public GamePlayerProxy(GamePlayer gamePlayer) {
this.gamePlayer = gamePlayer;
}
@Override
public void login() {
this.gamePlayer.login();
}
@Override
public void killBoss() {
this.gamePlayer.killBoss();
}
@Override
public void upgrade() {
this.gamePlayer.upgrade();
this.count();
}
@Override
public IGamePlayer getProxy() {
return this;
}
@Override
public void count() {
System.out.println("代练费100");
}
}
# 代理接口类
public interface IProxy {
void count();
}
动态代理是在实现阶段不用关心代理谁,而在运行阶段 才指定代理哪一个对象。相对来说,自己写代理类的方式就是静态代理。
类图说明:其中invoke方法是接口InvocationHandler定义必须实现的,它完成对真实方法的调用。我 们来详细讲解一下InvocationHandler接口,动态代理是根据被代理的接口生成所有的方法, 也就是说给定一个接口,动态代理会宣称“我已经实现该接口下的所有方法了”,那各位读者 想想看,动态代理怎么才能实现被代理接口中的方法呢?默认情况下所有的方法返回值都是 空的,是的,代理已经实现它了,但是没有任何的逻辑义,那怎么办?好办,通过 InvocationHandler接口,所有方法都由该Handler来进行处理,即所有被代理的方法都由 InvocationHandler接管实际的处理任务。
下面是JDK提供的InvocationHandler
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
这个类图中增加了Iadvice接口,作用是在调用业务方法的时候加入通知。这是两条独立发展的线路。动态代理实现代理的职责,业务逻辑Subject实现相关的 逻辑功能,两者之间没有必然的相互耦合的关系。通知Advice从另一个切面切入,最终在高层模块也就是Client进行耦合,完成逻辑的封装任务。
public class GamePlayer implements IGamePlayer {
private String name = null;
public GamePlayer(String name) {
this.name = name;
}
@Override
public void login() {
System.out.println(name + "登陆游戏了");
}
@Override
public void killBoss() {
System.out.println(name + "开始打BOSS了");
}
@Override
public void upgrade() {
System.out.println(name + "升级了");
}
}
public interface IGamePlayer {
void login();
void killBoss();
void upgrade();
}
public class GamePlayerInvocationHandler implements InvocationHandler {
Object obj = null;
public GamePlayerInvocationHandler(Object o) {
this.obj = o;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object invoke = method.invoke(this.obj, args);
if (method.getName().equals("login")) {
System.out.println("有人在用我的账号登录!");
}
return invoke;
}
}
import java.lang.reflect.Proxy;
public class DynamicProxy {
public static <T> T newProxyInstance(IGamePlayer gamePlayer) {
if (true) {
new BeforeAdvice().beforeAdvice();
}
T proxy = (T) Proxy.newProxyInstance(gamePlayer.getClass().getClassLoader(),
gamePlayer.getClass().getInterfaces(),
new GamePlayerInvocationHandler(gamePlayer));
return proxy;
}
}
public interface IAdvice {
void beforeAdvice();
}
public class BeforeAdvice implements IAdvice{
@Override
public void beforeAdvice() {
System.out.println("前置通知调用了");
}
}
public class Client {
public static void main(String[] args) {
GamePlayer player = new GamePlayer("张三");
IGamePlayer proxy = DynamicProxy.newProxyInstance(player);
proxy.login();
proxy.killBoss();
proxy.upgrade();
}
}