服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - Java代理模式与动态代理之间的关系以及概念

Java代理模式与动态代理之间的关系以及概念

2023-02-28 13:24绿仔牛奶_ Java教程

代理模式是开发中常见的一种设计模式,使用代理模式可以很好的对程序进行横向扩展。动态代理:代理类在程序运行时被创建的代理方式。关键在于动态,程序具有了动态特性,可以在运行期间根据不同的目标对象生成动态代理

什么是代理模式

代理模式是开发中常见的一种设计模式,使用代理模式可以很好的对程序进行横向扩展。代理,顾名思义就是一个真实对象会存在一个代理对象,并且代理对象可以替真实对象完成相应操作,外部通过代理对象来访问真实对象并且还可以在代理对象中进行额外操作的扩展。

代理模式的特征是拥有接口、代理类、被代理类。并且代理类与被代理类同时实现该接口。代理类与被代理类之间通常存在一定关联,设计时会在代理类中注册一个被代理类的对象用于调用代理类的方法。这也印证了代理对象依然是执行的真实对象的方法

代理模式又分为静态代理和动态代理

静态代理

静态代理,关键字静态是指在程序运行之前编译时就已经确定了代理类、被代理类、接口。

下面列举两个示例展示静态代理:

学生通过班长交班费,班长作为学生的代理,学生是被代理,具有同一行为就是交班费,这个行为我们用接口进行约束

程序:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 接口
public interface Person {void giveMoney();}
// 学生类--> 被代理类
public class Student implements Person{
  private String name;
  public Student(String name) {this.name = name;}
  public void giveMoney() {
    System.out.println(name+"同学上交50元班费");
  }
}
// 学生代理类
public class StuProxy implements Person{
  private Student stu;
  public StuProxy(Student stu) {
    if (stu.getClass() == Student.class) {
      this.stu = stu;
    }
  }
  public void giveMoney() {stu.giveMoney();}
}

测试:

?
1
2
3
4
5
6
7
8
public static void main(String[] args) {
  // 获取学生实例 
  Student stu = new Student("张三");
  // 学生找交钱给班长  学生找到代理
  StuProxy stuProxy = new StuProxy(stu);
  // 班长交给老师  代理交钱(交的是学生的钱)
  stuProxy.giveMoney();
}

房屋租赁,租客通过中介找房源,租客为被代理类,中介为代理类,接口声明租房方法

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 接口
public interface Rent {void doRent();}
// 被代理类
public class Renter implements Rent{
  public void doRent() {
    System.out.println("租客租房了");
  }
}
// 代理类
public class RentProxy implements Rent{
  private Renter renter;
  public RentProxy(Renter renter) {
    if (renter.getClass()==Renter.class)
      this.renter = renter;
  }
  public void doRent() {renter.doRent();}
}

测试:

?
1
2
3
4
5
6
7
8
public static void main(String[] args) {
  // 创建租客
  Renter renter = new Renter();
  // 租客找到中介
  RentProxy rentProxy = new RentProxy(renter);
  // 租客租房
  rentProxy.doRent();
}

上述两个示例,向代理类中注入被代理对象的方式都是通过构造器注入,当然也可以通过set方法注入

下面演示如果需要在已经编写好的代理类的输出中添加其他操作时的操作比如打印一个日志,在不修改源代码的情况下扩展

?
1
2
3
4
5
6
7
8
9
10
11
12
13
// 下面是最经典的Service层的写法
public interface UserService {
    void del();
    void select();
}
public class UserServiceImpl implements UserService{
    public void del() {
        System.out.println("删除操作");
    }
    public void select() {
        System.out.println("查询操作");
    }
}

假设现在我们需要在每一次执行操作前后打印一次执行日志,并且不能修改源代码那么就可以用到代理模式,将UserServiceImpl作为被代理类,扩展代理类如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class UserServiceImplProxy implements UserService{
  private UserServiceImpl userService;
  // set注入
  public void setUserService(UserServiceImpl userService) {
    this.userService = userService;
  }
  public void del() {
    printLog();
    userService.del();
  }
  public void select() {
    printLog();
    userService.select();
  }
  private void printLog(){
    System.out.println("执行时间="+new Date());
  }
}

动态代理

动态代理:代理类在程序运行时被创建的代理方式。

关键在于动态,程序具有了动态特性,可以在运行期间根据不同的目标对象生成动态代理对象,并且可以通过动态代理对象对目标对象(真实对象)进行功能性补强。大白话来讲就是,可以在程序运行期间额外的对真实对象功能进行扩展。

此处的动态代理对象不是通过预先编写好的程序生成的,而是运行期间由于用户需求或者说是代码的指示生成的

动态代理分为两种:一类是基于接口实现的动态代理,另一类是基于类的动态代理

基于接口的动态代理–JDK动态代理通过反射完成,基于类实现的–>cglib

JDK动态代理核心:Proxy类、InvocationHandler接口、要参与代理的目标类必须实现对应接口,比如上述的Student必须实现Person接口。

