代理模式(Proxy)
代理模式其实从字面上来说很好理解。实际生活中,形形色色的明星都会有自己的经纪人吧。这个经纪人其实就是明星的代理。他先负责跟投资方谈谈,然后明星才开始接拍电影,唱歌,跳舞啥的。我们的代码示例也以这个例子为业务基础。回到理论层面,代理模式就是多一个代理类出来,替原对象进行一些操作。代理模式又可以分为静态代理模式和动态代理模式,动态代理模式又分为JDK动态代理和cglib动态代理。首先我们来写静态代理模式代码,并分析静态代理模式的优缺点:
第一步,我们来声明两类明星的接口,歌星和舞星
/**
* @author chenglezheng
*/
public interface SongStar {
void song(String startName);
}
/**
* @author chenglezheng
*/
public interface DanceStar {
void dance(String startName);
}
然后我们再写两类接口具体的实现
/**
* @author chenglezheng
*/
public class SongStarImpl implements SongStar {
public void song(String startName) {
System.out.println(startName+"歌星演唱了一首特别high的歌曲!");
}
}
/**
* @author chenglezheng
*/
public class DanceStarImpl implements DanceStar {
public void dance(String startName) {
System.out.println(startName+"舞星表演了一段性感无比的舞蹈!!!");
}
}
接着就是代理了,静态代理此时就必须要针对这两类接口分别写不同的代理类,
/**
* @author chenglezheng
*/
public class SongStarProxy implements SongStar {
private SongStar star;
public SongStarProxy(SongStar star) {
this.star = star;
}
public void song(String startName) {
String proxy="我是"+startName+"明星代理人,有事先跟我谈。\n 谈好了,明星开始表演";
System.out.println(proxy);
this.star.song(startName);
}
}
/**
* @author chenglezheng
*/
public class DanceStarProxy implements DanceStar {
private DanceStar danceStar;
public DanceStarProxy(DanceStar danceStar) {
this.danceStar = danceStar;
}
public void dance(String startName) {
String proxy="我是"+startName+"明星代理人,有事先跟我谈。\n 谈好了,明星开始表演 ";
System.out.println(proxy);
this.danceStar.dance(startName);
}
}
最后我们来测试静态代理:
//静态代理测试
SongStar songStar=new SongStarImpl(); //歌星
SongStar songStarProxy=new SongStarProxy(songStar); //歌星代理人
songStarProxy.song("张某某");
DanceStar danceStar=new DanceStarImpl(); //舞星
DanceStar danceStarProxy=new DanceStarProxy(danceStar); //舞星代理人
danceStarProxy.dance("李某某");
控制台输出:
我是张某某明星代理人,有事先跟我谈。
谈好了,明星开始表演
张某某歌星演唱了一首特别high的歌曲!
我是李某某明星代理人,有事先跟我谈。
谈好了,明星开始表演
李某某舞星表演了一段性感无比的舞蹈!!!
从输出结果可以看出,明星在每次进行表演前,经纪人都跟投资方谈了谈,谈完了明星才开始表演。这就是典型的静态代理模式。
静态代理模式的
优点:编码简单
缺点:每类接口都需要一个代理类,而且每个代理类都要实现接口中的方法,如果接口特别多,有些接口可能后期要扩展,那么开发人员维护的难度将是想死的心都有的。
那么动态代理就应用而生了,这里我们只讲基于JDK实现的动态代理,至于cglib动态代理就不再赘述了,只讲它们的区别和应用场景。
首先我们先写一个公共的代理类:
/**
* @author chenglezheng
* @date 2020-01-19 15:55
*/
public class StarProxy {
public static void proxy(String starName) {
String proxy="我是"+starName+"明星代理人,有事先跟我谈。\n 谈好了,明星开始表演";
System.out.println(proxy);
}
}
接着,我们通过JDK的动态代理模式来关联公共代理类和具体的实现类之间的关系,其实就是通过Java的反射机制生成具体的实现,然后将它们关联起来
/**
* @author chenglezheng
*/
public class JDKDynamicProxy implements InvocationHandler {
private Object object;
public JDKDynamicProxy(Object object) {
this.object = object;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
StarProxy.proxy(args[0].toString());
Object objectTemp=method.invoke(object,args);
return objectTemp;
}
}
最后我们来测试下JDK动态代理
//动态代理测试
SongStar songStar1=new SongStarImpl(); //歌星
JDKDynamicProxy dynamicProxy=new JDKDynamicProxy(songStar1);
SongStar proxy1=(SongStar) Proxy.newProxyInstance(songStar1.getClass().getClassLoader(),
songStar1.getClass().getInterfaces(),
dynamicProxy);
proxy1.song("张某某");
DanceStar danceStar1=new DanceStarImpl(); //舞星
dynamicProxy=new JDKDynamicProxy(danceStar1);
DanceStar proxy2=(DanceStar) Proxy.newProxyInstance(danceStar1.getClass().getClassLoader(),
danceStar1.getClass().getInterfaces(),
dynamicProxy);
proxy2.dance("李某某");
控制台输出:
我是张某某明星代理人,有事先跟我谈。
谈好了,明星开始表演
张某某歌星演唱了一首特别high的歌曲!
我是李某某明星代理人,有事先跟我谈。
谈好了,明星开始表演
李某某舞星表演了一段性感无比的舞蹈!!!
从输出结果可以看出,跟静态代理没有任何区别。但是这里就不需要每类接口都要实现一个代理类了,代码维护起来就so easy了。最后总结下两种动态代理模式的区别:
Jdk动态代理模式是基于接口实现的一种代理模式,也就是你要实现此类代理模式就必须要有具体的接口。
cglib代理模式是基于子类实现的一种代理模式,也就是说你要实现此类代理模式就不能在类和方法上加final关键字修饰,因为被此关键字修饰的类不能继承,方法不能重写。
Spring的AOP就是基于这两类动态代理来实现切面编程的,并且这两类动态代理在Spring中可以自由切换。Sping的默认代理模式就是JDK动态代理,当然你也可以设置默认代理模式为cglib动态代理。