什么是动态代理?
csharp
public class Student {
public void eat() {
System.out.println("吃饭")
}
}
现在我们想给eat方法增加一些东西,让吃饭这个动作更加完整
csharp
public class Student {
public void eat() {
System.out.println("拿筷子");
System.out.println("盛饭");
System.out.println("吃饭");
}
}
这种修改叫做侵入式修改。在一个成熟的项目中,我们很少会这么修改,容易引发一系列连锁问题。
那么问题来了,我现在不能修改原有的代码,又要增加额外的功能,该如何实现?
此时我们可以找一个代理,即一个中介公司,它会先做拿筷子和盛饭这两个动作,等真正吃饭了再调用Student的eat方法吃饭,这就是动态代理,它可以无侵入式地给代码增加额外的功能。可以理解为明星的经纪人。
对象有什么方法想被代理,代理就一定要有对应的方法。代理中对应的方法会先把其它事情做完,再调用原来对象中的方法。
中介如何知道要派有对应方法的代理?这需要通过接口来解决。把被代理的方法写在接口中,让代理和对象都实现这个接口。
arduino
public class BigStar implements Star{
private String name;
public BigStar(String name) {
this.name = name;
}
public BigStar() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "BigStar{" +
"name='" + name + ''' +
'}';
}
//唱歌和跳舞
@Override
public String sing(String name) {
System.out.println(this.name + "正在唱" + name);
return "谢谢";
}
@Override
public void dance() {
System.out.println(this.name + "正在跳舞");
}
}
csharp
public interface Star {
//把所有想要代理的方法定义在接口中
//唱歌和跳舞
public abstract String sing(String name);
public abstract void dance();
}
java.lang.reflect.proxy类提供了为对象产生代理对象的方法
vbnet
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
参数一:用于指定用哪个类加载器,去加载生成的代理类。
参数二:指定接口,这些接口用于指定生成的代理有哪些方法
参数三:指定生成的代理对象要干什么事情
类加载器负责将字节码文件加载到内存当中,通过getClassLoader方法找到是谁把当前这个类的字节码文件加载到内存的。
csharp
public interface Star {
//把所有想要代理的方法定义在接口中
//唱歌和跳舞
public abstract String sing(String name);
public abstract void dance();
}
arduino
public class BigStar implements Star{
private String name;
public BigStar(String name) {
this.name = name;
}
public BigStar() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "BigStar{" +
"name='" + name + ''' +
'}';
}
//唱歌和跳舞
@Override
public String sing(String name) {
System.out.println(this.name + "正在唱" + name);
return "谢谢";
}
@Override
public void dance() {
System.out.println(this.name + "正在跳舞");
}
}
csharp
public class ProxyUtil {
//创建一个代理
//给一个明星对象创建一个代理
//形参:被代理的明星对象,要知道给谁做代理
//返回值:给明星创建的代理
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 {
//参数一:代理的对象
//参数二:要运行的方法
//参数三:方法参数
if("sing".equals(method.getName())) {
System.out.println("准备话筒,收钱");
} else if ("dance".equals(method.getName())) {
System.out.println("准备场地,收钱");
}
//去找大明星开始唱歌或跳舞
//代码里的表现形式:调用大明星里的唱歌或跳舞方法
return method.invoke(bigStar,args);//反射
}
}
);
return star;
}
}
java
public class test {
public static void main(String[] args) {
//需求:粉丝想要大明星唱一首歌
//1.获取代理的对象:代理对象 = ProxyUtil.createProxy(大明星的对象)
//2.再调用代理的唱歌方法,此时会运行invoke
//1.获取代理的对象
BigStar bigStar = new BigStar("鸡哥");
Star proxy = ProxyUtil.createProxy(bigStar);
//2.调用唱歌方法
String res = proxy.sing("只因你太美");
System.out.println(res);
}
}
重点在于理解创建代理的代码。可以理解为给明星配置一个经纪人。