动态代理
学无止境,学无止境,根本停不下来。
什么是动态代理?
现在有一个Student类,里面有吃饭方法。
public class Student{ public void eat(){ System.out.println("吃饭"); } }
现在我要给这个方法添加其他功能,比如:
System.out.println("拿筷子"); System.out.println("盛饭");
按以前所学,我们只能把这两句话放入eat()方法中,直接修改代码,被称为侵入式修改。在一个成熟的项目中,我们很少会这么去干,因为可能会整个项目坍塌。那我既不能修改原有的代码,还要增加新的功能,那我怎么办?此时我们就得去找一个代理,什么是代理,说白了就是中介公司,他会帮你先去做拿筷子和盛饭的这些准备工作,等真正吃饭了,再去调用Student里的方法,这就叫做动态代理。
动态代理,可以侵入式的给代码增加额外的功能。
那程序为什么需要代理?代理长什么样?将一个小故事,一个关于鸡哥的小故事(我不是小黑子哦)。鸡哥是一个大明星,他会唱歌、跳舞,在程序中反映出来就是唱歌和跳舞两个方法。鸡哥是一个大明星,唱歌跳舞肯定不能随便,得先准备话筒和场地,准备话筒收钱以及准备场地收钱。那这两个新增功能是写在自己的方法中吗?想一下鸡哥是一个大明星,他自己做这两件事烦不烦,就把这两件事交个中介公司,公司会派一个代理人打理这些事
唱歌(){ 真正开始唱歌; } 跳舞(){ 真正开始跳舞; } 代理{ 准备话筒,收钱; 准备场地,收钱; }
所以为什么程序需要代理?就是因为对象如果嫌身上干的事太多的话,可以通过代理来转移部分职责。那这个代理长什么样呢?就是说这个代理里面能写什么方法,肯定是有唱歌和跳舞的方法,因为其他人找鸡哥都是要先找代理。但是代理肯定不会唱跳,而是你找我唱歌,那我先收你钱,然后再调用鸡哥的唱歌方法,让唱。
说白了代理长什么样子,其实是和对象差不多的。对象有什么方法想被代理,代理就一定要有对应的方法,只不过代理要把准备工作先做完,然后再去调用对象中的方法。那代理如何能知道鸡哥要代理唱歌和跳舞这两个方法呢?万一还有第三个打篮球呢?代码中通过接口搞定,事先定义一个接口,有唱歌和跳舞的方法,这个接口中所有的方法就是我们想代理的方法。左边的代理和右边的鸡哥都要实现接口才可以。
public class BigStar implements Star { private String name; public BigStar() { } public BigStar(String name) { this.name = name; } //唱歌 @Override public String sing(String name){ System.out.println(this.name + "正在唱" + name); return "谢谢"; } //跳舞 @Override public void dance(){ System.out.println(this.name + "正在跳舞"); } /** * 获取 * @return name */ public String getName() { return name; } /** * 设置 * @param name */ public void setName(String name) { this.name = name; } public String toString() { return "BigStar{name = " + name + "}"; } }
public interface Star { //我们可以把所有想要被代理的方法定义在接口当中 //唱歌 public abstract String sing(String name); //跳舞 public abstract void dance(); }
如何为java对象创建一个代理对象呢?
- java.lang.reflect.Proxy类:提供了为对象产生代理对象的方法:
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) //参数一:用于指定用哪个类加载器,去加载生成的代理类 //什么是类加载器呢?就是Java在运行的时候,需要有一个人把字节码文件加载到内存当中,就是类加载器去加载的 //参数二:指定接口,这些接口用于指定生成的代理长什么样,也就是有哪些方法 //参数三:用来指定生成的代理对象要干什么事情
/* 类的作用:创建一个代理 */ public class ProxyUtil { /* 方法的作用: 给一个明星的对象,创建一个代理 形参: 被代理的明星对象 返回值: 给明星创建的代理 需求: 外面的人想要大明星唱一首歌 1. 获取代理的对象 代理对象 = ProxyUtil.createProxy(大明星的对象); 2. 再调用代理的唱歌方法 底层会调用代理类中的invoke() 代理对象.唱歌的方法("只因你太美"); */ public static Star createProxy(BigStar bigStar){ Star star = (Star)Proxy.newProxyInstance( //参数一:用于指定用哪个类加载器,去加载生成的代理类 ProxyUtil.class.getClassLoader(), //参数二:指定接口,这些接口用于指定生成的代理长什么样,也就是有哪些方法 new Class[]{Star.class}, //参数三:用来指定生成的代理对象要干什么事情 new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { /* * 参数一:代理的对象 * 参数二:要运行的方法 sing * 参数三:调用sing方法时,传递的实参 * */ if("sing".equals(method.getName())){ System.out.println("准备话筒,收钱"); }else if("dance".equals(method.getName())){ System.out.println("准备场地,收钱"); } //去找大明星开始唱歌或者跳舞 //代码的表现形式:调用大明星里面唱歌或者跳舞的方法 //反射的知识 return method.invoke(bigStar,args); } } );
创建代理对象并执行方法的过程有些复杂,下面这个图能帮助理解,一个过程图。
总结
最后我们来总结一下代理,要掌握如下几点:
- 为什么需要代理?
- 代理可以无侵入式的给对象增加其他的功能
- 代理长什么样?
- 代理里面就是对象要被代理的方法
- java通过什么来保证代理的样子?
- 通过接口保证,对象和代理需要实现同一个接口,接口中就是被代理的所有方法
我是一个转码的小白,平时会在牛客中做选择题,在做题中遇到不会的内容就会去找视频或者文章学习,以此不断积累知识。这个专栏主要是记录一些我通过做题所学到的基础知识,希望能对大家有帮助