我的编程空间,编程开发者的网络收藏夹
学习永远不晚

java面试常见模式问题---代理模式

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

java面试常见模式问题---代理模式

  • 本篇总结的是 代理设计模式,后续会经常更新~
  • 代理模式最直观的解释就是,通过代理,将被代理对象 “增强”!(即,扩展被代理对象的功能)
  • 代理模式分为静态代理,和动态代理:动态代理的代理类是动态生成的 , 静态代理的代理类是我们提前写好的逻辑。
  • Java 中实现动态代理的方式有 2 种:
  • JDK 动态代理
  • CGLIB 动态代理

1、静态代理

静态代理角色分析

  • 抽象角色 :一般使用接口或者抽象类来实现。
  • 真实角色 :被代理的角色。
  • 代理角色: 代理真实角色 , 代理真实角色后 ,一般会做一些附属的操作。
  • 调用方:使用代理角色来进行一些操作。

我们以租客租客租房子为例,涉及到的对象有:租客、中介、房东。(房东即为被代理对象,中介即为代理对象)

租客通过中介之手租住房东的房子,代理对象中介需要寻找租客租房,并从中获取中介费用。

代码实现

Rent.java 即抽象角色


// 抽象角色:租房
public interface Rent {
   public void rent();
}

Host.java 即真实角色


// 真实角色: 房东,房东要出租房子
public class Host implements Rent{
   public void rent() {
       System.out.println("房屋出租");
  }
}

Proxy.java 即代理角色


//代理角色:中介
public class Proxy implements Rent {
   private Host host;
   public Proxy() { }
   public Proxy(Host host) {
       this.host = host;
  }
   // 租房
   public void rent(){
       seeHouse();
       host.rent();
       fare();
  }
   // 看房
   public void seeHouse(){
       System.out.println("带房客看房");
  }
   // 收中介费
   public void fare(){
       System.out.println("收中介费");
  }
}

Client.java 调用方,即客户


// 客户类,一般客户都会去找代理!
public class Client {
   public static void main(String[] args) {
       // 房东要租房
       Host host = new Host();
       // 中介帮助房东
       Proxy proxy = new Proxy(host);
       // 你去找中介!
       proxy.rent();
  }
}

静态代理的缺点

需要手动创建代理类,如果需要代理的对象多了,那么代理类也越来越多。

为了解决,这个问题,就有了动态代理 !

2、动态代理

说到动态代理,面试的时候肯定会问动态代理的两种实现方式:

先来看公共的 UserService 接口,和 UserServiceImpl 实现类:



public interface UserService {
    
    void login();
    
    void logout();
}


public class UserServiceImpl implements UserService{
    @Override
    public void login() {
        System.out.println("用户登录...");
    }
    @Override
    public void logout() {
        System.out.println("用户推出登录...");
    }
}

JDK 动态代理

代码如下



public class JDKProxyFactory implements InvocationHandler {
    // 目标对象(被代理对象)
    private Object target;
    public JDKProxyFactory(Object target) {
        super();
        this.target = target;
    }
    
    public Object createProxy() {
        // 1.得到目标对象的类加载器
        ClassLoader classLoader = target.getClass().getClassLoader();
        // 2.得到目标对象的实现接口
        Class<?>[] interfaces = target.getClass().getInterfaces();
        // 3.第三个参数需要一个实现invocationHandler接口的对象
        Object newProxyInstance = Proxy.newProxyInstance(classLoader, interfaces, this);
        return newProxyInstance;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("JDK 动态代理:登录/登出前逻辑校验......");
        Object invoke = method.invoke(target, args);
        System.out.println("JDK 动态代理:登录/登出后日志打印......");
        return invoke;
    }
    public static void main(String[] args) {
        // 1.创建对象
        UserServiceImpl userService = new UserServiceImpl();
        // 2.创建代理对象
        JDKProxyFactory jdkProxyFactory = new JDKProxyFactory(userService);
        // 3.调用代理对象的增强方法,得到增强后的对象
        UserService userServiceProxy = (UserService) jdkProxyFactory.createProxy();
        userServiceProxy.login();
        System.out.println("==================================");
        userServiceProxy.logout();
    }
}

输出结果如下

JDK 动态代理:登录/登出前逻辑校验......
用户登录...
JDK 动态代理:登录/登出后日志打印......
==================================
JDK 动态代理:登录/登出前逻辑校验......
用户推出登录...
JDK 动态代理:登录/登出后日志打印......

CGLIB 动态代理

代码如下:



public class CglibProxyFactory implements MethodInterceptor {
    // 目标对象(被代理对象)
    private Object target;
    // 使用构造方法传递目标对象
    public CglibProxyFactory(Object target) {
        super();
        this.target = target;
    }
    
