反射的应用动态代理【Java】
写在前面的话:
- 参考资料:尚硅谷视频
- 本章内容:Java反射的实际应用动态代理
- IDE:eclipse
- JDK:Java8
目录
2.3.1 创建实现InvocationHandler接口的类
1.静态代理
静态代理:
- 每一个代理类只能为一个接口服务
- 在编译阶段,就确定了目标对象
示例代码
测试类
package static_proxy;
public class TestProxy {
public static void main(String[] args) {
//创建一个学生
Student student1 = new Student("张三","男",0);
//创建一个学生
Student student2 = new Student("小花","女",0);
System.out.println(student1);
System.out.println(student2);
//创建一个代理类
ProxyStudent proxyStudent = new ProxyStudent(new Teacher());
//给student[张三]打分
proxyStudent.giveStudentScore(student1, 78.5);
//给student[小花]打分
proxyStudent.giveStudentScore(student2, 89.2);
//打印输出学生信息
System.out.println(student1);
System.out.println(student2);
}
}
老师类
package static_proxy;
/*
* 【被代理类】
* 老师类 : 对学生进行打分
*/
public class Teacher implements GiveScore {
@Override
public void giveStudentScore(Student student,double score) {
//设置学生分数
student.setScore(score);
System.out.println("给" + student.getName() + "分数:" + score);
}
}
代理学生类
package static_proxy;
/*
* 【代理类】
* 由老师指派的一些学生进行打分
*/
public class ProxyStudent implements GiveScore{
GiveScore giveScore;
public ProxyStudent(Teacher teacher) {
super();
this.giveScore = teacher;
}
@Override
public void giveStudentScore(Student student,double score) {
System.out.print("[代理学生]");
giveScore.giveStudentScore(student, score);
}
}
学生类
package static_proxy;
import java.util.Objects;
public class Student {
private String name;//姓名
private String sex;//性别
private int id;//学号
private double score;//分数
private static int count;//学生个数
/**
* 创建一个学生
* @param name 姓名
* @param sex 性别
* @param score 分数
*/
public Student(String name, String sex, double score) {
super();
count++;
this.id = count;
this.name = name;
this.sex = sex;
this.score = score;
}
public Student() {
super();
count++;
this.id = count;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
@Override
public int hashCode() {
return Objects.hash(id, name, score, sex);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
return id == other.id && Objects.equals(name, other.name) && score == other.score
&& Objects.equals(sex, other.sex);
}
@Override
public String toString() {
return "学生[id=" + id + ",name=" + name + ", sex=" + sex +", score=" + score + "]";
}
}
接口:给出学生分数
package static_proxy;
/*
* 功能:给学生打分
*/
public interface GiveScore {
/**
* 给出学生分数
* @param student 给哪一个学生打分
* @param score 打分的多少
*/
public void giveStudentScore(Student student,double score);
}
通过代理,我们不需要创建老师这个对象,通过代理学生就可以完成对学生进行打分
效果截图:
2.动态代理
2.1 动态代理基本概念
动态代理是指客户通过代理类来调用其它对象的方法,并且是在程序运行时根据需要动态创建目标类的代理对象。(动态代理是什么?)
动态代理具体使用场合:
- 调试
- 远程方法调用
代理设计模式的原理:
使用一个代理将对象包装起来, 然后用该代理对象取代原始对象. 任何对原始对象的调用都要通过代理. 代理对象决定是否以及何时将方法调用转到原始对象上。
2.2 代码示例
上面的代码有些还可以利用:老师类、学生类、接口
ProxyInvocationHandler类:专门用来创建一个代理类【将获取代理类对象封装起一个方法】
package dynamic_proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/*
* 代理类
*/
//动态代理要实现接口:InvocationHandler
public class ProxyInvocationHandler implements InvocationHandler{
//实现了接口的被代理类的对象的声明【在这里:老师类对象的声明】
Object object;
//创建代理类的对象
public Object create(Object object) {
this.object = object;//实例化被代理类的对象
//返回代理类的实例化对象
return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),this);
}
//重写接口中的方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.print("[代理类]");
Object returnValue = method.invoke(object,args);//调用object的方法
//返回调用方法的返回值
return returnValue;
}
}
TestProxy类:用来测试用的
package dynamic_proxy;
public class TestProxy {
public static void main(String[] args) {
//1.创建一个被代理类
Teacher teacher = new Teacher();
//2.创建一个实现了InvocationHandler接口的类的对象
ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler();
//3.创建一个代理类【该代理类同样实现了被代理类实现接口GiveScore】
GiveScore proxy = (GiveScore) proxyInvocationHandler.create(teacher);//填入的是被代理类
//4.创建一个学生【被代理类要操作的对象】
Student student = new Student("张三","男",0);
System.out.println(student);
//5.通过代理类可以调用方法【调用的方法与被代理类一致】
proxy.giveStudentScore(student, 78.5);
System.out.println(student);
}
}
2.3 动态代理讲解
2.3.1 创建实现InvocationHandler接口的类
InvocationHandler 接口要实现动态代理,这是代码中重要的一部分
2.3.2 获取代理类的对象
获取代理类的对象
2.3.3 使用代理类
主要分为5个步骤:
- 创建一个被代理类
- 创建一个实现了InvocationHandler接口的类的对象【相当于代理类仓库】
- .创建一个代理类【该代理类同样实现了被代理类实现接口GiveScore】
- 创建一个学生【被代理类要操作的对象】
- 通过代理类可以调用方法【调用的方法与被代理类一致】
效果截图:
3. 静态代理与动态代理的区别?
区别:
- 静态代理中每一个代理类只能为一个接口服务,否则容易出错
- 静态代理如果一些被代理类实现的接口不同,需要另外创建代理类【与第1点类似】
- 动态代理只需要创建一个实现了InvocationHandler接口的类的对象
- 动态代理通过实现了InvocationHandler接口的类的对象 获取不同的代理类(即无需另外去创建代理类)
- 总的来说,动态代理必须创建一个实现了InvocationHandler接口的类的对象!
代码示例(通过代码来深入了解动态代理的好处)
新创建一个接口:功能是布置作业
package dynamic_proxy;
/*
* 布置作业
*/
public interface Homework {
/**
* 布置作业
* @param content 作业内容
* @param student 具体哪一个学生
*/
public void assignHomework(Student student,String content);
}
再创建一个Machine类:通过机器实现布置作业
package dynamic_proxy;
/*
* 再创建一个被代理类
*/
//实现接口Homework
public class Machine implements Homework{
@Override
public void assignHomework(Student student,String content) {
System.out.println("机器给" + student.getName() + "布置的作业为:" + content);
}
}
从这里开始,将分为动态代理和静态代理两部分来讲解
如果是动态代理的话,直接获取代理类即可
动态代理完整源码:
package dynamic_proxy;
public class TestProxy {
public static void main(String[] args) {
//1.创建一个被代理类
Teacher teacher = new Teacher();
//2.创建一个实现了InvocationHandler接口的类的对象
ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler();
//3.创建一个代理类【该代理类同样实现了被代理类实现接口GiveScore】
GiveScore proxy = (GiveScore) proxyInvocationHandler.create(teacher);//填入的是被代理类
//4.创建一个学生【被代理类要操作的对象】
Student student = new Student("张三","男",0);
System.out.println(student);
//5.通过代理类可以调用方法【调用的方法与被代理类一致】
proxy.giveStudentScore(student, 78.5);
System.out.println(student);
/*
* 再增加一个被代理类
*/
Student student2 = new Student("小红","女",0);
Machine machine = new Machine();
System.out.println(student2);
//获取代理类
Homework proxy1 = (Homework) proxyInvocationHandler.create(machine);
proxy1.assignHomework(student2, "背古诗");
}
}
效果截图:
静态代理 :需要返回代理类,进行添加相应的构造器(参数:被代理类的对象的声明)
添加构造器,被代理类的实现接口
添加了新的实现接口,需要重写相应的重写方法
在一个代理类中修改后,会出现一定的问题。
- 比如你代理的是Teacher,那么该代理是可以访问assignHomework方法,这会导致空指针异常。
- 这样,该代理类就不合理。我们应该创建2个不同的代理类 【这就是静态代理是一个代理类只能访问一个接口的原因】
所以在使用代理类的时候,需要特别注意一些代码,要将其注释掉
静态代理完整代码:
package static_proxy;
public class TestProxy {
public static void main(String[] args) {
//创建一个学生
Student student1 = new Student("张三","男",0);
//创建一个学生
Student student2 = new Student("小花","女",0);
System.out.println(student1);
System.out.println(student2);
//创建一个代理类
ProxyStudent proxyStudent = new ProxyStudent(new Teacher());
ProxyStudent proxyStudent2 = new ProxyStudent(new Machine());
//给student[张三]打分
proxyStudent.giveStudentScore(student1, 78.5);
// proxyStudent.assignHomework(student1,"背书");
//给student[小花]打分
// proxyStudent2.giveStudentScore(student2, 89.2);
proxyStudent2.assignHomework(student1,"写字");
//打印输出学生信息
System.out.println(student1);
System.out.println(student2);
}
}
效果截图:
完
【最后】附上项目结构图:
静态代理:
动态代理
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