一、代理模式
一个类代表另一个类去完成扩展功能,在主体类的基础上,新增一个代理类,扩展主体类功能,不影响主体,完成额外功能。比如买车票,可以去代理点买,不用去火车站,主要包括静态代理和动态代理两种模式。
代理类中包含了主体类
二、静态代理
无法根据业务扩展,每一次都要根据主体类,创建一个代理,如果多个主体类,就要多个代理。
创建一个接口
代码语言:javascript复制public interface Image { void display(); }
创建实现接口的实体类。
代码语言:javascript复制public class RealImage implements Image {
private String fileName;
public RealImage(String fileName){
this.fileName = fileName;
loadFromDisk(fileName);
}
@Override
public void display() {
System.out.println("Displaying " fileName);
}
private void loadFromDisk(String fileName){
System.out.println("Loading " fileName);
}
}
代理类
代码语言:javascript复制public class ProxyImage implements Image{
private RealImage realImage;
private String fileName;
public ProxyImage(String fileName){
this.fileName = fileName;
}
@Override
public void display() {
if(realImage == null){
realImage = new RealImage(fileName);
}
realImage.display();
}
}
当被请求时,使用 ProxyImage 来获取 RealImage 类的对象。
代码语言:javascript复制public class ProxyPatternDemo {
public static void main(String[] args) {
Image image = new ProxyImage("test_10mb.jpg");
// 图像将从磁盘加载
image.display();
System.out.println("");
// 图像不需要从磁盘加载
image.display();
}
}
缺点:ProxyImage 代理类已经固定是RealImage的类的代理了,所以不能在扩展了
三、动态代理
解决静态代理问题,代理类不是固定为某个主体类服务。Spring 的AOP底层就是动态代理实现
1)jdk代理
底层利用反射,实现 InvokeHandler,生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理,动态生成代理对象
代码语言:javascript复制public class JDKProcyImage implements InvocationHandler {
private Object object;
public JDKProcyImage(Object o) {
this.object = o;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("display")){
System.out.println("我是Image的代理,我跟realImage展示图片");
method.invoke(object,args);
System.out.println("我是Image的代理,我说完了");
}
return null;
}
}
调用:
代码语言:javascript复制public class JDKProcyImageDemo {
public static void main(String[] args) {
JDKProcyImage imageProxy = new JDKProcyImage(new RealImage2());
// 图像将从磁盘加载
Image image = (Image) Proxy.newProxyInstance(JDKProcyImageDemo.class.getClassLoader(), new Class[]{Image.class}, imageProxy);
image.display();
}
}
2)cglib动态代理
利用asm开源包,是对JDK代理的一个加强,实现MethodInterceptor类
代码语言:javascript复制public class CglibProxyImage implements MethodInterceptor {
private Object object;
public CglibProxyImage(Object o) {
this.object = o;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
if (method.getName().equals("display")){
System.out.println("我是Image的代理,我跟realImage展示图片");
method.invoke(object,objects);
System.out.println("我是Image的代理,我说完了");
}
return null;
}
}
public class CglibProxyImageDemo {
public static void main(String[] args) {
CglibProxyImage imageProxy = new CglibProxyImage(new RealImage3());
// 调用方便
RealImage3 realImage3 = (RealImage3) Enhancer.create(RealImage3.class, imageProxy);
realImage3.display();
}
}
四、总结
jdk与cglib比较
(1)JDK动态代理,java本身,只能对实现了接口的类生成代理,而不能针对类,主体类需要实现接口,调用操作繁琐
(2)CGLIB,依赖第三包是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,无需实现接口,调用简单。目标对象不用实现接口,底层通过继承目标对象产生代理对象。