今天这篇博客,我想来说一下我对于代理模式的理解,之前有写过关于代理模式的博客。这篇博客就再总结一下,所谓代理模式简单理解就是声明一个类作为代理的身份去执行另一个类的功能,这样就可以实现类的内部细节的隐藏同时还可以调用这个类的功能。与此同时我们可以对目标类中的方法进行加强。
代理模式的实现有两种方式,一种是静态代理,一种是动态代理。静态代理就是需要用户手动声明一个代理类,对目标类进行封装和细节的隐藏,同时实现方法的加强处理。动态代理则是利用java自带的反射机制,在运行的时候创建代理类,这个代理类的创建是由jvm完成的。下面来简单看一下这两种方法的实现。
1.静态代理
首先声明一个Star接口,表示明星所具有的功能。
public interface Star {
/**
* 面谈
*/
void confer();
/**
* 签合同
*/
void signContract();
/**
* 订票
*/
void bookTicket();
/**
* 唱歌
*/
void sing();
/**
* 收钱
*/
void collectMoney();
}
声明一个类实现这个接口的方法,
public class RealStar implements Star {
@Override
public void bookTicket() {
System.out.println("RealStar.bookTicket()");
}
@Override
public void collectMoney() {
System.out.println("RealStar.collectMoney()");
}
@Override
public void confer() {
System.out.println("RealStar.confer()");
}
@Override
public void signContract() {
System.out.println("RealStar.signContract()");
}
@Override
public void sing() {
System.out.println("RealStar(周杰伦本人).sing()");
}
}
同时声明一个代理类,代替RealStar执行唱歌方法
public class ProxyStar implements Star {
private Star star;
public ProxyStar(Star star) {
super();
this.star = star;
}
@Override
public void bookTicket() {
System.out.println("ProxyStar.bookTicket()");
}
@Override
public void collectMoney() {
System.out.println("ProxyStar.collectMoney()");
}
@Override
public void confer() {
System.out.println("ProxyStar.confer()");
}
@Override
public void signContract() {
System.out.println("ProxyStar.signContract()");
}
@Override
public void sing() {
star.sing();
}
}
可以看到在ProxyStar中的sing方法内部实现了对于RealStar方法的调用。下面来看测试代码
public class Client {
public static void main(String[] args) {
Star real = new RealStar();
Star proxy = new ProxyStar(real);
proxy.confer();
proxy.signContract();
proxy.bookTicket();
proxy.sing();
proxy.collectMoney();
}
}
静态代理没有太多的难点,重点在于动态代理,动态代理在Spring的AOP中也得到了广泛使用,详情可以看我的关于Spring源码阅读部分的博客
2.动态代理
和静态代理不同的是关于代理类部分的声明。这里动态代理声明了一个handler类,也就是实际进行方法运行的类。
public class StarHandler implements InvocationHandler {
Star realStar;
public StarHandler(Star realStar) {
super();
this.realStar = realStar;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object object = null;
System.out.println("真正的方法执行前!");
System.out.println("面谈,签合同,预付款,订机票");
if(method.getName().equals("sing")){
object = method.invoke(realStar, args); //执行相应的方法
}
System.out.println("真正的方法执行后!");
System.out.println("收尾款");
return object;
}
}
仔细看一下这个类,首先需要实现InvocationHandler 接口并实现其中的invoke方法,这样在执行目标方法的时候,实际上是通过invoke中method.invoke()部分通过反射实现对目标方法的调用,同时可以进行对于方法的增强。下面来看测试代码
public class Client {
public static void main(String[] args) {
Star realStar = new RealStar();
StarHandler handler = new StarHandler(realStar);
Star proxy = (Star) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
new Class[]{Star.class}, handler);
proxy.sing();
}
}
单独来看这一部分
Star proxy = (Star) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
new Class[]{Star.class}, handler);
这一句话是利用jdk自带的代理模式实现机制,通过反射产生一个新的类,这个类就对于Star接口实现类的增强,在这个里面指的是我们的RealStar。这句话会根据handler生成一个Proxy类,实际上对于目标方法的调用就是针对于proxy这个增强后的实例化对象的调用了。