JAVA的动态代理模式,理解上要分开,一个是纯代理模式,另一个是动态反射。
例子定义了两个接口,飞行接口,扣篮接口,投篮接口,其中乔丹实现了这三个接口,科比只实现了投篮与扣篮两个接口。
动态代理,一句简单的话来讲,就是:
Proxy类为我们建立出一个实体类的副本a,该副本a只对外声明了实现类实现的所有接口中的方法,且副本中保存了一个invocationHandler的实现类b。
此时的a就是一个代理类,当用户拿a去调用接口的方法时(即代理模式),JVM会将该副本类a及用户要调用的方法名还有参数交由b,通过反射机制实现【动态】调用
/**
* 篮球运动员 投篮 的接口
* */
public interface PlayerShoot {
public void shoot();
}
/**
* 运动员飞行接口
* */
public interface PlayerFly {
public void fly();
}
/**
* 篮球运动员 扣篮 的接口
* */
public interface PlayerDunk {
public void dunk();
}
/**
* 迈克尔乔丹 实现了投篮和扣篮这两个接口
* */
public class MichaelJordan implements PlayerShoot, PlayerDunk,PlayerFly{
@Override
public void dunk() {
System.out.println("Michael Jordan Dunk!!!WOW!!!");
}
@Override
public void shoot() {
System.out.println("Michael Jordan Shoot!!!Got it!!!");
}
@Override
public void fly() {
System.out.println("Look at that,mj is flying.....");
}
}
/**
* 科比类,同样实现了扣篮与投篮两个接口
* */
public class Kobe implements PlayerShoot, PlayerDunk {
@Override
public void dunk() {
System.out.println("Kobe Dunk!!!WOW!!!Not in!!");
}
@Override
public void shoot() {
System.out.println("Kobe Shoot!!!Fuck hit the rim!!!");
}
}
/**
* 这个类不是代理对象,而是代理对象中方法的调用渠道
* */
public class GameHandle implements InvocationHandler {
private Object player;
public GameHandle(Object player){
this.player = player;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
method.invoke(this.player, args);
return null;
}
public Object getPlayer() {
return player;
}
public void setPlayer(Object player) {
this.player = player;
}
}
public class GameStart {
/**
* JAVA的动态代理小结
*
* 1, 明确真实对象所具备的方法,即声明真实对象要实现的接口,起名曰 ability_interface
*
* 2, 明确真实对象所属类的方法的具体实现,即真实对象类要实现ability_interface中的所有方法,起名曰 ability_class
*
* 3,使用JVM的机制,实现接口InvocationHandler,实现类中必须实现invoke方法,起名曰inner_reflection
*
* 4,创建代理对象,使用Proxy.newProxyInstance方法,依次传递arg1,arg2,arg3,依次对应ability_class的classLoader,ability_interface中定义的方法,inner_reflection
* 此时,创建出的代理对象起名曰ProxyObject,简单理解起来,ProxyObject就是ability_class的一个副本,只不过,对外只公开ability_interface中定义的方法
*
* 注意:在创建ProxyObject的时候,JVM会将inner_reflection通过构造函数传递给ProxyObject,由此,ProxyObject就知道了由谁来通过反射机制调用其内的方法
*
* 5,此时,拿着ProxyObject就可以调用ability_interface中的方法了,参数由用户指定,而该方法的调用,则是由JVM将其传递给与ProxyObject中保存的inner_reflection
* 这里是通过反射机制来完成的,即将ProxyObject和其内要调用的方法名及用户指定的参数交由inner_reflection的invoke方法来调用
*
* 至此,就实现了通过JAVA的反射机制,针对不同真实对象的代理模式
*
* */
public static void main(String[] args) {
/**
* 这里有两个真实对象需要被代理,一个是乔丹,一个是科比
* */
MichaelJordan mj = new MichaelJordan();
Kobe kb = new Kobe();
Class<?> mjClass = mj.getClass();
Class<?> kbClass = kb.getClass();
/**
* 创建代理对象方法的调用渠道
* */
InvocationHandler bc = new GameHandle(kb);
/**
* 创建真实对象 科比 的代理对象
* */
Object actionkb = Proxy.newProxyInstance(kbClass.getClassLoader(), kbClass.getInterfaces(), bc);
/**
* 拿着科比的代理对象去调用科比已“具备的能力”,即其已实现的接口
* */
((PlayerDunk)actionkb).dunk();
((PlayerShoot)actionkb).shoot();
/**
* 现在需要代理 乔丹了,去创建出乔丹的代理对象
* */
((GameHandle)bc).setPlayer(mj);
Object actionmj = Proxy.newProxyInstance(mjClass.getClassLoader(), mjClass.getInterfaces(), bc);
/**
* 此时拿乔丹的代理对象去调用乔丹所具备的能力
* */
((PlayerDunk)actionmj).dunk();
((PlayerShoot)actionmj).shoot();
((PlayerFly)actionmj).fly();
}
}