【面试题】2、Docker和Spring相关

2023-11-08

1、Docker是什么?

(1)Docker是一个快速交互、运行应用的技术,可以将程序及其依赖、运行环境一起打包为一个镜像,该镜像可以迁移到任意的Linux操作系统
(2)运行时利用沙箱机制形成隔离容器,各个应用之间互不干扰
(3)移动和移除程序都可通过一行命令完成
(4)Docker 将应用程序及其所需的依赖、函数库、环境、配置等文件打包在一起构成镜像
(5)镜像应用程序运行后形成的进程就是容器,只是 Docker 会给容器做隔离,对外不可见

2、Docker相关命令

(1)镜像命令
① 从DockerHub拉取镜像: docker pull 镜像名
② 查看所有镜像:docker images
③ 保存镜像为一个tar压缩包:docker save -o 文件名.tar 镜像名 【-o:写为文件】
④ 删除一个镜像:docker rmi 镜像名
⑤ 加载压缩包为就像:docker load -q -i 文件名.tar【-q:没有日志输出;-i:读取tar文件】
⑥ 构建镜像:docker build
⑦ 推送镜像到DockHub:docker push


(2)容器命令

① 基于镜像创建并运行容器:docker run --name containerName -p 80:80 -d 镜像名

--name:给容器起一个名字
-p:将宿主机端口与容器端口进行映射【冒号左侧是宿主机端口,右侧是容器端口】
-d:后台运行容器

② 查看所有运行的容器及其状态:docker ps
③ 查看容器运行日志:docker logs 容器ID
④ 进入容器内部执行命令(该命令不是Docker的):docker exec -it 要进入的容器的名称 bash

-it:给当前进入的容器创建一个标准输入输出终端,允许与容器交互
bash:进入容器后执行的命令(bash是一个Linux终端交互命令)

⑤ 删除容器:docker rm(添加-f则是强制删除)

在这里插入图片描述

3、JDK如何实现动态代理?

(1)JDK实现动态代理必须要求被代理的类(目标类)有实现某个接口,因为JDK的代理实现逻辑就是实现目标类的接口
(2)JDK中的Proxy类有个静态方法newProxyInstance,它可以实现静态代理,它的返回值就是代理对象
(3)该方法需要一个ClassLoader类型作为参数(原因:类装载器把字节码装载到JVM后,类装载器会解析字节码,并生成对应字节码的Class对象。每个类都有一个Class对象,一个类能够被实例化的条件是必须有Class对象,Class对象中包含了类的完整信息)
(4)动态代理也叫做动态字节码,字节码在运行时生成,类装载器直接通过运行时生成的字节码创建该字节码的Class对象(减少了装载class文件的过程)
(5)newProxyInstance方法还需要一个Class对象数组(它是目标类实现的接口的Class对象数组),可通过目标类的getInterfaces方法获取
(6)附加代码通过newProxyInstance方法的第三个参数传入,第三个参数可以传入匿名类或InvocationHandler接口的实现类
(7)InvocationHandler接口中invoke方法的第一个参数proxy是代理对象;第二个参数的参数类型是Method,它是目标方法;第三个参数args是目标方法的参数
(8)bean生命周期的BeanPostProcessor可统一处理所有的bean,可在该生命周期中为指定的bean创建代理对象(增加额外功能)
(9)JDK的方式实现动态代理的缺点:假如目标类没有实现任何接口,则无法通过JDK的方式实现动态代理【可通过CGLib进行实现】
(10)MyBatis的SqlSession对象的getMapper方法传入Dao的类对象后可返回Dao的代理对象,MyBatis使用的是JDK的动态代理实现

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

/**
 * 使用BeanPostProcessor生命周期为指定bean生成代理对象
 * 目的是:为Bean增加日志打印的功能
 */
