1.概念
代理模式就是为某个对象提供一种代理,以控制对这个对象的访问。
2.涉及角色
抽象角色:声明真实对象和代理对象的共同接口;
代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。
真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。
3.静态代理例子
以打游戏,找教练为例。你就是被代理对象,教练就是代理类。
教练可以在你打游戏的前后给你一些指导,但是真正打游戏的还是你自己,不是教练。
下面看代码:
public interface IGamePlayer {
/*
* 登陆游戏
*/
public void login();
/*
* 杀怪
*/
public void killBoss();
/*
* 升级
*/
public void upgrade();
}
public class GamePlayer implements IGamePlayer{
String name;
public GamePlayer(String name) {
this.name = name;
}
@Override
public void login() {
System.out.println(name+"已登陆游戏!");
}
@Override
public void killBoss() {
System.out.println(name+"正在刷怪!");
}
@Override
public void upgrade() {
System.out.println("恭喜升级!");
}
}
public class GamePlayProxy implements IGamePlayer{
IGamePlayer gamePlay;
/*
* 构造函数
*/
public GamePlayProxy(IGamePlayer gamePlay) {
this.gamePlay = gamePlay;
}
@Override
public void login() {
System.out.println("--->开始玩游戏前,教练指导战术!");
this.gamePlay.login();
}
@Override
public void killBoss() {
this.gamePlay.killBoss();
}
@Override
public void upgrade() {
this.gamePlay.upgrade();
System.out.println("--->游戏结束,教练总结经验!");
}
}
/*
* 客户端
*/
public class App {
public static void main(String[] args) {
GamePlayer gamePlay = new GamePlayer("张三");
GamePlayProxy proxy = new GamePlayProxy(gamePlay);
proxy.login();
proxy.killBoss();
proxy.upgrade();
}
}
输出结果:
--->开始玩游戏前,教练指导战术!
张三已登陆游戏!
张三正在刷怪!
恭喜升级!
--->游戏结束,教练总结经验!
4.动态代理
根据如上的介绍,你会发现每个代理类只能为一个接口服务,这样程序开发中必然会产生许多的代理类
所以我们就会想办法可以通过一个代理类完成全部的代理功能,那么我们就需要用动态代理
在上面的示例中,一个代理只能代理一种类型,而且是在编译器就已经确定被代理的对象。而动态代理是在运行时,通过反射机制实现动态代理,并且能够代理各种类型的对象
JDK动态代理
目前Java开发包中包含了对动态代理的支持,但是其实现只支持对接口的的实现。 其实现主要通过java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。
还是上面的例子用动态代理实现:
public interface IGamePlayer {
/*
* 登陆游戏
*/
public void login();
/*
* 杀怪
*/
public void killBoss();
/*
* 升级
*/
public void upgrade();
}
public class GamePlayer implements IGamePlayer{
String name;
public GamePlayer(String name) {
this.name = name;
}
@Override
public void login() {
System.out.println(name+"已登陆游戏!");
}
@Override
public void killBoss() {
System.out.println(name+"正在刷怪!");
}
@Override
public void upgrade() {
System.out.println("恭喜升级!");
}
}
public class GamePlayProxy implements InvocationHandler{
/*
* 腰代理的真实对象
*/
private Object obj;
public GamePlayProxy(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
//调用之前
//doBefore();
//调用原始对象的方法
result=method.invoke(obj, args);
//调用之后
//doAfter();
return result;
}
}
public class App {
public static void main(String[] args) {
GamePlayer gamePlayer = new GamePlayer("张三");
GamePlayProxy proxy = new GamePlayProxy(gamePlayer);
IGamePlayer gamePlayProxy = (IGamePlayer) Proxy.newProxyInstance(
GamePlayer.class.getClassLoader(),
GamePlayer.class.getInterfaces(),
proxy);
gamePlayProxy.login();
gamePlayProxy.killBoss();
gamePlayProxy.upgrade();
}
}
结果:
CGLIB动态代理
/*
* 目标对象
*/
public class Train {
public void start(){
System.out.println("火车开始启动......");
}
}
public class Cglibproxy implements MethodInterceptor{
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class clazz){
//设置创建子类的类
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
/*
* 拦截所有目标类方法的调用
* obj 目标类的实例
* m 目标方法的反射对象
* arge 方法的参数、
* proxy 代理类的实例
*/
@Override
public Object intercept(Object obj, Method m, Object[] args, MethodProxy proxy) throws Throwable {
//代理类调用父类方法
proxy.invokeSuper(obj, args);
return null;
}
}
/*
* 客户端
*/
public class App {
public static void main(String[] args) {
Cglibproxy proxy = new Cglibproxy();
Train t = (Train) proxy.getProxy(Train.class);
t.start();
}
}
显然:动态代理不仅仅只能代理一种类。
JDK代理和cglib代理简单比较:
JDK动态代理
1.只能代理实现了接口的类
2.没有实现接口的类不能实现JDK动态代理
CGLIB动态代理
1.针对类来实现动态代理
2.对指定目标类产生一个子类,通过方法拦截技术拦截所有父类方法的使用。