前言:
最近看了一节黑马讲师阿玮老师的Java基础课 -动态代理,现将笔记和总结汇总。因为是结合自己平时记笔记和看笔记的习惯,再加上一些通俗的语言。所以,不喜勿喷,不喜勿喷,不喜勿喷。
问题抛出:
1.为什么需要代理?
2.代理长什么样?
3.Java通过什么来保证代理的样子?
第一个问题:为什么需要代理?
代理可以在不改变原先方法代码的基础上,无侵入式的给对象增强其他的功能。
其调用模式为:调用者-》代理-》对象
对象只负责实现自身的业务逻辑,其他需要实现的业务则需要请一个对象帮忙实现,这个帮忙的对象就是代理对象。这样调用者想要调用目标对象之前,就需要先调用该目标对象的代理,然后再通过代理去调用目标对象。如果调用者直接调用对象的话,那这个对象只会实现自身的业务,而其它的业务就不会实现。
第二个问题:代理长什么样?
代理里面就是对象要被代理的方法
代理类Proxy在java.lang.reflect包下,该类中有一个静态方法newProxyInstance,就是用来创建代理,该方法中有三个参数,其作用分别为:
-
参数一:用于指定哪个类加载器,去加载生成的字节码文件
-
参数二:指定接口,用于指定生成的代理长什么样,也就是需要代理对象中的方法
-
参数三:用来指定生成的代理对象需要干什么事情
其中参数三通过匿名内部类的方式实现具体的业务逻辑。
第三个问题:Java通过什么来保证代理的样子
通过接口保证,后面的对象和代理需要实现同一个接口,接口中就是被代理的所有方法
代码实现:
废话不说上代码:
被代理的对象:
创建一个JavaBean对象,也就是目标对象,该对象有一个属性为name,还有两个方法 ,分别为sing(唱歌)和dance(跳舞)。
public class BigStar implements Star {
private String name;
public BigStar() {
}
public BigStar(String name) {
this.name = name;
}
/**
* 唱歌
* @param songName
* @return
*/
public String sing(String songName) {
System.out.println(this.name + "正在唱歌" + songName);
return "谢谢";
}
/**
* 跳舞
*/
public void dance() {
System.out.println(this.name + "正在跳舞");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
指定接口:
创建一个接口,里面则是需要被代理的方法
public interface Star {
public String sing(String songName);
public void dance();
}
代理对象:
创建代理对象,通过createProxy方法创建代理,其中通过代理类Proxy调用newProxyInstance方法,再传入三个参数:
ProxyUtil.class.getClassLoader()作用:加载生成的字节码文件
new Class[]{Star.class}作用:指定接口
new InvocationHandler()作用:通过匿名内部类的方式指定生成的代理对象需要干什么事情
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyUtil {
/**
* 创建代理
* @param bigStar 被代理的对象
*/
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("--------开始调用方法" + method.getName() + "--------");
System.out.println("明星准备唱歌了...");
}else if("dance".equals(method.getName())) {
System.out.println("--------开始调用方法" + method.getName() + "--------");
System.out.println("明星开始跳舞了...");
}
return method.invoke(bigStar, args);
}
}
);
return star;
}
}
测试类:
public class Test {
public static void main(String[] args) {
//获取代理对象
BigStar bigStar = new BigStar("鸡哥");
Star proxy = ProxyUtil.createProxy(bigStar);
//调用方法
String res = proxy.sing("《你好,我有一个毛衫》");
System.out.println(res);
proxy.dance();
}
}
运行结果:

执行流程:
讲完整体逻辑之后,我们来看一下具体的执行流程吧:
首先,由Test(调用者)类先调用代理获取代理对象,再由代理对象调用sing方法,在方法的底层会自动调用匿名内部类中的invoke方法,将sing方法和参数歌名分别传递给method和args对象。这时,invoke方法中通过if语句判断需要执行的对应的业务,之后method调用其invoke方法通过反射机制调用并传参给BigStar类中的sing方法,最后通过return将字符串“谢谢”返回给res打印出来


被折叠的 条评论
为什么被折叠?



