丹丹丹学妹哭着对我说:学长,SpringBoot集成Redis集群

aaasdass【注】:装箱、拆箱的开销是Java泛型慢的重要原因。也成为今天Valhalla项目要重点解决的问题之一。

aa

aasdas②、运行期无法取到泛型类型信息。会让一些代码变得相当啰嗦。比如不支持对泛型进行实例判断、不支持使用泛型创建对象、不支持使用泛型创建数组,都是由于运行期Java虚拟机无法取得泛型类型而导致的。

aaasdass【注】:比如我们去写一个泛型版本的从List到数组的转换方法,由于不能从List中取得参数化类型T,所以不得不从一个额外参数中再传入一个数组的组件类型进去。

aasdsadasd

aasdsasdsadsadsadssadsaadasdsadadasdas不得不加入的类型参数


public static <T> T[] convert(List<T> list, Class<T> componentType) {

	T[] array = (T[])Array.newInstance(componentType, list.size());

	...

} 

aa

aasdas③、通过擦除法来实现泛型,还丧失了一些面向对象思想应有的优雅,带来了一些模棱两可的模糊状况。

aasdsadasd

aasdsasdsadsadsadssadsaadasdsadadasdas当泛型遇见重载1


public class GenericTypes {

	public static void method(List<String> list) {

		System.out.println("invoke method(List<String> list)");

	}

	public static void method(List<Integer> list) {

		System.out.println("invoke method(List<Integer> list)");

	}

} 

aasasaas分析:这段代码是不能被编译的,因为参数List< Integer>和List< String>编译之后都被擦除了,变成了同一种的裸类型List,类型擦除导致这两个方法的特征签名变得一模一样。初步看来,无法重载的原因已经找到了,但是真的就是如此吗?其实这个例子中泛型擦除成相同的裸类型只是无法重载的其中一部分原因。再看:

aasdsadasd

aasdsasdsadsadsadssadsaadasdsadadasdas当泛型遇见重载2


public class GenericTypes {

	public static String method(List<String> list) {

		System.out.println("invoke method(List<String> list)");

		return "";

	}

	public static int method(List<Integer> list) {

		System.out.println("invoke method(List<Integer> list)");

		return 1;

	}

	public static void main(String[] args) {

		method(new ArrayList<String>());

		method(new ArrayList<Integer>());

	}

}

执行结果:

	invoke method(List<String> list)

	invoke method(List<Integer> list) 

aasasaas分析:这里的重载当然不是根据返回值来确定的,之所以这次能编译和执行成功,是因为两个method()方法加入了不同的返回值后才能共存在一个Class文件之中。 由于List< String>和List< Integer>擦除后是同一个类型,我们只能添加两个并不需要实际使用到的返回值才能完成重载,这是一种毫无优雅和美感可言的解决方案,并且存在一定语意上的混乱。

aaasdass【注】:前面的文章已经提到:方法重载要求方法具备不同的特征签名,返回值并不包含在方法的特征签名中,所以返回值不参与重载选择,但是在Class文件格式之中,只要描述符不是完全一致的两个方法就可以共存。也就是说两个方法如果有相同的名称和特征签名,但返回值不同,那它们也是可以合法地共存于一个Class文件中的。

aaasdass总结:

aaaasdsasas①、由于Java泛型的引入,各种场景(虚拟机解析、反射等)下的方法调用都可能对原有的基础产生影响并带来新的需求,如在泛型类中如何获取传入的参数化类型等。所以《Java虚拟机规范》做出了相应的修改,引入了诸如SignatureLocalVariableTypeTable等新的属性用于解决伴随泛型而来的参数类型的识别问题

aaaasdsasasdas⒈Signature:存储一个方法在字节码层面的特征签名,这个属性中保存的参数类型并不是原生类型,而是包括了参数化类型的信息。

aaaasdsasas②、从Signature属性的出现我们还可以得出结论:擦除法所谓的擦除,仅仅是对方法的Code属性中的字节码进行擦除,实际上元数据中还是保留了泛型信息,这也是我们在编码时能通过反射手段取得参数化类型的根本依据。 (很重要,后面会进一步分析,因为现在也不能很明白的表达。)


