代理模式(proxy)指的是为一个对象提供一个代理以控制外界对该对象的访问,比如有些情况下对象A不能直接访问对象B,此时可以为对象B创建一个代理C,然后对象A通过访问代理C来间接访问对象B。比如你看上了你女性朋友的闺蜜,此时你可以通过你的朋友来跟她闺蜜进行一些沟通。 有的时候我们希望增强某个方法的功能,但是有不方便直接修改该方法,此时也可通过代理来实现,即在该方法执行的前后做一些事情。比如你要打官司,但是法律上的事情你可能不清楚,此时需要请一名代理律师,让这个代理律师帮助你去做一些事情。
代理的模式的优点:
- 提高程序的扩展性和可复用性
- 保护目标对象
代理模式分为两种:静态代理和动态代理。
静态代理代理类和相关的方法直接在代码中写死。下面以你看上了你女性朋友娜娜的闺蜜小曼举例:
首先定义一个接口:
package com.monkey1024.proxy.staticproxy;
/**
* 女神
*/
public interface Beauty {
void eat();
}
创建小曼的类并实现上面的接口:
package com.monkey1024.proxy.staticproxy;
/**
* 你的目标对象小曼
* 你女性朋友娜娜的闺蜜
*/
public class XiaoMan implements Beauty {
@Override
public void eat() {
System.out.println("小曼吃饭");
}
}
创建娜娜的类实现上面接口,娜娜是中间人,所以实现方式不太一样,这里的eat方法中要调用目标对象上的eat方法:
package com.monkey1024.proxy.staticproxy;
/**
* 中间人,你的女性朋友娜娜
*/
public class NaNa implements Beauty {
private Beauty beauty;
/**
* 通过构造方法传入目标对象
* @param beauty
*/
public NaNa(Beauty beauty) {
this.beauty = beauty;
}
@Override
public void eat() {
//调用目标对象上的吃饭方法
beauty.eat();
}
}
创建你的类,里面添加交朋友的方法:
package com.monkey1024.proxy.staticproxy;
public class You {
private Beauty beauty;
public You(Beauty beauty) {
this.beauty = beauty;
}
/**
* 交朋友
*/
public void makeFriend() {
beauty.eat();
}
}
创建测试类:
package com.monkey1024.proxy.staticproxy;
public class Test {
public static void main(String[] args) {
XiaoMan xiaoMan = new XiaoMan();
NaNa naNa = new NaNa(xiaoMan);
You you = new You(naNa);
you.makeFriend();
}
}
动态代理
动态代理它可以直接给某一个目标对象生成一个代理对象,而不需要代理类存在。动态代理与静态代理原理是一样的,只是它没有具体的代理类,直接在程序运行时动态生成了一个代理对象。
动态代理的技术实现:
- JDK提供的动态代理,底层使用反射原理,只能创建接口的代理。
- cglib,底层是通过使用一个小而快的字节码处理框架ASM,可以创建类和接口的代理。
jdk的动态代理:
-
Proxy.newProxyInstance():产生代理接口的实例。仅能代理实现至少一个接口的类
- ClassLoader:类加载器。即被代理的接口的类加载器。
- Class[] interface:被代理对象的父接口
- InvocationHandler:将要在代理中实现的功能写在该对象中
-
InvocationHandler中的invoke方法:调用代理类的任何方法,此方法都会执行
- Object proxy:代理对象自身的引用。
- Method method:当前被调用的方法。
- Object[] args:当前被调用方法用到的参数
只需要将之前的测试类中的代码修改为下面的内容即可:
package com.monkey1024.proxy.staticproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Test {
public static void main(String[] args) {
Beauty xiaoMan = new XiaoMan();
//不需要自己创建代理了
//NaNa naNa = new NaNa(xiaoMan);
//由jdk动态的为你创建一个代理
Beauty proxy = (Beauty)Proxy.newProxyInstance(xiaoMan.getClass().getClassLoader(), xiaoMan.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("吃饭之前的准备");
Object invoke = method.invoke(xiaoMan);
System.out.println("吃饭之后的结果");
return invoke;
}
});
You you = new You(proxy);
you.makeFriend();
}
}
调用有参数的方法 在彼此认识之后,你打算送小曼礼物,此时将之前的代码稍作修改:
在接口中新增gift方法,count表示礼物的数量:
void gift(int count);
在XiaoMan的类中添加gift方法的重写:
@Override
public void gift(int count) {
System.out.println("收到" + count + "礼物");
}
在You类中添加show方法用来送礼物:
/**
* 展示
*/
public void show(){
beauty.gift(10);
}
修改之前的测试类如下,送礼物的时候,为了感谢代理人,所以每次会把礼物分一半给代理人:
Beauty xiaoMan = new XiaoMan();
//不需要自己创建代理了
//NaNa naNa = new NaNa(xiaoMan);
//由jdk动态的为你创建一个代理
Beauty proxy = (Beauty)Proxy.newProxyInstance(xiaoMan.getClass().getClassLoader(), xiaoMan.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("准备");
Object invoke = null;
if ("gift".equals(method.getName())){
invoke = method.invoke(xiaoMan,new Object[]{(Integer)args[0]/2});
}else{
invoke = method.invoke(xiaoMan);
}
System.out.println("结果");
return invoke;
}
});
You you = new You(proxy);
you.makeFriend();
you.show();
转自: http://www.monkey1024.com/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/1482