记录些Spring+题集(14)

方法区中的符号引用和直接引用

方法区是Java虚拟机的一部分,主要用于存储类级别的信息,如类的结构、常量池、静态变量以及编译后的代码等。在方法区中,符号引用与直接引用是关联类中方法和字段调用的两个重要概念。

符号引用:

  • 定义:符号引用包含一系列符号,用于描述类文件结构中的元素,它们是间接、抽象的引用形式,通常是一些文本字符串。

  • 内容:符号引用通常包含如下信息:

    • 类和接口的全限定名

    • 字段的名称和描述符

    • 方法的名称和描述符

    • 方法句柄和方法类型

  • 作用:符号引用在类文件中作为常量信息存在,它们在编译时创建,运行时需要通过解析转换成直接引用才能被JVM使用。

直接引用:

  • 定义:直接引用是具体化的引用,它直接指向目标数据或者方法代码的内存地址或偏移量。

  • 内容:直接引用的实际内容取决于它所指向的对象的种类,可能是以下几种:

    • 对于类静态属性,可能是一个静态存储区域的地址。

    • 对于实例字段,可能是相对于对象头部的偏移量。

    • 对于方法,可能是指向方法代码的指针或偏移量。

  • 作用:直接引用使得JVM可以高效地执行方法调用和字段访问操作,因为它们提供了一条直接通向目标数据或方法代码的路径。

举例说明:

比方说我们有一个Java类ExampleClass,它有一个实例字段counter和一个方法increment():

package com.example;
public class ExampleClass {    public int counter = 0;
    public void increment() {        counter++;    }}

当这个类被编译后,在.class文件中,对于counter字段和increment方法的引用会以符号引用的形式存在。它们可能会呈现如下:

  • 符号引用到counter字段可能是:“com/example/ExampleClass.counter:I”

  • 符号引用到increment方法可能是:“com/example/ExampleClass.increment:()V”

当这个.class文件被加载到JVM中,并且类ExampleClass被第一次使用时(例如,创建ExampleClass的实例或者调用它的方法),JVM会把这些符号引用解析成直接引用。具体来说:

  • 对于字段counter,直接引用将包括该字段在ExampleClass对象中存储的具体内存位置的偏移量。

  • 对于increment方法,直接引用将是指向JVM中方法区内该方法代码开始位置的指针。

这个过程确保了运行时的效率,因为解析工作只需完成一次,之后JVM就可以直接利用这些引用,无需再进行查找和匹配,从而加速程序执行。

什么是 SpringCloud?

Spring Cloud 是一系列框架的集合,旨在为分布式系统的开发提供解决方案。它基于 Spring Boot,利用 Spring Boot 的快速开发特性,帮助开发者快速构建分布式微服务架构系统。Spring Cloud 通过集成和封装各种成熟的开源解决方案,提供了配置管理、服务发现、负载均衡、断路器、分布式追踪、消息驱动微服务、网关路由等功能。

了解了 SpringCloud 提供了什么能力:

1)配置管理:集中管理配置,支持动态刷新。

2)服务发现和注册:实现服务的自动注册和发现。

3)负载均衡:提供客户端负载均衡解决方案。

4)断路器:实现故障隔离和容错机制。

5)分布式追踪:跟踪微服务调用链路,便于监控和调试。

6)消息驱动的微服务:通过消息中间件实现服务间的异步通信。

7)网关路由:提供API网关,进行路由和过滤。

Spring Cloud 组件代码片段

Spring Cloud Config

Spring Cloud Config(配置管理) 提供了一种集中管理分布式系统配置的方法。配置服务器(Config Server)可以从 Git、SVN 等版本控制系统中读取配置文件,并将其提供给各个微服务。通过这种方式,可以实现配置的集中管理和动态刷新。

// 示例:Config Server的配置
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApplication.class, args);
    }
}
Eureka

Eureka 是一个服务注册与发现组件,允许微服务在启动时自动注册到 Eureka Server,并在需要调用其他服务时通过 Eureka Client 进行查找和调用。

示例:Eureka Server 的配置
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}
Ribbon

Ribbon 是一个客户端负载均衡器,它能够对多实例的微服务进行负载均衡,提升服务调用的可靠性和性能。Ribbon 可以与 Eureka 集成,实现动态的服务实例选择。

示例:使用 Ribbon 进行负载均衡
@RestController
public class RibbonController {

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/consume")
    public String consume() {
        return restTemplate.getForObject("http://SERVICE-NAME/endpoint", String.class);
    }
}
Feign

