代理模式
我们都知道java中有23种设计模式,今天我们就来聊一聊这23种设计模式中的代理设计模式,首先代理模式其实就是控制对其他对象的访问,在访问其他对象之前我们可以进行一些其他的操作。其实代理一般分为一以下四类:
其实这几种设计模式通常用我们常说的动态代理全部都可以实现,下面我就引用一下虚拟代理的实例,模拟了图片延迟加载的情况下使用与图片大小相等的临时内容去替换原始图片,直到图片加载完成才将图片显示出来。
public interface Image {
void showImage();
}
public class HighResolutionImage implements Image {
private URL imageURL;
private long startTime;
private int height;
private int width;
public int getHeight() {
return height;
}
public int getWidth() {
return width;
}
public HighResolutionImage(URL imageURL) {
this.imageURL = imageURL;
this.startTime = System.currentTimeMillis();
this.width = ;
this.height = ;
}
public boolean isLoad() {
// 模拟图片加载,延迟 3s 加载完成
long endTime = System.currentTimeMillis();
return endTime - startTime > ;
}
@Override
public void showImage() {
System.out.println("Real Image: " + imageURL);
}
}
java
public class ImageProxy implements Image {
private HighResolutionImage highResolutionImage;
public ImageProxy(HighResolutionImage highResolutionImage) {
this.highResolutionImage = highResolutionImage;
}
@Override
public void showImage() {
while (!highResolutionImage.isLoad()) {
try {
System.out.println("Temp Image: " + highResolutionImage.getWidth() + " " + highResolutionImage.getHeight());
Thread.sleep();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
highResolutionImage.showImage();
}
}
java
public class ImageViewer {
public static void main(String[] args) throws Exception {
String image = "http://image.jpg";
URL url = new URL(image);
HighResolutionImage highResolutionImage = new HighResolutionImage(url);
ImageProxy imageProxy = new ImageProxy(highResolutionImage);
imageProxy.showImage();
}
}
java
JDK中的动态代理
其实在jdk中的java.lang.reflect的包下就为我们内置了一种基与接口的动态代理模式proxy,其实这种动态代理模式也非常的好理解,我们用演员来举一个例子,演员出名了以后,就要给粉丝签签名,陪粉丝吃吃饭啦。这里模拟一个演员的接口
public interface Actor {
/**
* 给人签名
*/
public void signature();
/**
* 和粉丝吃饭
*/
public void eat();
}
java
有一个叫做FBB的演员实现了演员这个接口
public class FBB implements Actor{
public void signature() {
System.out.println("给人签名...");
}
public void eat() {
System.out.println("陪人吃饭...");
}
}
java
后来FBB越来越火,想要和她要签名和吃饭的粉丝也越来越多,所以FBB就请来一个经纪人帮他拦一拦
public class Proxy {
public static void main(String[] args) {
final FBB fbb = new FBB();
// FBB的代理类
Actor proxyActor = (Actor) java.lang.reflect.Proxy.newProxyInstance(fbb.getClass().getClassLoader(), fbb.getClass().getInterfaces(), new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("你谁呀!");
if ("是一个真爱粉") {
return method.invoke(fbb);
}
return null;
}
});
proxyActor.signature();
proxyActor.eat();
}
}
这样FBB每次就不用每次都为给谁签名和谁吃饭而发愁了,他的经纪人也就是JDK中内置的proxy就全权帮他搞定了,这里再介绍一下proxy的api: Proxy.newProxyInstance(三个参数) 参数含义: ClassLoader:和被代理对象使用相同的类加载器。 Interfaces:和被代理对象具有相同的行为。实现相同的接口。 InvocationHandler:如何代理。 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable 参数: proxy:代理对象的引用。不一定每次都用得到 method:当前执行的方法对象 args:执行方法所需的参数 **返回值:**当前执行方法的返回值 这就是JDk中自带的动态模式,但是这种代理模式是有bug的,如果FBB中存在接口中没有的方法,则就无法进行代理。所以这里在介绍由第三方类库Cglib提供的另外一种一种基于继承的动态代理方式。
Cglib中的动态代理
其实他和jdk中的静态代理非常相似,一般分为一下几5个步骤
public class cglibProxy {
public static void main(String[] args) {
final FBB fbb = new FBB();
// 使用cglib动态代理fbb
// 1.创建增强器
Enhancer enhancer = new Enhancer();
// 2.设定接口
enhancer.setInterfaces(fbb.getClass().getInterfaces());
// 3.设定父类
enhancer.setSuperclass(fbb.getClass());
// 4.为增强器设定回调函数
enhancer.setCallback(new MethodInterceptor() {
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("你谁呀!");
return method.invoke(fbb);
}
});
// 5.生成代理对象
FBB cglib = (FBB) enhancer.create();
cglib.eat();
cglib.signature();
}
因为Cglib提供的动态代理是基于继承的所以第二步设定接口一般可以不写。用过spring的也都知道,其实Cglib的这种动态代理其实就是Spring中Aop的底层的一种实现。