代理的作用就是让我们关注自己的正事,其他的事情由代理商来帮我们办。
举个栗子:我们要去买火车票,但是一般买火车票都需要去火车站去购买,这样大大加大了我们购票的难度,也给我们增加了很多的负担,所以这时就有代理这个概念出现了,就是我们买火车票不需要去车站了而是找一个就近的代理商,在代理商这里直接购买火车票,其余的杂事(如怎么去火车站,排队等)都交给代理来帮我们完成,这就大大简化了我们的购票难度。
代理模式uml
接口类:需要干什么
public interface HandleInterface {
public void handle(String doSomething);
}
实际处理类:要干什么(买票)
/**
* 静态代理之实际处理类
* @author hong
*
*/
public class Handle implements HandleInterface {
public void handle(String doSomething) {
System.out.println("我正在"+doSomething);
}
}
静态代理类:通过代理来干一些列其他事情(代理商)
/**
* Handle的静态代理类
* @author hong
*
*/
public class HandleProxy implements HandleInterface {
Handle handle = new Handle();
/**
* 在HandleProxy的handle方法中调用Handle的方法并在之前和之后干一些事情
*/
public void handle(String doSomething) {
beforeHandleMethod();
// 调用需要代理类的方法
handle.handle(doSomething);
afterHandleMethod();
}
public void beforeHandleMethod() {
System.out.println("在方法【前】干了一系列事情。。。");
}
public void afterHandleMethod() {
System.out.println("在方法【后】干了一系列事情。。。");
}
}
测试类:测试静态代理
public class StaticProxyTest {
public static void main(String[] args) {
String doSomething = "吃饭";
// 直接调用代理类的方法
new HandleProxy().handle(doSomething);
}
}
测试类输出:
在方法【前】干了一系列事情。。。
我正在吃饭
在方法【后】干了一系列事情。。。
静态代理的优缺点:
静态代理的优点:代理类在调动预先需要的工作之前或之后帮我们干了一些事情(让我可以专注一件事)。
静态代理的缺点:当我们更改业务,比如不买票,而是买水等等,那么我们每一项业务都需要增加新的代理类,这样大大的增大了程序的负担,也是我们不想看见的(这时我们就需要使用动态代理类)。
动态代理主要是使用InvocationHandler接口和Proxy类来实现动态代理。
InvocationHandler需要实现的方法:
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
proxy:代表我们所代理的对象
method:代表需要调用对象的哪个方法
args:调用method需要用到的参数
Proxy需要使用的方法:
public static Object newProxyInstance(ClassLoader loader, Class>[] interfaces, InvocationHandler h) throws IllegalArgumentException
loader:类加载器,定义了使用哪个类加载器来来对生成的代理对象进行加载
interfaces:一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
h:一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
接口:(定义要干什么)
public interface HandleInterface {
public void doSomething(String something);
}
实际业务类:(干什么活)
/**
* 动态代理之处理类
* @author hong
*
*/
public class Handle implements HandleInterface {
@Override
public void doSomething(String something) {
System.out.println("我正在"+something);
}
}
动态代理类:(在实际业务之前或之后干一些其他事情)
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 动态代理类
* @author hong
*
*/
public class DynamicProxy implements InvocationHandler {
// 需要代理的对象
private Object proxyObject;
public DynamicProxy(Object proxyObject) {
this.proxyObject = proxyObject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
beforeHandleMethod();
method.invoke(proxyObject, args);
afterHandleMethod();
return null;
}
public void beforeHandleMethod() {
System.out.println("在方法【前】干了一系列事情。。。");
}
public void afterHandleMethod() {
System.out.println("在方法【后】干了一系列事情。。。");
}
}
动态代理测试类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class DynamicProxyTest {
public static void main(String[] args) {
HandleInterface realSubject = new Handle();
InvocationHandler handler = new DynamicProxy(realSubject);
HandleInterface handleProxy = (HandleInterface)Proxy.newProxyInstance(
handler.getClass().getClassLoader(),
realSubject.getClass().getInterfaces(),
handler);
handleProxy.doSomething("吃饭");
}
}
输出结果
在方法【前】干了一系列事情。。。
我正在吃饭
在方法【后】干了一系列事情。。。
不惑解答
写完这些你可能就要问了,这动态代理和静态代理的想要的结果都一样,那为什么我们要使用动态代理而不用静态代理呢?(明明动态代理写起来更麻烦)。在这里我来说明一下,在业务少的时候我们使用静态代理其实比使用动态代理更快,但是当我们业务量大的时候,就如我在静态代理的缺点分析中说到的一样,我们使用静态代理需要创建大量的代理类(增加了jvm类加载的负担,使系统更加臃肿),这时我们就使用动态代理(当然业务类需要实现相应的接口),动态代理就是根据业务类实现的接口,让代理类实现了相应的接口,在运行时采用反射技术动态生成一个代理对象(减少我们写代理类的负担),在调用方法的业务方法的时候只需要进行一个强制的转换,就好了。
HandleInterface handleProxy = (HandleInterface)Proxy.newProxyInstance(
handler.getClass().getClassLoader(),
realSubject.getClass().getInterfaces(),
handler);
动态代理的优缺点分析
优点:相对于静态代理不用写很多的代理类,代理类都是在运行时jvm通过反射动态生成的,只需让业务类实现相应的接口,在使用的时候进行强制转化,调用代理类的业务方法,就可达到目的。
缺点:写起来相对的复杂。
在服务器中存放了一个很大的图片,这时如果用户直接访问包含这个图片的网页,则会出现网页出来了,图片等很久都没出来的情况,这时我们就可以使用代理模式,即在后台对图片进行一系列的处理(减少图片的像素),把处理过的图片用来代替原图片,这样就可以加快网页的显示。