继续以上述学生交班费为例,更改为动态代理模式:

JDK动态代理中间类:该类需要实现InvocationHandler接口

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// JDK动态代理中间类
public class ProxyInvocationHandler implements InvocationHandler {
  // 被代理的对象
  private Object target;
  // ser方法注入参数
  public void setTarget(Object target) {this.target = target;}
  // 生成动态代理类
  public Object getProxy(){
    return Proxy.newProxyInstance(this.getClass().getClassLoader(),
target.getClass().getInterfaces(),this);
  }
  // 处理代理实例,并返回结果
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    Object result = method.invoke(target,args);
    return result;
  }
}

测试:

?
1
2
3
4
5
6
7
8
9
10
11
public static void main(String[] args) {
  // 获取真实角色
  Student stu = new Student("张三三");
  // 动态代理中间类对象
  InvocationHandlerProxyStudent proxyStudent = new InvocationHandlerProxyStudent();
  proxyStudent.setStu(stu);
  // 代理类实例
  Person proxy = (Person) proxyStudent.getProxy();
  // 代理类实例调用方法
  proxy.giveMoney();
}

上述程序,我们利用Proxy来生成代理类:

?
1
2
3
4
public Object getProxy(){
  return Proxy.newProxyInstance(this.getClass().getClassLoader(),
stu.getClass().getInterfaces(),this);
}

Proxy提供了静态的获取Proxy代理类的方法newProxyInstance,三个参数分别是1.类加载器 2.代理对象实现的接口 3. 调用处理程序(InvocationHandler)

在InvocationHandler官方文档就已经指出,每一个代理实例都关联有一个InvocationHandler调用处理程序,所以这里填this即可

在使用代理类的时候首先我们创建需要被代理的真实对象和动态代理中间类的对象,用set方法将真实对象交给中间类中的代理对象。在调用上述getProxy方法获取代理类。动态代理相对于静态代理有些难以理解,这是因为静态代理的代理类可以在程序中显式的被看到,而动态代理中的代理类文件是缓存在Java虚拟机,类名叫$Proxy0。

在虚拟机中生成的代理类中就会将我们所调用的方法内置,我们在执行proxy.giveMoney()的同时,实际上是将giveMoney()方法作为参数传进invoke()的参数中去,而此时我们就可以将其他的操作交给invoke,由于所有代理对象在执行时最终都会走invoke方法,所以也为我们的开发节省大量代码

到此这篇关于Java代理模式与动态代理之间的关系以及概念的文章就介绍到这了,更多相关Java代理模式与动态代理内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/yuqu1028/article/details/129014269

延伸 · 阅读

精彩推荐
  • Java教程Java数据结构之循环队列简单定义与用法示例

    Java数据结构之循环队列简单定义与用法示例

    这篇文章主要介绍了Java数据结构之循环队列简单定义与用法,简要描述了循环队列的概念、原理,并结合实例形式分析了java循环队列的定义与使用方法,需要...

    CharlinGod10542021-01-24
  • Java教程Java中字符编码格式详解

    Java中字符编码格式详解

    在java应用软件中,会有多处涉及到字符集编码,有些地方需要进行正确的设置,有些地方需要进行一定程度的处理。本文主要给大家讲解java中字符的编码...

    leesf3432020-04-12
  • Java教程Spring Bean的线程安全问题

    Spring Bean的线程安全问题

    Spring容器中的Bean是否线程安全,本文主要介绍了Spring Bean的线程安全问题,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可...

    Trouvailless6022023-02-09
  • Java教程java用类加载器的5种方式读取.properties文件

    java用类加载器的5种方式读取.properties文件

    这篇文章主要介绍了java用类加载器的5种方式读取.properties文件,详细的介绍了这5种方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起...

    技术让世界更精彩11362021-06-14
  • Java教程java单例模式学习示例

    java单例模式学习示例

    java中单例模式是一种常见的设计模式,单例模式分三种:懒汉式单例、饿汉式单例、登记式单例三种,下面提供了单例模式的示例 ...

    java技术网4672019-10-30
  • Java教程java的Jackson将json字符串转换成泛型List

    java的Jackson将json字符串转换成泛型List

    这篇文章主要介绍了java的Jackson将json字符串转换成泛型List ,这里整理了详细的代码,有需要的小伙伴可以参考下。...

    Hotao學6482020-08-04
  • Java教程使用dubbo+zookeeper+spring boot构建服务的方法详解

    使用dubbo+zookeeper+spring boot构建服务的方法详解

    这篇文章主要给大家介绍了关于如何使用dubbo+zookeeper+spring boot构建服务的相关资料,文中通过示例代码及图片介绍的非常详细,需要的朋友可以参考借鉴,...

    神牛步行33922021-04-28
  • Java教程简述IDEA集成Git在实际项目中的运用

    简述IDEA集成Git在实际项目中的运用

    这篇文章主要介绍了IDEA集成Git在实际项目中的运用,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...

    人无名,则可专心练剑7602021-10-21