动态代理
学无止境,学无止境,根本停不下来。
什么是动态代理?
现在有一个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通过什么来保证代理的样子?
- 通过接口保证,对象和代理需要实现同一个接口,接口中就是被代理的所有方法
我是一个转码的小白,平时会在牛客中做选择题,在做题中遇到不会的内容就会去找视频或者文章学习,以此不断积累知识。这个专栏主要是记录一些我通过做题所学到的基础知识,希望能对大家有帮助
查看21道真题和解析