今天在项目中见到这个动态代理的实现,很是有趣,所以学习记录一下。
动态代理,就是在运行的时候,动态的生成对某个/某些接口的新的实现类,通过在其中组合进我们想要代理的类的实例,就能够实现代理的功能。Proxy.newProxyInstance的操作,针对的是接口(Interface)而不是类(class),这也符合我们面向接口编程的编程思想。
在动态代理中,我们主要会面对两个方法:
一个是InvocationHandler接口中的invoke方法,这个方法的目的是处理代理类中对接口方法的具体实现。
/*
* InvocationHandler接口中的invoke方法
* Object proxy :Proxy.newProxyInstance生成的代理类,
* Method method :调用的方法
* Object[] args :方法中的参数
*/
public Object invoke(Object proxy, Method method, Object[] args)
一个是Proxy.newProxyInstance方法,这个方法会返回对应接口的实现类(代理)。
/*
* 动态生成对应的代理类
* ClassLoader loader :加载代理对象的类加载器
* Class>[] interfaces :所需要代理的接口
* InvocationHandler h :我们自定义的InvocationHandler
public static Object newProxyInstance(ClassLoader loader,Class>[] interfaces,InvocationHandler h)
下面举个例子:
假设有一个音乐播放器的接口:
public interface IMusicPlayer {
void start();
void pause();
void stop();
void next();
String getStatus();
}
有一个MP3播放器对该接口进行实现:
public class MP3Player implements IMusicPlayer {
private static final String TAG = "MP3Player";
private String mStatus = "stop";
@Override
public void start() {
System.out.println(TAG + " start");
mStatus = "start";
/* do sth */
}
@Override
public void pause() {
mStatus = "pause";
System.out.println(TAG + " pause");
}
@Override
public void stop() {
mStatus = "stop";
System.out.println(TAG + " stop");
}
@Override
public void next() {
mStatus = "start";
System.out.println(TAG + " next");
}
@Override
public String getStatus() {
return mStatus;
}
}
我们需要一个代理,在每一步处理之前,先记录下当前的status,所以我们的InvocationHandler接口实现类设计如下:
public class MusicInvocationHandler implements InvocationHandler {
private IMusicPlayer mMusicPlayer;
public MusicInvocationHandler(IMusicPlayer musicPlayer) {
mMusicPlayer = musicPlayer;
}
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
if(mMusicPlayer != null) {
System.out.println("before : music player is " + mMusicPlayer.getStatus());
Object invoke = method.invoke(mMusicPlayer,objects);
System.out.println("after : music player is " + mMusicPlayer.getStatus());
return invoke;
}
return null;
}
}
最后main函数如下:
public class MusicProxyTest {
public static void main(String[] args) {
IMusicPlayer musicPlayer = new MP3Player();
//需要用MP3Player.class.getInterfaces(),不能用IMusicPlayer.class.getInterfaces()
IMusicPlayer musicProxy = (IMusicPlayer) Proxy.newProxyInstance(MP3Player.class.getClassLoader(), MP3Player.class.getInterfaces(), new MusicInvocationHandler(musicPlayer));
musicProxy.start();
musicProxy.pause();
musicProxy.stop();
musicProxy.next();
}
}
执行后输出结果为:
before : music player is stop
MP3Player start
after : music player is start
before : music player is start
MP3Player pause
after : music player is pause
before : music player is pause
MP3Player stop
after : music player is stop
before : music player is stop
MP3Player next
after : music player is start
其中需要注意的是,在Proxy.newProxyInstance方法中,interface的获取需要用实现类的Class的getInterfaces()方法而不是接口的Class的getInterfaces()方法。因为getInterfaces()方法的注解中说了,该方法是获得被当前类所实现的接口或者被当前接口所扩展的所有接口。当时就是看了网上别人的教程结果就出错了...所以代码这东西还是要靠自己写和看源码才靠谱。