一. 什么是动态代理
- 假设Student里面有一个吃饭的eat方法,那么现在我要给这个方法去增加其他的功能,比如说吃饭之前,要去拿筷子,要去盛饭,按照以前所学,我们只能把这两段代码都写在eat方法当中,那此时直接去修改代码,是叫做侵入式修改。
- 在以后在一个成熟的项目当中,我们一般很少会这么去干。
- 那么问题来了,我现在又不能去修改原有的代码,又要去增加额外的功能,那这个时候我该怎么办呢?
- 此时我们就得去找一个代理,什么是代理,说白了就是中介公司。
- 代理会帮你先去做拿筷子和盛饭这两个准备工作,等真正的吃饭了再去调用Student里面的方法去吃饭,这个呢其实就是动态代理。
1.为什么需要代理呢?
- 代理可以无侵入式的给对象增强其他的功能。
- 当调用者去调用对象中的方法的时候,其实呢不是直接通过对象去调用,而是先去调用代理中的方法,代理会做一些准备工作,然后呢再由代理去调用对象中的方法,是有这样的一个过程
二. 程序为什么需要代理?代理长什么样?
程序为什么需要代理?
- 说白了就是因为如果对象任务自己身上干的事情太多了,就可以通过代理转义部分的职责。
那么中介派出的这个代理它是长什么样子的呢?
- 代理里面就是对象要被代理的所有的方法
- 在代码当中代理长什么样子,说白了就是代理的里面可以写什么样的方法。
- 代理长什么样子,其实是跟对象差不多的。
- 对象要有什么方法想要被代理,那么代理呢也要有对应的方法,只不过方法里面干的事情是不太一样的,代理它会先把准备工作做完,然后再去调用对象中的方法。
- 代理是通过接口去知道对象想要代理的方法,在这个接口里面所有的方法就是我们想要代理的方法。
- 左边的代理和右边的对象都要去实现中间的这个接口才是可以的!
- 为什么需要代理?
- 代理可以无侵入式的给对象增强其他的功能。
- 代理长什么样?
- 代理里面就是对象要被代理的所有的方法。
- Java通过什么来保证代理的样子?
- Java通过接口保证代理的样子,对象和代理需要实现同一个接口,接口中就是被代理的所有的方法。
三. 如何为Java对象创建一个代理对象
package com.gch.d10_dynamic_proxy;/**定义大明星类:模拟对象*/
public class BigStar implements Star{private String name;public BigStar() {}public BigStar(String name) {this.name = name;}/*** 唱歌* @param name:歌曲的名字* @return:"谢谢"*/@Overridepublic String sing(String name){System.out.println(this.name + "正在唱" + name);return "谢谢";}/**跳舞*/@Overridepublic 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 + "}";}
}
package com.gch.d10_dynamic_proxy;/**接口:接口当中定义的是对象所有想要被代理的方法(抽象方法)我们可以把所有想要被代理的方法定义在接口当中*/
public interface Star {/*** 唱歌* @param name:歌曲名*/public abstract String sing(String name);/**跳舞*/public abstract void dance();
}
package com.gch.d10_dynamic_proxy;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/*** 代理类* 类的作用:创建一个代理*/
public class ProxyUtil {/*** 方法的作用:给一个对象,去创建一个代理对象* 方法的返回值类型直接写接口的类型,因为我们的代理也是要去实现接口的* @param bigstar:形参:被代理的明星对象* @return 返回值:给明星创建的代理对象*/public static Star createProxy(BigStar bigstar){/*** java.lang.reflect.Proxy类:提供了为对象产生代理对象的方法:* public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)* 参数一:用于指定用哪个类加载器,去加载生成的代理类 是类加载器把类的字节码文件加载到内存当中的* 参数二:指定接口,这些接口用于指定生成的代理长什么,也就是有哪些方法* 参数三:用来指定生成的代理对象要干什么事情*/Star star = (Star) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(), // 参数一:用于指定用哪个类加载器,去加载生成的代理类new Class[]{Star.class} // 参数二:指定接口,这个就表示我们生成的这个代理,也就是中介,它可以代理Star这个接口里面所有的方法, new InvocationHandler() { // 参数三:用来指定生成的代理对象要干什么事情@Override/*** 用来指定生成的代理对象要干什么事情 invoke:调用* 参数一:表示代理的对象,重点看参数二和参数三* 参数二:要运行的方法 sing,dance...* 参数三:调用sing方法时,传递的实参*/public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if("sing".equals(method.getName())){System.out.println("准备话筒,收钱");}else if("dance".equals(method.getName())){System.out.println("准备场地,收钱");}// 代理去找大明星开始唱歌或者跳舞// 代码的表现形式:调用大明星里面唱歌或者跳舞的方法return method.invoke(bigstar,args);}});return star;}
}
package com.gch.d10_dynamic_proxy;/**需求:外面的人想要大明星唱一首歌1.获取代理对象代理对象 = ProxyUtil.createProxy(大明星的对象);2.再调用代理的唱歌方法代理对象.唱歌的方法("只因你太美");*/
public class Test {public static void main(String[] args) {// 1.创建对象BigStar bigStar = new BigStar("鸡哥");// 2.获取代理的对象 proxy:代理Star proxy = ProxyUtil.createProxy(bigStar);// 3.调用唱歌的方法String result = proxy.sing("只因你太美");System.out.println(result);// 4.调用跳舞的方法proxy.dance();}
}