自动装箱、拆箱与遍历循环

aa

aaas就纯技术的角度而论,自动装箱、自动拆箱与遍历循环 这些语法糖,无论是实现复杂度上还是其中蕴含的思想上都不能与泛型相提并论,两者涉及的难度和深度都有很大差距。

aa

aaas我们看一段代码,其中包含了泛型、自动装箱、自动拆箱、遍历循环与变长参数5种语法糖:

aasdsadasd

aasdsasdsadsadsadssadsaadasdsadadasdas编译前的代码


public static void main(String[] args) {

List<Integer> list = Arrays.asList(1, 2, 3, 4);

int sum = 0;

for (int i : list) {

sum += i;

}

System.out.println(sum);

} 

aasdsasdsadsadsadssadsaadasdsadadasdas编译后的代码


public static void main(String[] args) {

	List list = Arrays.asList( new Integer[] {   //泛型消除

		Integer.valueOf(1),

		Integer.valueOf(2),

		Integer.valueOf(3),

		Integer.valueOf(4) });

	int sum = 0;

	for (Iterator localIterator = list.iterator(); localIterator.hasNext(); ) {

		int i = ((Integer)localIterator.next()).intValue();

		sum += i;

	}

	System.out.println(sum);

} 

aasasaas分析:

aasasasdasdaas⒈泛型:编译后泛型消除,List< Integer>变成了List 。

aasasasdasdaas⒉自动装箱、拆箱:编译之后被转化成了对应的包装和还原方法,如本例中的Integer.valueOf()intValue()方法,

aasasasdasdaas⒊遍历循环:编译之后代码还原成了迭代器的实现,这也是为何遍历循环需要被遍历的类实现Iterable接口的原因。

aasasasdasdaas⒋变长参数:它在调用的时候变成了一个数组类型的参数,在变长参数出现之前,程序员的确也就是使用数组来完成类似功能的。

aa

aasdsasdsadsadsadssadsaadasdsadadasdas自动封装带来的陷阱:


public static void main(String[] args) {

	Integer a = 1;

	Integer b = 2;

	Integer c = 3;

	Integer d = 3;

	Integer e = 321;

	Integer f = 321;

	Long g = 3L;

	System.out.print(c == d );   true

	System.out.print(e == f );   false			//超出了范围[-128,127],所以封装的地址不一样了

	System.out.print(c == (a + b) );  true   //自动拆箱了,

	System.out.print(c.equals(a + b) );   true 

	System.out.print(g == (a + b) );   true 	//“==”运算遇到了"+",自动拆箱

	System.out.print(g.equals(a + b) );  false  //equals()方法不处理数据转型的关系

}

执行结果:

true false true true true false 

aasasaas分析:包装类的 “==”运算 在不遇到算术运算的情况下不会自动拆箱,以及它们equals()方法不处理数据转型的关系,在实际编码中尽量避免这样使用自动装箱与拆箱。


条件编译

aa

aaasC、C++中使用预处理器指示符(#ifdef)来完成条件编译。C、C++的预处理器最初的任务是解决编译时的代码依赖关系(如极为常用的#include预处理命令)。

aa

aaasJava语言实现条件编译,方法就是使用条件为常量的if语句,该代码中的if语句不同于其他Java代码,它在编译阶段就会被“运行”。

aasdsasdsadsadsadssadsaadasdsadadasdasJava语言的条件编译:


public static void main(String[] args) {

	if (true) {

		System.out.println("block 1");

	} else {

		System.out.println("block 2");

	}

} 

aasdsasdsadsadsadssadsasadadasdas该代码编译后Class文件的反编译结果:


public static void main(String[] args) {

	System.out.println("block 1");

} 

最后

权威指南-第一本Docker书

引领完成Docker的安装、部署、管理和扩展,让其经历从测试到生产的整个开发生命周期,深入了解Docker适用于什么场景。并且这本Docker的学习权威指南介绍了其组件的基础知识,然后用Docker构建容器和服务来完成各种任务:利用Docker为新项目建立测试环境,演示如何使用持续集成的工作流集成Docker,如何构建应用程序服务和平台,如何使用Docker的API,如何扩展Docker。

总共包含了:简介、安装Docker、Docker入门、使用Docker镜像和仓库、在测试中使用Docker、使用Docker构建服务、使用Fig编配Docke、使用Docker API、获得帮助和对Docker进行改进等9个章节的知识。

image

image

image

image

关于阿里内部都在强烈推荐使用的“K8S+Docker学习指南”—《深入浅出Kubernetes:理论+实战》、《权威指南-第一本Docker书》,看完之后两个字形容,爱了爱了!

CodeChina开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频】

-W63MTdK4-1630937025990)]