    public Object createProxy() {
        // 1.创建Enhancer
        Enhancer enhancer = new Enhancer();
        // 2.传递目标对象的class
        enhancer.setSuperclass(target.getClass());
        // 3.设置回调操作
        enhancer.setCallback(this);
        return enhancer.create();
    }
    
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("cglib 动态代理:登录/登出前逻辑校验......");
        Object invoke = method.invoke(target, objects);
        System.out.println("cglib 动态代理:登录/登出后日志打印......");
        return invoke;
    }
    public static void main(String[] args) {
        // 1.创建对象
        UserServiceImpl userService = new UserServiceImpl();
        // 2.创建代理对象
        CglibProxyFactory cglibProxyFactory = new CglibProxyFactory(userService);
        // 3.调用代理对象的增强方法,得到增强后的对象
        UserService userServiceProxy = (UserService) cglibProxyFactory.createProxy();
        userServiceProxy.login();
        System.out.println("==================================");
        userServiceProxy.logout();
    }
}

测试结果如下

cglib 动态代理:登录/登出前逻辑校验......
用户登录...
cglib 动态代理:登录/登出后日志打印......
==================================
cglib 动态代理:登录/登出前逻辑校验......
用户推出登录...
cglib 动态代理:登录/登出后日志打印......

面试题一:JDK动态代理和CGLIB动态代理区别?

① JDK 动态代理本质上是实现了被代理对象的接口,而 CGLib 本质上是继承了被代理对象,覆盖其中的方法。

② JDK 动态代理只能对实现了接口的类生成代理,CGLib 则没有这个限制。但是 CGLib 因为使用继承实现,所以 CGLib 所以无法对 final private 方法static方法进行代理。

③ JDK 动态代理是 JDK 里自带的,CGLib 动态代理需要引入第三方的 jar 包。

④ 在调用代理方法上,JDK动态代理是通过反射机制调用,CGLib 是通过 FastClass 机制直接调用。(看过一篇文章,介绍说 FastClass 简单的理解,就是使用一个 index 下标作为入参,可以直接定位到要调用的方法直接,并进行调用)

在性能上,JDK1.7 之前,由于使用了 FastClass 机制,CGLib 在执行效率上比 JDK 快,但是随着 JDK 动态代理的不断优化,从 JDK 1.7 开始,JDK 动态代理已经明显比 CGLib 更快了。

面试题二:JDK 动态代理为什么只能对实现了接口的类生成代理?

根本原因是通过 JDK 动态代理生成的类已经继承了 Proxy 类,所以无法再使用继承的方式去对类实现代理。

总结

文章会不定时更新,有时候一天多更新几篇,如果帮助您复习巩固了知识点,还请三连支持一下,后续会一点点的更新!希望大家多多关注编程网的其他内容!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

java面试常见模式问题---代理模式

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

java中代理模式的面试题有哪些

小编给大家分享一下java中代理模式的面试题有哪些,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!1、静态代理静态代理角色分析:抽象角色 :一般使用接口或者抽象类来
2023-06-15

PHP设计模式:常见问题解答

php 设计模式主要用于解决常见编程问题,包含以下解决方案:观察者模式:通过分离对象和事件,实现松耦合。单例模式:确保一个类只有一个实例。策略模式:通过交换算法,实现可扩展性。PHP 设计模式:常见问题解答简介设计模式是可重用的软件解决
PHP设计模式:常见问题解答
2024-05-13

常见的Java面试问题

JVMJava虚拟机(JVM)是运行 Java 字节码的虚拟机。JVM有针对不同系统的特定实现(Windows,Linux,macOS),目的是使用相同的字节码,它们都会给出相同的结果。什么是字节码?采用字节码的好处是什么?在 Java 中
2023-06-03

java常见面试题整理

面向对象的特征有哪些方面? 所谓封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。封装是面向对象的特征之一,是对象和类概念的主要特性。 (推荐学习:java常见面试题)继承是指子类获得父类的
java常见面试题整理
2016-08-28

java设计模式笔记之代理模式

代理(Proxy)模式:代理模式是对象的结构模式。代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。核心作用:通过代理,控制对对象的访问。可以详细控制访问某个(某类)对象的方法,在调用这个方法之前做前置处理,在调用这个方
2023-05-31

java设计模式学习之代理模式

代理模式(Proxy):为其他对象提供一种代理以控制对这个对象的访问。代理模式结构图模拟需求:3班小张喜欢1班小红,但是不认识小红,委托1班小明送给小红礼物。1:创建一个小张和小明都能实现的接口。package ProxyModel;/**
2023-05-31

S模式下的Windows10和Windows11常见问题解答

在S模式下的Windows10和Windows11常见问题解答:1. 什么是S模式?S模式是一种安全模式,限制用户只能安装和运行来自Microsoft Store的应用程序。这可以提高系统的安全性和稳定性。2. 如何退出S模式?在Windo
2023-09-14

Java常见设计模式有哪些

这篇文章主要介绍Java常见设计模式有哪些,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、设计模式总述:1、什么是设计模式:设计模式是一套经过反复使用的代码设计经验,目的是为了重用代码、让代码更容易被他人理解、保证
2023-06-29

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录