public class LogProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        Class<?> beanCls = bean.getClass();
        Class<?>[] interfaceArr = beanCls.getInterfaces();

        // 如果当前bean没有实现过接口: 无法通过JDK的方式为其增加额外功能
        if (interfaceArr.length < 1) return bean;

        return Proxy.newProxyInstance(
            getClass().getClassLoader(),
            interfaceArr,
            new LogInvocationHandlerImpl(bean)
        );
    }

    /**
     * 实现InvocationHandler接口, 重写它的invoke方法(编写附加代码)
     */
    private static class LogInvocationHandlerImpl implements InvocationHandler {
        private final Object targetBean;

        public LogInvocationHandlerImpl(Object targetBean) {
            this.targetBean = targetBean;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("LogInvocationHandlerImpl 附加代码1");
            Object retVal = method.invoke(targetBean, args);
            System.out.println("LogInvocationHandlerImpl 附加代码2");
            return retVal;
        }
    }
}

4、CGLib如何实现动态代理?

(1)CGLib在Spring框架中已有集成,它的实现逻辑是:让代理类继承目标类
(2)创建CGLib库的Enhancer类的实例,并设置类加载器、设置目标类的类对象、通过MethodInterceptor接口设置附加代码,最后调用该实例的create方法
(3)bean生命周期的BeanPostProcessor可统一处理所有的bean,可在该生命周期中为指定的bean创建代理对象(增加额外功能)
(4)CGLib相比JDK的动态代理实现方案比较灵活,不要求目标类必须实现接口

在这里插入图片描述

/**
 * 通过CGLib的方式为指定目标类的目标方法增加额外功能, 生成该目标类的代理类
 */
public class LogProcessorByCGLib implements BeanPostProcessor {

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        Enhancer enhancer = new Enhancer();
        // 设置类加载器
        enhancer.setClassLoader(getClass().getClassLoader());
        // 设置目标类
        enhancer.setSuperclass(bean.getClass());
        // 设置目标代码
        enhancer.setCallback(new LogMethodInterceptorImpl(bean));

        return enhancer.create(); // 创建代理类
    }

    /**
     * 实现MethodInterceptor接口, 增加附加功能
     * MethodInterceptor是Callback接口的子接口
     */
    private static class LogMethodInterceptorImpl implements MethodInterceptor {
        private final Object targetBean;

        public LogMethodInterceptorImpl(Object targetBean) {
            this.targetBean = targetBean;
        }

        @Override
        public Object intercept(Object proxy,
                                Method method,
                                Object[] args,
                                MethodProxy methodProxy) throws Throwable {
            System.out.println("LogMethodInterceptorImpl 日志1");

            // 调用目标方法
            Object retVal = method.invoke(targetBean, args);

            System.out.println("LogMethodInterceptorImpl 日志2");

            return retVal;
        }
    }
}

5、Bean的生命周期

(1)构造方法
(2)setter
(3)BeanNameAware接口的setBeanName方法
(4)ApplicationContextAware接口的setApplacationContext方法
(5)BeanPostProcessor接口的postProcessBeforInitialization方法
(6)InitializingBean接口的afterPropertiesSet方法
(7)配置文件中的init-method属性的方法
(8)BeanPostProcessor接口的postAfterInitialization方法
(9)业务方法
(10)DisposableBean接口的destroy方法
(11)配置文件中的destroy-method属性的方法

若配置文件中bean标签的scope属性是singleton,且容器销毁,才会出发第10和第11个方法

6、AOP是什么?

(1)AOP是Aspect Oriented Programming的简称。
(2)使用AOP技术可以很精确地为某些类的某些方法增加额外功能。虽然JDK的动态代理和CGLib也可以控制为某些类的某些方法增加功能,但判断很多,代码比较复杂。
(3)AOP依赖两个库:aspectjrt和aspectjweaver
(4)附加代码可通过两个接口编写:MethodBeforeAdvice接口和MethodInterceptor接口
(5)若有配置文件的话,需在配置文件中配置切入点和附加代码结合【在<aop:config>标签中配置切入点和切入点与附加代码的结合;在<aop:pointcut>标签中配置切入点;在<aop:advisor>标签中配置切入点和附加代码的结合】
(6)通过MethodBeforeAdvice接口只能在目标方法之前执行附加代码;MethodInterceptor接口则可以在目标方法之前或之后执行附加代码