Feign 是一个声明式的 HTTP 客户端,它简化了 HTTP API 的调用。通过注解方式定义 HTTP 请求,可以像调用本地方法一样调用远程服务。

// 示例:Feign 客户端的定义
@FeignClient(name = "service-name")
public interface ServiceClient {
    @GetMapping("/endpoint")
    String callEndpoint();
}
Spring Cloud Gateway

Spring Cloud Gateway 是一个现代化的 API 网关,它提供了动态路由、限流、断路、重试等功能,能够处理所有外部请求的路由和过滤。相比于 Zuul,Spring Cloud Gateway 具有更高的性能和更丰富的功能。

// 示例:Gateway 的配置
@SpringBootApplication
public class GatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
}

@Configuration
public class GatewayConfig {
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("path_route", r -> r.path("/get")
                        .uri("http://http.org"))
                .build();
    }
}

实际事物加深记忆的例子

想象下,经营着一家大型连锁超市,各个分店相当于微服务,每个分店需要定期向总部(配置服务器)获取商品价格(配置)和库存信息(配置)。每个分店的员工(服务实例)在接待顾客(请求)时,需要查找商品(服务发现),确保顾客可以在多个分店中进行购物(负载均衡)。当顾客咨询商品信息时,可以通过电话直接联系其他分店的员工(Feign),而总服务台(API 网关)则负责处理所有顾客的咨询电话,确保顾客的请求能够快速准确地转接到相应的分店。

通过这个例子,我们可以更好地理解 Spring Cloud 各个核心组件的作用及其在实际应用中的意义。Spring Cloud 为我们提供了构建和管理分布式系统的强大工具,使得开发和运维微服务架构变得更加简便和高效。

其他补充

Spring Cloud的核心组件及其功能补充:

1)Spring Cloud Netflix Zuul:

  • 功能:API网关服务。

  • 用途:提供动态路由、监控、弹性、安全等功能,处理所有外部请求的路由。

2)Spring Cloud Netflix Hystrix:

  • 功能:实现熔断器模式。

  • 用途:提供容错和延迟容忍能力,防止单个服务的失败导致整个系统崩溃。

3)Spring Cloud Sleuth:

  • 功能:分布式追踪工具。

  • 用途:为Spring Cloud应用添加分布式追踪功能,与Zipkin或Jaeger集成,用于跟踪请求在微服务中的调用链路。

4)Spring Cloud Bus:

  • 功能:事件总线,用于传播集群中的状态变化。

  • 用途:通过消息代理(如RabbitMQ、Kafka)在多个服务实例之间传播配置更新或其他事件。

5)Spring Cloud Stream:

  • 功能:消息驱动微服务框架。

  • 用途:简化与消息中间件的整合,提供统一的编程模型,支持Kafka、RabbitMQ等。

localhost和127.0.0.1啥区别?

在日常开发和网页浏览中,我们经常会遇到localhost127.0.0.1。它们看似相似,实则有着本质的区别。

本地主机(localhost)

localhost是一个特殊的域名,它代表的是本机地址。它的存在主要是为了方便开发者和用户记忆,因为相比于IP地址,域名更容易被记住和识别。

localhost的有效范围仅限于本机。这意味着在同一局域网内的其他计算机上访问localhost,它们将无法找到目标主机,因为localhost并不指向一个网络中的真实地址,而是指向本机。这在开发环境中非常有用,因为它允许开发者在不暴露内部开发服务器的情况下进行本地测试。

本地回环地址(127.0.0.1)

localhost相对的是127.0.0.1,这是一个特殊的IP地址,被称为本地回环地址。它同样用于指向本机,但是它是一个IP地址,这意味着它遵循IP地址的规则和结构。

127.0.0.1是TCP/IP协议中定义的官方IPv4地址,用于在本地计算机上测试网络服务。由于它是一个IP地址,它可以直接与网络栈交互,而不需要DNS解析。这使得使用127.0.0.1进行网络通信更为直接和快速。

域名解析

localhost127.0.0.1之间的联系在于它们都指向同一个地方—本机。但是,它们的解析方式不同。localhost是通过DNS解析实现的,而127.0.0.1则不需要DNS解析。

在每台计算机上,都有一个名为hosts的文件,它包含了一些本地DNS解析规则。在大多数操作系统中,hosts文件会有一个预定义的条目,将localhost映射到127.0.0.1。这意味着当你在浏览器中输入http://localhost时,操作系统会查找hosts文件,将localhost解析为127.0.0.1,然后浏览器会向这个IP地址发送请求。

应用场景