[外链图片转存中…(img-hpew3WZz-1630937025992)]

[外链图片转存中…(img-bO8iFREL-1630937025993)]

[外链图片转存中…(img-zM2ERgdN-1630937025995)]

关于阿里内部都在强烈推荐使用的“K8S+Docker学习指南”—《深入浅出Kubernetes:理论+实战》、《权威指南-第一本Docker书》,看完之后两个字形容,爱了爱了!

CodeChina开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频】

1. 概述 Redis是一个高性能的key-value数据库,它支持丰富的数据结构,如字符串、哈希、列表、集合、有序集合等。在实际应用中,为了提高Redis的可用性和扩展性,我们常常使用Redis集群。 本文将介绍如何在Spring Boot项目中集成Redis集群。 2. 环境准备 本文使用的环境如下: - JDK 1.8 - Spring Boot 2.3.8.RELEASE - Redis 5.0.10 - Redis集群 3. 集成Redis集群 3.1. 添加依赖 首先,在pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>3.5.2</version> </dependency> ``` 其中,spring-boot-starter-data-redis是Spring Boot对Redis的支持,jedis是RedisJava客户端。 3.2. 配置Redis集群 在application.properties文件中添加如下配置: ``` # Redis集群配置 spring.redis.cluster.nodes=192.168.0.101:7001,192.168.0.101:7002,192.168.0.101:7003,192.168.0.102:7004,192.168.0.102:7005,192.168.0.102:7006 spring.redis.cluster.max-redirects=3 ``` 其中,spring.redis.cluster.nodes指定了Redis集群中所有节点的地址和端口,多个节点之间用逗号分隔,spring.redis.cluster.max-redirects指定了Redis客户端在执行命令时最多可以重定向的次数,一般设置为3即可。 3.3. 编写代码 在代码中使用Redis时,可以通过注入RedisTemplate来操作RedisRedisTemplate是Spring对RedisTemplate的封装,使用起来非常方便。 ```java @Service public class RedisService { @Autowired private RedisTemplate<String, Object> redisTemplate; public void set(String key, Object value) { redisTemplate.opsForValue().set(key, value); } public Object get(String key) { return redisTemplate.opsForValue().get(key); } public void delete(String key) { redisTemplate.delete(key); } } ``` 上述代码中,我们定义了一个RedisService类,其中使用了@Autowired注解注入RedisTemplate,并提供了set、get、delete等操作Redis的方法。 4. 测试 在集成Redis集群的Spring Boot项目中,我们可以通过调用RedisService中的方法来操作Redis。下面是一个简单的测试用例: ```java @SpringBootTest class RedisClusterApplicationTests { @Autowired private RedisService redisService; @Test void testRedis() { String key = "name"; String value = "John"; // 设置值 redisService.set(key, value); // 获取值 Object result = redisService.get(key); System.out.println(result); // 删除值 redisService.delete(key); } } ``` 在测试用例中,我们首先使用redisService.set方法将一个键值对存入Redis中,然后使用redisService.get方法获取值,并打印出来,最后使用redisService.delete方法删除该键值对。 5. 总结 本文介绍了在Spring Boot项目中集成Redis集群的方法,主要包括添加依赖、配置Redis集群和编写代码等步骤。通过本文的学习,相信大家已经掌握了Spring Boot集成Redis集群的基本方法,可以在实际项目中应用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值