Java的代理就是客户端不再直接和委托类打交道,而是通过一个中间层来访问,这个中间层就是代理。
使用代理有两个好处,一是可以隐藏委托类的实现;二是可以实现客户与委托类之间的解耦,在不修改委托类代码的情况下能够做一些额外的处理。
举个很常见的例子。工厂会生产很多的玩具,但是我们买玩具都是到商店买的,而不是到工厂去买的,工厂怎么生产我们并不关心,我们只知道到商店可以买到自己想要的玩具,并且,如果我们需要送人的话商店还可以把这些玩具使用礼品盒进行包装。在这里,这个工厂就是委托类,商店就是代理类,我们就是客户类,礼品盒就是代理类对委托类做的一些额外处理。
在Java中有很多场景需要使用代理类,比如远程RPC调用的时候就是通过代理类去实现的,还有Spring的AOP切面中,我们也是为切面生成了一个代理类等等。
ASP站长网代理类主要分为静态代理、JDK动态代理和CGLIB动态代理,它们各有优缺点,没有最好的,存在就是有意义的,在不同的场景下它们会有不同的用途。
Java的静态代理
静态代理首先是定义接口和接口的实现类,然后定义接口的代理对象,并将接口的实例注入到代理对象中,然后通过代理对象去调用真正的实现类,实现过程非常简单也比较容易理解。静态代理的代理关系在编译期间就已经确定了的,适合于代理类较少且确定的情况,可以实现在不修改委托类的情况下做一些额外的处理,比如包装礼盒,实现客户类与委托类的解耦等。但是缺点是只适用于委托方法少的情况下,试想一下,如果委托类有几百上千个方法,岂不是要在代理类中写一堆的代理方法,于是就有了动态代理来解决这个问题,动态代理在后面说。
定义接口和接口的实现类
// 委托接口
public interface SayHelloService {
void sayHello(String userName);
}
// 委托实现类
public class SayHelloServiceImpl implements SayHelloService {
public void sayHello(String userName) {
System.out.println("hello, " + userName);
}
}
接口的代理类
// 代理类
public class SayHelloProxy implements SayHelloService {
private SayHelloService sayHelloService = new SayHelloServiceImpl();
public void sayHello(String userName) {
// 代理事前做一些事情
System.out.println("do something before proxy...");
// 调用委托类的方法
sayHelloService.sayHello(userName);
// 代理事后做一些事情
System.out.println("do something after proxy...");
}
}
通过代理对象访问委托类
// 测试静态代理类
public class SayHelloTest {
public static void main(String[] args) {
SayHelloProxy sayHelloProxy = new SayHelloProxy();
sayHelloProxy.sayHello("yanggb");
}
}
Java的动态代理技术
代理类在程序运行时创建的代理方式,就叫做动态代理。在了解动态代理之前,先要回顾JVM的类加载机制中的加载阶段要做的三件事情:
1.通过一个类的全名或其他途径来获取这个类的二进制字节流。
2.将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
3.在内存中生成一个代表这个类的Class对象,作为方法区中对这个类访问的入口。