在实际应用中,localhost127.0.0.1有着不同的用途。

  • • 开发和测试:开发者在进行本地开发和测试时,通常会使用localhost作为开发服务器的地址。这样做的好处是,即使在不同的开发环境中,只要使用localhost,就可以确保指向的是本机的开发服务器。

  • • 网络服务:在需要确保网络请求不会离开本机的情况下,使用127.0.0.1是一个更安全的选择。例如,在进行网络安全测试或者需要隔离网络请求时,127.0.0.1可以确保所有的网络交互都局限在本机。

域名的等级划分

域名系统是分层的,从顶级域名(TLD)到二级域名(SLD),再到三级域名(3LD)。

顶级域名(TLD):顶级域名是域名系统中最高级别的域名。它位于域名的最右边,通常由几个字母组成。顶级域名分为两种类型:通用顶级域名和国家顶级域名。常见的通用顶级域名包括表示工商企业的.com、表示网络提供商的.net、表示非盈利组织的.org等,而国家顶级域名则代表特定的国家或地区,如.cn代表中国、.uk代表英国等。

二级域名(SLD):二级域名是在顶级域名之下的一级域名。它是由注册人自行选择和注册的,可以是个性化的、易于记忆的名称。例如,juejin.cn 就是二级域名。我们平常能够申请到的也是这种。目前来说申请 xxx.com、xxx.net、xxx.cn等等域名,其实大家不太关心其顶级域名com\net\cn代表的含义,看着简短好记是主要诉求。

三级域名(3LD):三级域名是在二级域名之下的一级域名。它通常用于指向特定的服务器或子网。例如,在blog.example.com中,blog就是三级域名。www是最常见的三级域名,用于代表网站的主页或主站点,不过这只是某种流行习惯,目前很多网站都推荐直接使用二级域名访问了。

localhost在这个分层结构中是一个特例。虽然它看起来像一个顶级域名,但它实际上是一个保留的顶级域,专门用于访问当前计算机。

对称加密和非对称加密在HTTPS中的应用

对称加密(Symmetric Encryption)

对称加密使用相同的密钥进行数据的加密和解密。发送方将明文数据通过对称加密算法和密钥进行加密,接收方收到密文后,使用同样的密钥和对称加密算法进行解密以恢复明文。

优点:

  • 加密和解密速度快

  • 适用于大量数据的加密

缺点:

  • 密钥分发问题,双方都需要有同样的密钥,安全密钥交换成为挑战

  • 密钥管理成本高,每个通信对需要一个独立的密钥

常见算法:AES, DES, 3DES, RC4等。

非对称加密(Asymmetric Encryption)

非对称加密使用一对密钥:公钥(public key)和私钥(private key)。公钥可以公开,而私钥必须保密。如果用公钥加密数据,只有对应的私钥才能解密;如果用私钥加密数据,只有对应的公钥才能解密。

优点:

  • 解决了密钥分发的问题,密钥对中的公钥可以自由分发

  • 提供了数字签名功能,确保了消息的完整性和身份验证

缺点:

  • 加密和解密速度慢于对称加密,不适合大量数据加密

  • 计算复杂度高

常见算法:RSA, ECC, ElGamal等。

HTTPS中的应用:

HTTPS(超文本传输安全协议)是一种用于在互联网上安全传输数据的协议。它在标准的HTTP(超文本传输协议)上增加了SSL/TLS(安全套接层/传输层安全)协议。SSL/TLS结合了对称加密和非对称加密,兼顾了两者的优势。

  1. 建立连接时的非对称加密:

    • 浏览器向服务器请求建立SSL连接。

    • 服务器发送其SSL证书,包括服务器的公钥。

    • 浏览器验证证书的有效性,然后生成一个随机数作为对称密钥的会话密钥。

    • 浏览器用服务器的公钥加密这个会话密钥,并发送给服务器。

    • 服务器用自己的私钥解密这个会话密钥。

  2. 数据传输时的对称加密:

    • 一旦双方都有了会话密钥,它们就使用对称加密算法加密通信过程中的所有数据。

    • 这样,即使有人截获了加密后的数据,也无法解密,因为他们没有会话密钥。

  3. 身份验证和完整性检查:

    • 服务器和客户端还可能使用非对称加密提供数字签名,以确保数据的完整性和来源验证。

总结:HTTPS协议通过结合对称和非对称加密的优点,提供了既安全又高效的网络数据传输方法。在建立连接阶段使用非对称加密来交换密钥,保证了密钥的隐私和安全;而在数据传输阶段使用对称加密来保障数据传输的效率。此外,通过数字签名保障了数据的完整性和来源的可验证性。这种混合加密策略兼顾了性能和安全性