在这里插入图片描述

在这里插入图片描述

   <dependency>
       <groupId>org.aspectj</groupId>
       <artifactId>aspectjrt</artifactId>
       <version>1.9.6</version>
   </dependency>
   <dependency>
       <groupId>org.aspectj</groupId>
       <artifactId>aspectjweaver</artifactId>
       <version>1.9.6</version>
   </dependency>

/**
 * 实现MethodBeforeAdvice接口, 在该接口的before方法中编写AOP的附加代码
 */
public class LogMethodBeforeAdvice implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] args, Object o) throws Throwable {
        System.out.println("LogMethodBeforeAdvice_before: " + Arrays.toString(args));
    }
}
/**
 * 通过实现org.aopalliance.intercept.MethodInterceptor接口添加附加代码
 */
public class LogMethodInterceptor implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        System.out.println("LogMethodInterceptor_附加代码1");
        Object retVal = methodInvocation.proceed();
        System.out.println("LogMethodInterceptor_附加代码2");
        return retVal;
    }
}
 <!-- 附加代码 -->
 <bean id="logMethodBeforeAdvice" class="com.guoqing.aop.LogMethodBeforeAdvice"/>
 <aop:config>
     <!-- 配置切入点 -->
     <!-- 切入任意方法 -->
     <aop:pointcut id="pointcut1" expression="execution(* *(..))"/>
     <!--切入方法名以【Impl】结尾的方法 -->
     <aop:pointcut id="pointcut2" expression="execution(* *Impl(..))"/>

     <!-- 在切入点pointcut1处添加附加代码logMethodBeforeAdvice -->
     <aop:advisor advice-ref="logMethodBeforeAdvice" pointcut-ref="pointcut1"/>
 </aop:config>

切入点表达式

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【面试题】2、Docker和Spring相关 的相关文章