自定义工厂类给线程池命名

项目模块较多,在运行时调用了不同模块的线程池,为了在发生异常后快速定位问题,一般会在构建线程池时给它一个名字。

方法一: 通过Spring 框架提供的CustomizableThreadFactory命名

ThreadFactory springThreadFactory = new CustomizableThreadFactory("Spring线程池:");
ExecutorService exec = new ThreadPoolExecutor(1, 1,
         0L, TimeUnit.MILLISECONDS,
         new LinkedBlockingQueue<Runnable>(10),springThreadFactory);
 exec.submit(() -> {
     log.info(exec.toString());
 });

方法二: 通过Google guava工具类提供的ThreadFactoryBuilder命名

//链式调用
ThreadFactory guavaThreadFactory = new ThreadFactoryBuilder().setNameFormat("guava线程池:").build();
ExecutorService exec = new ThreadPoolExecutor(1, 1,
          0L, TimeUnit.MILLISECONDS,
          new LinkedBlockingQueue<Runnable>(10),guavaThreadFactory );
  exec.submit(() -> {
      log.info(exec.toString());
  });

其实还有一个是Apache commons-lang3 提供的 BasicThreadFactory工厂类,也可以给线程池命名,他们的本质都是通过Thread 的setName()方法实现的。

方法三: 自定义工厂类实现线程池命名

先定义一个工厂类,通过实现ThreadFactory的newThread方法,完成命名。

public class MyThreadFactory implements ThreadFactory {

    private final AtomicInteger threadNum = new AtomicInteger();
    private final String name;

    /**
     * 创建一个带名字的线程池生产工厂
     */
    public MyThreadFactory(String name) {
        this.name = name;
    }

    @Override
    public Thread newThread(Runnable r) {
        Thread t = new Thread(r);
        t.setName(name + "-" + threadNum.incrementAndGet());
        return t;
    }
}

调用一下看看结果:

@Slf4j
public class Test {
    public static void main(String[] args) {
        MyThreadFactory myThreadFactory = new MyThreadFactory("javaBuild-pool");
        ExecutorService exec = new ThreadPoolExecutor(1, 1,
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>(10),myThreadFactory);
        exec.submit(() -> {
            log.info(exec.toString());
        });
    }
}

进程和线程的区别?

进程和线程是操作系统中用于并发编程的两种基本单位,它们在资源管理、执行流程等方面有着本质的区别。

进程(Process):

  • 定义:进程是操作系统进行资源分配和调度的独立单位,是应用程序运行的载体。一个进程通常包含代码、数据和分配给它的系统资源。

  • 资源隔离:每个进程拥有独立的地址空间,一个进程崩溃不会直接影响到其他进程。

  • 通信成本:进程间通信(IPC)需要特殊的操作系统支持,如管道、消息队列、共享内存等,相比线程间通信较为复杂且效率较低。

  • 切换开销:进程切换涉及当前执行状态的保存以及新进程状态的装载,上下文切换开销比线程大。

优点:

  • 稳定性高:进程之间相互独立,崩溃的进程不会影响到其他进程。

  • 安全性好:独立的地址空间加强了数据安全。

缺点:

  • 开销大:创建进程比创建线程资源消耗大,上下文切换时间长。

  • 通信复杂:进程间通信机制相对麻烦,效率不如线程间通信。

线程(Thread):

  • 定义:线程是进程内的一个独立执行流,是被系统独立调度和分派的基本单位。一个进程可以包含多个线程,它们共享进程的地址空间和资源。

  • 资源共享:同一进程内的线程共享内存和文件等资源,这使得线程间的通信非常方便。

  • 通信成本:线程间的通信可以通过直接读写进程内的数据进行,开销小。

  • 切换开销:线程切换只需少量寄存器和栈的变更,因此速度快。

优点:

  • 创建快速:创建线程比进程快,资源消耗小。

  • 切换快速:线程间切换的开销小于进程切换。

  • 通信高效:线程间可以直接通信,共享内存,无需IPC。

缺点:

  • 稳定性低:一个线程崩溃可能会影响整个进程。

  • 安全性差:线程间共享资源,数据处理不当容易导致冲突。

综合来说,进程相比线程更为稳定安全,但代价是更高的资源消耗和通信成本;而线程则灵活高效,但协作中的风险也更大。选择使用进程或线程通常取决于具体情况:如果需要执行多个相对独立且需要隔离的任务,适合使用多进程;如果任务之间需要频繁交换信息,又或者是在同一应用内的多个执行任务,使用多线程则更加合适。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值