随机推荐

  • was配置mysql数据源另一种方式

    1 添加JDBC驱动程序 打开was控制台 资源 JDBC提供程序 新建 2 配置JDBC参数 选择数据库类型为 用户自定义 数据库类型 com mysql jdbc jdbc2 optional MysqlXADataSource 名称
  • nRF52832 — 1.44寸 TFT屏

    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XX 作 者 文化人 XX 联系方式 XX 版权声明 原创文章 欢迎评论和转载 转载时能告诉我一声就最好了 XX 要说的
  • 关于:(.text+0x21): undefined reference to `shm_open'问题

    C programming in the UNIX environment的编程手册 一般都会为进程间用共享内存的方法通信提供两组方法 1 POSIX定义的 int shm open const char name int oflag mo
  • 开源数据集分类汇总(医学,卫星,分割,分类,人脸,农业,姿势等)

    本文汇总了医学图像 卫星图像 语义分割 自动驾驶 图像分类 人脸 农业 打架识别等多个方向的数据集资源 均附有下载链接 该文章仅用于学习记录 禁止商业使用 1 医学图像 疟疾细胞图像数据集 下载链接 http suo nz 2VQTUt 皮
  • Sqoop 使用详解

    Sqoop 概述 Sqoop 是Apache 旗下的一款开源工具 用于Hadoop与关系型数据库之间传送数据 其核心功能有两个 导入数据和导出数据 导入数据是指将MySQL Oracle等关系型数据库导入Hadoop的HDFS Hive H
  • C#(Unity3D)数值分析-牛顿(迭代)法

    最近需要用此方法解决一元五次方程求解问题 所以学习了下 在此记录一下 此方法的产生 是由于很多方程没有通解公式 所以求解只能通过数值方法 方法有很多 参见 数值分析 类似书有很多 牛顿法 这里引用书籍上所述 设方程 f x 0 其中有近似根
  • 多线程:线程安全与同步

    线程安全问题 线程安全问题产生的三个必要条件 多线程环境中 有共享数据 成员变量 而非局部变量 栈中是线程独立的 多个线程操作 增删改 了共享数据 单线程 以及 多线程在没有访问共享数据的情况下 是不会产生线程安全问题的 一旦多线程访问了共
  • 【Revit二次开发学习笔记】选取元素之先选择元素后执行命令

    第一步 写代码 using System using System Collections Generic using System Linq using System Text using System Threading Tasks u
  • TOWARDS A UNIFIED VIEW OF PARAMETER-EFFICIENT TRANSFER LEARNING

    本文也是属于LLM系列的文章 针对 TOWARDS A UNIFIED VIEW OF PARAMETER EFFICIENT TRANSFER LEARNING 的翻译 关于参数有效迁移学习的统一观点 摘要 1 引言 2 前言 2 1 T
  • xxx.app已损坏,打不开。 您应该将它移到废纸篓。

    Mac最新的系统打开网上下载的应用程序时 会提示 xxx app已损坏 打不开 您应该将它移到废纸篓 解决方式 1 系统偏好设置 gt 安全性与隐私 gt 修改为任何来源 2 serria里面没有 任何来源 这一项 需要打开终端执行sudo
  • 【数据结构】 二叉树面试题讲解->贰

    文章目录 引言 二叉树遍历 https www nowcoder com practice 4b91205483694f449f94c179883c1fef tpId 60 tqId 29483 rp 1 ru activity oj qr
  • 关于链表的三个常用算法

    找到环的第一个入口点 static public SinglyLinkedListNode
  • (s2-048)Struts2 反序列化漏洞

    Struts2 Struts2是一个基于MVC设计模式 java 的Web应用框架 它本质上相当于一个servlet 在MVC设计模式中 Struts2作为控制器 Controller 来建立模型与视图的数据交互 Struts2 是 Apa
  • 【故障处理】java程序cpu飙高如何排查

    使用传统jstack手法来排查 如何使用原生top命令 jstack命令来做定位具体代码的位置处理 简单步骤有下面几步 执行top命令 查看CPU占用情况 找到进程的pid 12002 使用 top Hp
  • Win10增加右键以管理员方式打开cmd,可自定义右键文本图标。

    先上设置后效果 设置步骤 1 打开注册表找到表项 按 win r 输入 regedit 打开注册表 找到注册表项 HKEY CLASSES ROOT Directory Background shell 2 在shell上新建项 右键 sh
  • word显示修改痕迹

    开发十年 就只剩下这套Java开发体系了 gt gt gt 1 打开待修改的word 2 设置修订 审阅 修订 修订 3 显示修改痕迹 添加修改内容
  • Fisco Bcos学习(环境搭建)

    服务器搭建联盟链过程 一 docker方式部署单群组4节点区块链 1 安装依赖 1 安装curl openssl yum install y curl openssl openssl devel 2 下载安装脚本 curl LO https
  • 完美解决 vcpkg 下载速度慢

    vcpkg 下载慢非常令人头痛 下面是一位 github 用户的抱怨 非常真实 The download and compilation time of vcpkg is relatively long So during this wai
  • 人才画像--持续更新

    人力资源管理包括人力资源规划 招聘与配置 培训与开发 绩效管理 薪酬管理及员工关系 六大模块 六大模块之间相辅相成 相互联系 对解决企业人才的 留 选 育 用 问题具有极为关键的作用 大数据时代的到来 为其注入了新能量 有人认为 大数据将成
  • 【面试题】2、Docker和Spring相关

    1 Docker是什么 1 Docker是一个快速交互 运行应用的技术 可以将程序及其依赖 运行环境一起打包为一个镜像 该镜像可以迁移到任意的Linux操作系统 2 运行时利用沙箱机制形成隔离容器 各个应用之间互不干扰 3 移动和移除程序都