首页
统计
关于
Search
1
Sealos3.0离线部署K8s集群
1,088 阅读
2
类的加载
744 阅读
3
Spring Cloud OAuth2.0
727 阅读
4
SpringBoot自动装配原理
693 阅读
5
集合不安全问题
589 阅读
笔记
Java
多线程
注解和反射
JVM
JUC
设计模式
Mybatis
Spring
SpringMVC
SpringBoot
MyBatis-Plus
Elastic Search
微服务
Dubbo
Zookeeper
SpringCloud
Nacos
Sentinel
数据库
MySQL
Oracle
PostgreSQL
Redis
MongoDB
工作流
Activiti7
Camunda
消息队列
RabbitMQ
前端
HTML5
CSS
CSS3
JavaScript
jQuery
Vue2
Vue3
Linux
容器
Docker
Kubernetes
Python
FastApi
登录
Search
标签搜索
Java
CSS
mysql
RabbitMQ
JavaScript
Redis
JVM
Mybatis-Plus
Camunda
多线程
CSS3
Python
Spring Cloud
注解和反射
Activiti
工作流
SpringBoot
Mybatis
Spring
html5
蘇阿細
累计撰写
391
篇文章
累计收到
4
条评论
首页
栏目
笔记
Java
多线程
注解和反射
JVM
JUC
设计模式
Mybatis
Spring
SpringMVC
SpringBoot
MyBatis-Plus
Elastic Search
微服务
Dubbo
Zookeeper
SpringCloud
Nacos
Sentinel
数据库
MySQL
Oracle
PostgreSQL
Redis
MongoDB
工作流
Activiti7
Camunda
消息队列
RabbitMQ
前端
HTML5
CSS
CSS3
JavaScript
jQuery
Vue2
Vue3
Linux
容器
Docker
Kubernetes
Python
FastApi
页面
统计
关于
搜索到
157
篇与
的结果
2021-02-05
Stream流的使用笔记
Stream流一、遍历/匹配 foreach/find/matchpackage com.sw.demo.stream; import java.util.Arrays; import java.util.List; import java.util.Optional; /** * 1.遍历/匹配(foreach/find/match) */ public class foreach01 { public static void main(String[] args) { List<Integer> list = Arrays.asList(1, 77, 5, 4, 33, 677, 86, 43); //遍历输出符合条件的元素 list.stream().filter(x -> x > 6).forEach(System.out::println); //匹配第一个 Optional<Integer> findFirst = list.stream().filter(x -> x > 6).findFirst(); //匹配任意一个元素(适用于并行流) Optional<Integer> findAny = list.stream().filter(x -> x > 6).findAny(); //是否包含符合指定条件的元素 boolean flag = list.stream().anyMatch(x -> x > 6); System.out.println("匹配第一个元素" + findFirst.get()); System.out.println("匹配任意一个元素" + findAny.get()); System.out.println("是否存在大于6的值" + flag); } } 二、筛选 filter按照一定的规则校验流中的元素,将符合条件的元素提取到新的流中package com.sw.demo.stream; import com.sw.demo.pojo.Person; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; /** * 2.筛选员工中工资高于8000的人,并形成新的集合 */ public class filter02 { public static void main(String[] args) { List<Person> personList = new ArrayList<Person>(); personList.add(new Person("Tom", 8900, 18, "male", "昆明")); personList.add(new Person("Jack", 7000, 19, "male", "楚雄")); personList.add(new Person("Lily", 7800, 20, "female", "楚雄")); personList.add(new Person("Anni", 8200, 21, "female", "大理")); personList.add(new Person("Owen", 9500, 22, "male", "昆明")); personList.add(new Person("Alisa", 7900, 22, "female", "保山")); List<String> result = personList.stream().filter(x -> x.getSalary()>8000).map(Person::getName).collect(Collectors.toList()); System.out.println("工资大于8000的员工:"+result); } } 三、聚合 max/min/count与MySQL中聚合函数的使用类似package com.sw.demo.stream; import java.util.Arrays; import java.util.Comparator; import java.util.List; import java.util.Optional; /** * 3.聚合(max/min/count) */ public class polymerization03 { public static void main(String[] args) { //例1:获取String集合中最长的元素 List<String> list = Arrays.asList("abc", "dcdf", "nihao", "xiexieni", "hello"); Optional<String> max = list.stream().max(Comparator.comparing(String::length)); //System.out.println("最长的元素为:" + max); //例2:获取最大值,并按自定义格式排序 List<Integer> list2 = Arrays.asList(1, 55, 22, 8, 90, 777, 45); //自然排序 Optional<Integer> max01 = list2.stream().max(Integer::compareTo); //自定义排序 Optional<Integer> max02 = list2.stream().max(new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o1.compareTo(o2); } }); //System.out.println("自然排序" + max01); //System.out.println("自定义排序" + max02); //例3:获取员工工资最高的人(同理获取String集合中最长的元素) //例4:计算集合中有几个大于6的数 List<Integer> list4 = Arrays.asList(5, 6, 8, 1, 2, 55, 22); long count = list4.stream().filter(x -> x > 6).count(); System.out.println(count); } } 四、映射 map/flatMapmap:接收一个函数作为参数该函数会被应用到每个元素上并将其映射成一个新的元素flatMap:接收一个函数作为参数,并将流中的每个值都换成另一个流,然后把所有流连接成一个新的流package com.sw.demo.stream; import com.sw.demo.pojo.Person; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; /** * 4.映射(map/flatMap) * 映射可以将一个流的元素按照一定的规则映射到另一个流中 * map:接受一个函数作为参数,该函数会被应用到每个函数上,并将其映射成一个新的函数 * flatMap:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流 */ public class mapping04 { public static void main(String[] args) { //例1:将数组元素转换为大写/每个元素+3 String[] str = {"abc", "bde", "cfg"}; List<String> list01 = Arrays.stream(str).map(String::toUpperCase).collect(Collectors.toList()); List<Integer> list02 = Arrays.asList(1, 2, 3, 6, 7); List<Integer> plus = list02.stream().map(x -> x + 3).collect(Collectors.toList()); //System.out.println("字符转换为大写:" + list01); //System.out.println("每个值+3:" + plus); //例2:每个员工的薪资上涨1000 List<Person> personList = new ArrayList<Person>(); personList.add(new Person("Tom", 8900, 18, "male", "昆明")); personList.add(new Person("Jack", 7000, 19, "male", "楚雄")); personList.add(new Person("Lily", 7800, 20, "female", "楚雄")); personList.add(new Person("Anni", 8200, 21, "female", "大理")); personList.add(new Person("Owen", 9500, 22, "male", "昆明")); personList.add(new Person("Alisa", 7900, 22, "female", "保山")); //不改变原来员工集合的方式 List<Person> newPersonList = personList.stream().map(person -> { Person newPerson = new Person(person.getName(), 0, 0, null, null); newPerson.setSalary(person.getSalary() + 1000); return newPerson; }).collect(Collectors.toList()); //System.out.println("改动前:" + personList.get(0).getName() + "----->" + personList.get(0).getSalary()); //System.out.println("改动后:" + newPersonList.get(0).getName() + "----->" + newPersonList.get(0).getSalary()); //改变了原来员工集合的方式 List<Person> newPersonList1 = personList.stream().map(person -> { person.setSalary(person.getSalary() + 1000); return person; }).collect(Collectors.toList()); //System.out.println("二次改动前:" + personList.get(0).getName() + "----->" + personList.get(0).getSalary()); //System.out.println("二次改动后:" + newPersonList1.get(0).getName() + "----->" + newPersonList1.get(0).getSalary()); /* 二次改动前:Tom----->9900(直接在personList的基础上操作,没有new对象) 二次改动后:Tom----->9900 */ //例3:将两个字符串合并为1个新的字符串 List<String> list03 = Arrays.asList("a,s,a,s", "a,s,1,2,d"); List<String> newList03 = list03.stream().flatMap(s -> { //将每个元素转换为一个stream String[] split = s.split(","); Stream<String> s01 = Arrays.stream(split); return s01; }).collect(Collectors.toList()); System.out.println("处理集合前:" + list03); System.out.println("处理集合后:" + newList03); /* 处理集合前:[a,s,a,s, a,s,1,2,d] 处理集合后:[a, s, a, s, a, s, 1, 2, d] */ } } 五、归约 reduce把一个流缩减成一个值,实现对集合的求和、乘积、最值等操作package com.sw.demo.stream; import com.sw.demo.pojo.Person; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Optional; /** * 5.规约 * 规约也称缩减,即把一个流缩减为一个值,实现对集合求和、乘积、最值 */ public class reduce05 { public static void main(String[] args) { //例1: List<Integer> list = Arrays.asList(5, 8, 88, 9, 555); //求和方式一: Optional<Integer> sum1 = list.stream().reduce((x, y) -> x + y); //求和方式二: Optional<Integer> sum2 = list.stream().reduce(Integer::sum); //求和方式三: Integer sum3 = list.stream().reduce(0, Integer::sum); //乘积 Optional<Integer> product = list.stream().reduce((x, y) -> x * y); //求最大值方式一 Optional<Integer> max1 = list.stream().reduce((x, y) -> x > y ? x : y); //求最大值方式er Integer max2 = list.stream().reduce(1, Integer::max); //System.out.println("求和:" + sum1.get() + "," + sum2.get() + "," + sum3); //System.out.println("乘积:" + product.get()); //System.out.println("最值:" + max1 + "," + max2); //例2:求所有员工的工资之和,最高工资 List<Person> personList = new ArrayList<Person>(); personList.add(new Person("Tom", 8900, 18, "male", "昆明")); personList.add(new Person("Jack", 7000, 19, "male", "楚雄")); personList.add(new Person("Lily", 7800, 20, "female", "楚雄")); personList.add(new Person("Anni", 8200, 21, "female", "大理")); personList.add(new Person("Owen", 9500, 22, "male", "昆明")); personList.add(new Person("Alisa", 7900, 22, "female", "保山")); //求和1: Optional<Integer> s1 = personList.stream().map(Person::getSalary).reduce(Integer::sum); //方式2: Integer s2 = personList.stream().reduce(0, (s, p) -> s += p.getSalary(), (sa1, sa2) -> sa1 + sa2); //方式3: Integer s3 = personList.stream().reduce(0, (s, p) -> s += p.getSalary(), Integer::sum); //求工资最高的人方式一 Integer smax1 = personList.stream().reduce(0, (m, p) -> m > p.getSalary() ? m : p.getSalary(), Integer::max); //求工资最高的人方式二 Integer smax2 = personList.stream().reduce(0, (m, p) -> m > p.getSalary() ? m : p.getSalary(), (x, y) -> x > y ? x : y); System.out.println("工资之和:"+s1+","+s2+","+s3); System.out.println("工资最值:"+smax1+","+smax2); } } 六、收集 collect1.归集 toList/toSet/toMap因为流不存储数据,在流中的数据处理完之后,要将流中的数据重新归到新的集合里package com.sw.demo.stream; import com.sw.demo.pojo.Person; import java.util.*; import java.util.stream.Collectors; /** * 6.收集(collect) * 将流收集为一个值或一个新的集合 * collect主要依赖java.util.stream.Collectors类内置的静态方法 */ public class collect01 { public static void main(String[] args) { /* 6.1 归集:因为流不存储数据,在流中的数据处理完之后,需要将流中的数据重新归集到新的集合里 toList(),toSet(),toMap() */ //toList/toSet List<Integer> list = Arrays.asList(1, 6, 3, 4, 6, 7, 9, 6, 20); List<Integer> newList = list.stream().filter(x -> x % 2 == 0).collect(Collectors.toList()); //去重 Set<Integer> newSet = list.stream().filter(x -> x % 2 == 0).collect(Collectors.toSet()); List<Person> personList = new ArrayList<Person>(); personList.add(new Person("Tom", 8900, 18, "male", "昆明")); personList.add(new Person("Jack", 7000, 19, "male", "楚雄")); personList.add(new Person("Lily", 7800, 20, "female", "楚雄")); personList.add(new Person("Anni", 8200, 21, "female", "大理")); personList.add(new Person("Owen", 9500, 22, "male", "昆明")); personList.add(new Person("Alisa", 7900, 22, "female", "保山")); Map<?, Person> map = personList.stream().filter(p -> p.getSalary() > 8000).collect(Collectors.toMap(Person::getName, p -> p)); System.out.println("toList:" + newList); //toList:[6, 4, 6, 6, 20] System.out.println("toSet" + newSet); //toSet[4, 20, 6] System.out.println("toMap:" + map); //key:name - value:Person } } 2.统计 count/averagingCollectors提供了一系列用于数据统计的静态方法计数 count平均值 averagingInt,averagingLong,averagingDouble最值 maxBy,minBy求和 summingInt,summingLong,summingDouble统计以上所有 summarizingInt,summarizingLong,summarizingDoublepackage com.sw.demo.stream; import com.sw.demo.pojo.Person; import java.util.*; import java.util.stream.Collectors; /** * 6.2 统计(count/averaging) * 计数 count * 平均值 averagingInt averagingLong averagingDouble * 最值 maxBy minBy * 求和 summingInt summingLong summingDouble * 统计以上所有 summarizingInt summarizingLong summarizingDouble */ public class collect02 { public static void main(String[] args) { List<Person> personList = new ArrayList<Person>(); personList.add(new Person("Tom", 8900, 18, "male", "昆明")); personList.add(new Person("Jack", 7000, 19, "male", "楚雄")); personList.add(new Person("Lily", 7800, 20, "female", "楚雄")); personList.add(new Person("Anni", 8200, 21, "female", "大理")); personList.add(new Person("Owen", 9500, 22, "male", "昆明")); personList.add(new Person("Alisa", 7900, 22, "female", "保山")); //求总数 Long count = personList.stream().collect(Collectors.counting()); //平均工资 Double salary = personList.stream().collect(Collectors.averagingDouble(Person::getSalary)); //最高工资 Optional<Integer> max = personList.stream().map(Person::getSalary).collect(Collectors.maxBy(Integer::compareTo)); //工资之和 Integer sum = personList.stream().collect(Collectors.summingInt(Person::getSalary)); //统计所有信息 DoubleSummaryStatistics collect = personList.stream().collect(Collectors.summarizingDouble(Person::getSalary)); System.out.println("员工总数:" + count); System.out.println("平均工资:" + salary); System.out.println("最高工资:" + max); System.out.println("工资之和:" + sum); System.out.println("所有信息:" + collect); } } 3.分组 partitioningBy/groupingBy分区:将stream按条件分为两个map,例:按性别将员工分组分组:将集合分为多个map,例:按地区分组package com.sw.demo.stream; import com.sw.demo.pojo.Person; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collector; import java.util.stream.Collectors; /** * 6.3 分组(partitioningBy/groupingBy) * 分区:将stream按条件分为两个Map * 分组:将集合分为多个Map,如按部门,地区分组 */ public class collect03 { public static void main(String[] args) { List<Person> personList = new ArrayList<Person>(); personList.add(new Person("Tom", 8900, 18, "male", "昆明")); personList.add(new Person("Jack", 7000, 19, "male", "楚雄")); personList.add(new Person("Lily", 7800, 20, "female", "楚雄")); personList.add(new Person("Anni", 8200, 21, "female", "大理")); personList.add(new Person("Owen", 9500, 22, "male", "昆明")); personList.add(new Person("Alisa", 7900, 22, "female", "保山")); //按员工薪资高于8000分组 key:boolean - value:List Map<Boolean, List<Person>> part = personList.stream().collect(Collectors.groupingBy(x -> x.getSalary() > 8000)); //按性别分组 key:String - value:List Map<String, List<Person>> sex = personList.stream().collect(Collectors.groupingBy(Person::getSex)); //先按性别分组,再按地区分组 key:String - value:Map Map<String, Map<String, List<Person>>> area = personList.stream().collect(Collectors.groupingBy(Person::getSex, Collectors.groupingBy(Person::getArea))); System.out.println("薪资高于8000的员工:"+part); System.out.println("按性别分组:"+sex); System.out.println("按地区分组:"+area); } } 4.接合 joining将stream中的元素用特定的连接符连接成一个字符串(如果没有连接符,则直接连接)package com.sw.demo.stream; import java.util.Arrays; import java.util.List; import java.util.stream.Collector; import java.util.stream.Collectors; /** * 6.4 接合(joining) * joining可以将stream中的元素用特定的连接符连接成一个字符串(如果没有连接符,则直接连接) */ public class collect04 { public static void main(String[] args) { List<String> list = Arrays.asList("a", "1", "b", "2", "c", "3", "d", "4"); String joining = list.stream().collect(Collectors.joining("-->")); System.out.println(joining); } } 5.归约 reducingCollectors类提供的reducing方法,相比于stream本身的reduce方法,增加了对自定义归约的支持package com.sw.demo.stream; import com.sw.demo.pojo.Person; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; /** * 6.5 规约(reducing) * Collectors类提供的reducing方法相较于stream本身的reduce方法,增加了对自定义规约的支持 */ public class collect05 { public static void main(String[] args) { List<Person> personList = new ArrayList<Person>(); personList.add(new Person("Tom", 8900, 18, "male", "昆明")); personList.add(new Person("Jack", 7000, 19, "male", "楚雄")); personList.add(new Person("Lily", 7800, 20, "female", "楚雄")); personList.add(new Person("Anni", 8200, 21, "female", "大理")); personList.add(new Person("Owen", 9500, 22, "male", "昆明")); personList.add(new Person("Alisa", 7900, 22, "female", "保山")); //每位员工增加50块奖金,求发奖金之后所有员工的薪资之和 Integer sum = personList.stream().collect(Collectors.reducing(0, Person::getSalary, (x, y) -> (x + y + 50))); System.out.println("发奖金之后的薪资之和:" + sum); //stream的reduce方法,求员工薪资之和 Optional<Integer> reduceSum = personList.stream().map(Person::getSalary).reduce(Integer::sum); System.out.println("员工薪资之和(reduce方法):"+reduceSum); } } 七、排序 sortedsorted():自然排序,流中元素需实现Comparable接口sorted(Comparator com):自定义排序package com.sw.demo.stream; import com.sw.demo.pojo.Person; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; /** * 7 排序(sort) * sorted():自然排序,流中元素实现Comparable接口 * sorted(Comparator com):Comparator排序器实现自定义排序 */ public class sorted07 { public static void main(String[] args) { List<Person> personList = new ArrayList<Person>(); personList.add(new Person("Tom", 8900, 18, "male", "昆明")); personList.add(new Person("Jack", 7000, 19, "male", "楚雄")); personList.add(new Person("Lily", 7800, 20, "female", "楚雄")); personList.add(new Person("Anni", 8900, 21, "female", "大理")); personList.add(new Person("Owen", 9500, 22, "male", "昆明")); personList.add(new Person("Alisa", 7900, 22, "female", "保山")); //例:按薪资排序(工资相同的按年龄比较) //升序排列(自然排序) List<String> listASC = personList.stream().sorted(Comparator.comparing(Person::getSalary)).map(Person::getName).collect(Collectors.toList()); //降序排列(升序反转即为降序) List<String> listDESC = personList.stream().sorted(Comparator.comparing(Person::getSalary).reversed()).map(Person::getName).collect(Collectors.toList()); //先按工资,再按年龄升序排列(升序) List<String> listASC01 = personList.stream().sorted(Comparator.comparing(Person::getSalary).thenComparing(Person::getAge)).map(Person::getName).collect(Collectors.toList()); //先按工资再按年龄自定义排序(降序) /* debug流程(降序):两两比较,a>b,a存起来,b继续跟c比较,如果b<c,则继续比较a、c两个数,否则反之 */ List<String> diy = personList.stream().sorted((p1, p2) -> { if (p1.getSalary() == p2.getSalary()) { //System.out.println(p2.getAge() - p1.getAge()); return p2.getAge() - p1.getAge(); } else { //System.out.println(p2.getSalary() - p1.getSalary()); return p2.getSalary() - p1.getSalary(); } }).map(Person::getName).collect(Collectors.toList()); System.out.println("自然排序:"+listASC); System.out.println("工资降序:"+listDESC); System.out.println("先按工资再按年龄自然排序:"+listASC01); System.out.println("自定义排序:"+diy); } } 八、提取/组合concat合并,distinct去重,limit限制,skip跳过package com.sw.demo.stream; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; /** * 8.提取/组合 * 对流进行合并、去重(distinct)、限制(limit)、跳过(skip)等操作 */ public class extract08 { public static void main(String[] args) { String[] arr1 = {"a", "b", "d", "r", "a"}; String[] arr2 = {"g", "r", "d", "b", "c"}; Stream<String> stream1 = Stream.of(arr1); Stream<String> stream2 = Stream.of(arr2); //合并两个流,并去重 List<String> concatDistinct = Stream.concat(stream1, stream2).distinct().collect(Collectors.toList()); //limit 限制只能从流中获取前n个数 List<Integer> limit = Stream.iterate(1, x -> x + 1).limit(10).collect(Collectors.toList()); //skip 跳过前n个数据,注:需加上limit限制,否则iterate构造器会一直创建数据 List<Integer> skip = Stream.iterate(1, x -> x + 2).skip(1).limit(5).collect(Collectors.toList()); System.out.println("合并流:" + concatDistinct); System.out.println("限制只能从流中获取前10个数:" + limit); System.out.println("跳过第一个数据:" + skip); } } 注:全文参考https://blog.csdn.net/mu_wind/article/details/109516995
2021年02月05日
225 阅读
0 评论
0 点赞
2021-01-06
集合不安全问题
集合类不安全List不安全package com.sw.unsafe; import java.util.*; import java.util.concurrent.CopyOnWriteArrayList; /** * @Author suaxi * @Date 2021/1/4 17:12 * java.util.ConcurrentModificationException 并发修改异常 */ public class ListTest { public static void main(String[] args) { /* 并发情况下ArrayList不安全 解决方案: 1、List<String> list = new Vector<>(); 2、List<String> list = Collections.synchronizedList(new ArrayList<>()); 3、List<String> list = new CopyOnWriteArrayList<>(); CopyOnWrite 写入时复制(是一种优化策略) 多个线程调用的时候可能存在写入覆盖问题,读取没问题 CopyOnWrite在写入的时候复制一份给调用者,调用者写入新的数据完成之 后再把之前复制的数据放回原来的位置,保证线程的安全,以此避免了写入覆盖问题 相较于Vector,它没有采用synchronized锁,而是采用Lock锁,效率更高 */ List<String> list = new CopyOnWriteArrayList<>(); for (int i = 0; i < 100; i++) { new Thread(() ->{ list.add(UUID.randomUUID().toString().substring(0,5)); System.out.println(list); },String.valueOf(i)).start(); } } } Set不安全package com.sw.unsafe; import java.util.*; import java.util.concurrent.CopyOnWriteArraySet; /** * @Author suaxi * @Date 2021/1/4 22:08 * java.util.ConcurrentModificationException 并发修改异常 * 解决方法: * 1、Set<String> set = Collections.synchronizedSet(new HashSet<>()); * 2、Set<String> set = new CopyOnWriteArraySet<>(); */ public class SetTest { public static void main(String[] args) { Set<String> set = new CopyOnWriteArraySet<>(); for (int i = 0; i < 30; i++) { new Thread(() ->{ set.add(UUID.randomUUID().toString().substring(0,5)); System.out.println(set); },String.valueOf(i)).start(); } } } hashSet底层是什么?public HashSet(){ map = new HashMap<>(); } //源码 //set add的本质就是map public boolean add(E e) { return map.put(e, PRESENT)==null; } //PRESENT是静态终类 private static final Object PRESENT = new Object();Map不安全package com.sw.unsafe; import java.util.HashMap; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; /** * @Author suaxi * @Date 2021/1/4 22:26 * java.util.ConcurrentModificationException * 解决方法: * Map<String, String> map = new ConcurrentHashMap<>(); */ public class MapTest { public static void main(String[] args) { //默认等价于? new HashMap<>(16,0.75); Map<String, String> map = new ConcurrentHashMap<>(); for (int i = 0; i < 30; i++) { new Thread(() ->{ map.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0,5)); System.out.println(map); },String.valueOf(i)).start(); } } }
2021年01月06日
589 阅读
0 评论
0 点赞
2021-01-06
8锁问题
8锁问题什么是锁?锁的对象是谁?package com.sw.lock8; import java.util.concurrent.TimeUnit; /** * @Author suaxi * @Date 2021/1/4 15:44 * 1、执行顺序:发短信 打电话 * 2、增加睡眠时间后,执行顺序:发短信 打电话 */ public class Test1 { public static void main(String[] args) { Phone1 phone1 = new Phone1(); new Thread(() ->{ phone1.sms(); },"A").start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(() ->{ phone1.call(); },"B").start(); } } class Phone1{ //synchronized锁的对象是方法的调用者 //两个方法用的是同一个锁,谁先拿到锁,谁先调用 public synchronized void sms(){ try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("发短信"); } public synchronized void call(){ System.out.println("打电话"); } }package com.sw.lock8; import java.util.concurrent.TimeUnit; /** * @Author suaxi * @Date 2021/1/4 15:51 * 3、增加一个hello的普通方法后,执行顺序为 hello 发短信 * 4、两个对象、两个同步方式,执行顺序为 打电话 发短信 */ public class Test2 { public static void main(String[] args) { //两个对象、两个调用者、两把锁 Phone2 phone1 = new Phone2(); Phone2 phone2 = new Phone2(); new Thread(() ->{ phone1.sms(); },"A").start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(() ->{ phone2.call(); },"B").start(); } } class Phone2{ //synchronized锁的对象是方法的调用者 public synchronized void sms(){ try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("发短信"); } public synchronized void call(){ System.out.println("打电话"); } //普通方法不受锁的限制 public void hello(){ System.out.println("hello"); } }package com.sw.lock8; import java.util.concurrent.TimeUnit; /** * @Author suaxi * @Date 2021/1/4 15:58 * 5、增加static后,执行顺序为 发短信 打电话 * 6、两个Phone对象,执行顺序依然为为 发短信 打电话 */ public class Test3 { public static void main(String[] args) { //两个对象的Class类模板只有一个,与问题5一样锁的也是Class Phone3 phone = new Phone3(); Phone3 phone1 = new Phone3(); new Thread(() ->{ phone.sms(); },"A").start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(() ->{ phone1.call(); },"B").start(); } } class Phone3{ //synchronized锁的对象是方法的调用者 //static静态方法,类一加载就有了,此处锁的是Class对象 public static synchronized void sms(){ try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("发短信"); } public static synchronized void call(){ System.out.println("打电话"); } }package com.sw.lock8; import java.util.concurrent.TimeUnit; /** * @Author suaxi * @Date 2021/1/4 16:05 * 7、1个静态同步方法,1个普通同步方法,一个对象,执行顺序 打电话 发短信 * 8、1个静态同步方法,1个普通同步方法,两个对象,执行顺序 打电话 发短信 */ public class Test4 { public static void main(String[] args) { //两个对象的Class类模板只有一个,与问题5一样锁的也是Class Phone4 phone1 = new Phone4(); Phone4 phone2 = new Phone4(); new Thread(() ->{ phone1.sms(); },"A").start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(() ->{ phone2.call(); },"B").start(); } } class Phone4{ //静态同步方法 锁的是Class类模板 public static synchronized void sms(){ try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("发短信"); } //普通同步方法 锁的是调用者,不需要再等待发短信的sleep睡眠时间,两个方法用的不是同一个锁 public synchronized void call(){ System.out.println("打电话"); } }小结一个对象,拿的是同一把锁两个对象拿的是不同的锁加了static静态方法之后,不论有几个对象,锁的只有一个Class模板普通方法不受锁的限制
2021年01月06日
91 阅读
0 评论
0 点赞
2021-01-06
生产者和消费者问题
生产者和消费者问题package com.sw.pc; /** * @Author suaxi * @Date 2021/1/4 14:25 */ public class A { public static void main(String[] args) { Data data = new Data(); new Thread(() ->{ for (int i = 0; i < 10; i++) { try { data.incr(); } catch (InterruptedException e) { e.printStackTrace(); } } },"A").start(); new Thread(() ->{ for (int i = 0; i < 10; i++) { try { data.decr(); } catch (InterruptedException e) { e.printStackTrace(); } } },"B").start(); } } class Data{ private int num = 0; //+1 public synchronized void incr() throws InterruptedException { if (num!=0){ //等待 this.wait(); } num++; System.out.println(Thread.currentThread().getName()+"===>"+num); //通知 this.notifyAll(); } //-1 public synchronized void decr() throws InterruptedException { if (num==0){ //等待 this.wait(); } num--; System.out.println(Thread.currentThread().getName()+"===>"+num); //通知 this.notifyAll(); } } 当增加多个线程时(A,B,C,D),会出现虚假唤醒的问题虚假唤醒:线程可以被唤醒,但不会被通知、中断或超时解决方法:将if判断换为whilepackage com.sw.pc; /** * @Author suaxi * @Date 2021/1/4 14:25 */ public class A { public static void main(String[] args) { Data data = new Data(); new Thread(() ->{ for (int i = 0; i < 10; i++) { try { data.incr(); } catch (InterruptedException e) { e.printStackTrace(); } } },"A").start(); new Thread(() ->{ for (int i = 0; i < 10; i++) { try { data.decr(); } catch (InterruptedException e) { e.printStackTrace(); } } },"B").start(); new Thread(() ->{ for (int i = 0; i < 10; i++) { try { data.incr(); } catch (InterruptedException e) { e.printStackTrace(); } } },"C").start(); new Thread(() ->{ for (int i = 0; i < 10; i++) { try { data.decr(); } catch (InterruptedException e) { e.printStackTrace(); } } },"D").start(); } } class Data{ private int num = 0; //+1 public synchronized void incr() throws InterruptedException { while (num!=0){ //等待 this.wait(); } num++; System.out.println(Thread.currentThread().getName()+"===>"+num); //通知 this.notifyAll(); } //-1 public synchronized void decr() throws InterruptedException { while (num==0){ //等待 this.wait(); } num--; System.out.println(Thread.currentThread().getName()+"===>"+num); //通知 this.notifyAll(); } } JUC版生产者消费者问题使用了Condition接口下的await()等待和signalAll()通知package com.sw.pc; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @Author suaxi * @Date 2021/1/4 14:55 */ public class B { public static void main(String[] args) { Data1 data1 = new Data1(); new Thread(() ->{ for (int i = 0; i < 10; i++) { try { data1.incr(); } catch (InterruptedException e) { e.printStackTrace(); } } },"A").start(); new Thread(() ->{ for (int i = 0; i < 10; i++) { try { data1.decr(); } catch (InterruptedException e) { e.printStackTrace(); } } },"B").start(); new Thread(() ->{ for (int i = 0; i < 10; i++) { try { data1.incr(); } catch (InterruptedException e) { e.printStackTrace(); } } },"C").start(); new Thread(() ->{ for (int i = 0; i < 10; i++) { try { data1.decr(); } catch (InterruptedException e) { e.printStackTrace(); } } },"D").start(); } } class Data1{ private int num = 0; Lock lock = new ReentrantLock(); Condition condition = lock.newCondition(); //+1 public void incr() throws InterruptedException { try { lock.lock(); //加锁 while (num!=0){ //等待 condition.await(); } num++; System.out.println(Thread.currentThread().getName()+"===>"+num); //通知 condition.signalAll(); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); //解锁 } } //-1 public void decr() throws InterruptedException { try { lock.lock(); //加锁 while (num==0){ //等待 condition.await(); } num--; System.out.println(Thread.currentThread().getName()+"===>"+num); //通知 condition.signalAll(); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); //解锁 } } }Condition精准通知与线程唤醒可以看到之前的线程执行顺序是无序的。package com.sw.pc; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @Author suaxi * @Date 2021/1/4 15:08 * Condition精准通知与线程唤醒 * ABC三个人互相打电话,A->B,B->C,C->A顺序执行 */ public class C { public static void main(String[] args) { Data2 data2 = new Data2(); new Thread(() ->{ for (int i = 0; i < 10; i++) { data2.CallA(); } },"A").start(); new Thread(() ->{ for (int i = 0; i < 10; i++) { data2.CallB(); } },"B").start(); new Thread(() ->{ for (int i = 0; i < 10; i++) { data2.CallC(); } },"C").start(); } } class Data2{ private int num = 1; // 1A 2B 3C private Lock lock = new ReentrantLock(); Condition condition1 = lock.newCondition(); Condition condition2 = lock.newCondition(); Condition condition3 = lock.newCondition(); public void CallA(){ try { lock.lock(); //加锁 while (num!=1){ //等待 condition1.await(); } num = 2; System.out.println(Thread.currentThread().getName()+"===>A打完了"); //通知 condition2.signal(); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); //解锁 } } public void CallB(){ try { lock.lock(); //加锁 while (num!=2){ //等待 condition2.await(); } num = 3; System.out.println(Thread.currentThread().getName()+"===>B打完了"); //通知 condition3.signal(); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); //解锁 } } public void CallC(){ try { lock.lock(); //加锁 while (num!=3){ //等待 condition3.await(); } num = 1; System.out.println(Thread.currentThread().getName()+"===>C打完了"); //通知 condition1.signal(); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); //解锁 } } } 通过不同的监视器监视线程来达到精准通知与线程唤醒的目的
2021年01月06日
148 阅读
0 评论
0 点赞
2021-01-06
Lock锁
Lock锁传统synchronized锁package com.sw; /** * @Author suaxi * @Date 2021/1/4 14:00 */ public class SaleTicket01 { public static void main(String[] args) { Ticket1 ticket1 = new Ticket1(); new Thread(() ->{for (int i = 0; i < 30; i++) ticket1.sale();},"A").start(); new Thread(() ->{for (int i = 0; i < 30; i++) ticket1.sale();},"B").start(); new Thread(() ->{for (int i = 0; i < 30; i++) ticket1.sale();},"C").start(); } } //synchronized锁 class Ticket1{ private int num = 30; public synchronized void sale(){ if (num>0){ System.out.println(Thread.currentThread().getName()+"卖了"+(num--)+"张票,剩余:"+num); } } } Lock接口公平锁:先来后到非公平锁:可以插队(默认使用)package com.sw; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @Author suaxi * @Date 2021/1/4 11:28 */ public class SaleTicket02 { public static void main(String[] args) { Ticket ticket = new Ticket(); new Thread(() ->{for (int i = 0; i < 30; i++) ticket.sale();},"A").start(); new Thread(() ->{for (int i = 0; i < 30; i++) ticket.sale();},"B").start(); new Thread(() ->{for (int i = 0; i < 30; i++) ticket.sale();},"C").start(); } } //Lock锁 class Ticket{ private int num = 30; //1.新建重入锁 Lock lock = new ReentrantLock(); public void sale(){ lock.lock(); //2.加锁 try{ //业务代码 if (num>0){ System.out.println(Thread.currentThread().getName()+"卖了"+(num--)+"张票,剩余:"+num); } }catch (Exception e){ e.printStackTrace(); }finally { lock.unlock(); //3.解锁 } } } synchronized与Lock的区别1、synchronized 是内置的Java关键字;Lock是一个Java类2、synchronized 无法判断 获取锁 的状态;Lock可以判断3、synchronized 会自动释放锁;Lock必须手动释放,如果不释放,会产生死锁问题4、synchronized 线程1(获得锁,阻塞),线程2(一直傻傻的等待);Lock锁就不一定会一直等待下去lock.trylock()5、synchronized 可重入锁,不可中断,非公平;Lock 可重入锁,可以判断锁的状态,非公平(可自定义公平性)6、synchronized 适用于锁少量的同步代码问题;Lock 适合大量同步代码问题
2021年01月06日
66 阅读
0 评论
0 点赞
2021-01-01
Spring Cloud Config分布式配置中心
Spring Cloud ConfigSpring Cloud Config为微服务架构中的微服务提供集中化的外部配置支持,配置服务器为各个不同微服务应用的所有环节提供了一个中心化的外部配置。Spring Cloud Config分为客户端和服务端:服务端:分布式配置中心,它是一个独立的微服务应用,用来连接配置服务器,并为客户端提供获取配置信息,加密,解密信息等访问接口客户端:通过指定的配置中心来管理应用资源,以及与业务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息。配置服务器默认采用git来存储配置信息,这样有助于对环境配置进行版本管理。作用:集中管理配置文件不同环境,不同配置,动态化的配置更新,分环境部署,如:开发、测试、生产等环境运行期间可以动态调整配置,不再需要在每个服务部署的机器上编写配置文件,服务会向配置中心统一拉取配置自己的信息当配置发生变动时,服务节点不需要重启,动态应用新的配置配置信息以REST接口的形式暴露图片来源:狂神说Java具体实例1、服务端pom依赖:<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> <version>2.1.1.RELEASE</version> </dependency> <!--actuator监控信息--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> </dependencies>application.yml配置:server: port: 3344 spring: application: name: springcloud-config-server #连接远程仓库 cloud: config: server: git: uri: https://github.com/suaxi/SpringCloud-config.gitSpringBoot启动类开启ConfigServer注解:package com.sw.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.config.server.EnableConfigServer; /** * @Author suaxi * @Date 2020/12/30 14:49 */ @SpringBootApplication @EnableConfigServer public class Config_Server_3344 { public static void main(String[] args) { SpringApplication.run(Config_Server_3344.class,args); } } 2、客户端pom依赖:<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> <version>2.1.1.RELEASE</version> </dependency> <!--actuator监控信息--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> </dependencies>bootstrap.yml配置:#系统级别的配置 spring: cloud: config: name: config-client #需要从远程仓库读取的资源名称 profile: dev #版本 label: master #分支 uri: http://localhost:3344 #获取配置信息的地址(Config配置服务端)application.yml配置:#用户级别的配置 spring: application: name: springcloud-config-client-3355Controller(配置REST接口)package com.sw.springcloud.controller; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * @Author suaxi * @Date 2020/12/30 15:29 */ @RestController public class ConfigClientController { @Value("${spring.application.name}") private String applicationName; @Value("${eureka.client.service-url.defaultZone}") private String eurekaServer; @Value("${server.port}") private String port; @RequestMapping("/config") public String getConfig(){ return "applicationName:"+applicationName+ "eurekaServer:"+eurekaServer+ "port:"+port; } } 3、Eureka服务注册中心pom依赖:<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka-server</artifactId> <version>1.4.7.RELEASE</version> </dependency> <!--config--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> <version>2.1.1.RELEASE</version> </dependency> </dependencies>bootstrap.yml配置:与config配置中心的客户端一致,都是从Config服务端获取配置信息spring: cloud: config: name: config-eureka label: master profile: dev uri: http://localhost:3344application.yml配置:spring: application: name: springcloud-config-eureka-7001SpringBoot启动类:package com.sw.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; /** * @Author suaxi * @Date 2020/12/29 11:02 */ @SpringBootApplication @EnableEurekaServer //服务端 public class EurekaConfigServer_7001 { public static void main(String[] args) { SpringApplication.run(EurekaConfigServer_7001.class,args); } } 4、Eureka服务提供者pom依赖:<dependencies> <!--需要拿到实体类,配置api module--> <dependency> <groupId>com.sw</groupId> <artifactId>springcloud-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jetty</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> <version>1.4.7.RELEASE</version> </dependency> <!--actuator监控信息--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId> <version>1.4.7.RELEASE</version> </dependency> <!--config--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> <version>2.1.1.RELEASE</version> </dependency> </dependencies>bootstrap.yml配置:与以上两个的配置一致,都是从Config服务端获取配置信息spring: cloud: config: name: config-dept label: master profile: dev uri: http://localhost:3344application.yml配置:spring: application: name: springcloud-config-dept-8088服务提供者对比之前的配置(application.yml):通过Config分布式配置中心,将配置文件放到git统一管理,现只需从Config-server获取即可server: port: 8088 #mybatis配置 mybatis: type-aliases-package: com.sw.springcloud.pojo config-location: classpath:mybatis/mybatis-config.xml mapper-locations: classpath:mybatis/mapper/*.xml #Spring配置 spring: application: name: springcloud-provider-dept datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/db01?useUnicode=true&character=UFT-8 username: root password: 123456 #配置Eureka,配置服务注册到哪里 eureka: client: service-url: defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/ instance: instance-id: springcloud-provider_dept8088 #修改Eureka默认描述信息 prefer-ip-address: true #显示服务的真实ip地址,替换原先的localhost #info配置 info: app.name: springcloud-demo company.name: suaxi 配置文件交由git统一管理
2021年01月01日
80 阅读
0 评论
0 点赞
2020-12-31
Zuul路由网关
Zuul路由网关Zuul包含对请求的路由和过滤两个功能:路由功能:负责将外部请求转发到具体的微服务实例上,实现外部访问入口统一过滤:对请求的处理过程进行干预,是实现请求校验,服务聚合等功能的基础注:Zuul服务也会注册到Eureka服务注册中心1、导入依赖<dependencies> <!--zuul--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zuul</artifactId> <version>1.4.7.RELEASE</version> </dependency> <!--hystrix--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId> <version>1.4.7.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId> <version>1.4.7.RELEASE</version> </dependency> <!--Ribbon--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-ribbon</artifactId> <version>1.4.7.RELEASE</version> </dependency> <!--Eureka--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> <version>1.4.7.RELEASE</version> </dependency> <dependency> <groupId>com.sw</groupId> <artifactId>springcloud-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>2、application.yml配置server: port: 8888 spring: application: name: springcloud-zuul eureka: client: service-url: defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/ instance: instance-id: zuul8888.com prefer-ip-address: true info: app.name: springcloud-demo company.name: suaxi zuul: routes: mydept.serviceID: springcloud-provider-dept mydept.path: /mydept/** ignored-services: "*" #ignored-services: springcloud-provider-dept禁止使用原来的微服务名访问 #设置为 * 表示禁止使用全部的微服务ID进行访问3、SpringBoot启动类开启Zuul注解一般使用@EnableZuulProxypackage com.sw.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.zuul.EnableZuulProxy; /** * @Author suaxi * @Date 2020/12/30 10:50 */ @SpringBootApplication @EnableZuulProxy //开启Zuul路由网关 public class ZuulApplication_8888 { public static void main(String[] args) { SpringApplication.run(ZuulApplication_8888.class,args); //http://www.xxx.com:8888/mydept/dept/get/1 } } 开启Zuul路由网关后,可通过:域名+端口号 访问微服务项目
2020年12月31日
95 阅读
0 评论
0 点赞
2020-12-31
Hystrix服务降级
Hystrix服务降级A、B、C三台服务器,A在某一时间段的负载很重,急需扩容,而此时间段B、C负载很小或没有访问量,需关闭其中的服务器,拿去给A扩容,以降低负载,同时设置fallback回调,让这个时间段需要访问B、C服务器的用户得到“服务暂时不可用或关闭”的信息,这个过程可以简单的比喻为服务降级。1、API接口设置fallback回调pojopackage com.sw.springcloud.pojo; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; import java.io.Serializable; /** * @Author suaxi * @Date 2020/12/28 21:07 */ @Data @NoArgsConstructor @Accessors(chain = true) //链式编程 public class Dept implements Serializable { private Long deptno; private String dname; private String db_source; //数据存在哪个数据库 public Dept(String dname) { this.dname = dname; } } service接口package com.sw.springcloud.service; import com.sw.springcloud.pojo.Dept; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import java.util.List; /** * @Author suaxi * @Date 2020/12/29 20:02 */ @Component @FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT",fallbackFactory = DeptClientServiceFallbackFactory.class) public interface DeptClientService { @GetMapping("/dept/get/{id}") public Dept findById(@PathVariable("id")Long id); @GetMapping("/dept/list") public List<Dept> findAll(); @PostMapping("/dept/add") public boolean addDept(Dept dept); } FallbackFactoryService服务降级设置package com.sw.springcloud.service; import com.sw.springcloud.pojo.Dept; import feign.hystrix.FallbackFactory; import org.springframework.stereotype.Component; import java.util.List; /** * @Author suaxi * @Date 2020/12/30 9:33 * 服务降级 */ @Component public class DeptClientServiceFallbackFactory implements FallbackFactory { @Override public Object create(Throwable throwable) { return new DeptClientService() { @Override public Dept findById(Long id) { return new Dept() .setDeptno(id) .setDname("未查询到数据,该服务现已被关闭") .setDb_source("没有数据库信息"); } @Override public List<Dept> findAll() { return null; } @Override public boolean addDept(Dept dept) { return false; } }; } /* 服务熔断:服务端,某个服务超时或异常,引起熔断(类似于保险丝) 服务降级:客户端,从系统整体负载考虑,当某个服务熔断或关闭之后,服务将不再被调用 此时在客户端可以设置一个回调FallbackFactory,返回一个默认的缺省值,可以 提升用户体验,但服务质量随之下降 */ } 2、消费者端设置appliction.yml配置服务降级server: port: 80 eureka: client: register-with-eureka: false #不向注册中心注册自己(消费者端) service-url: defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/ #开启降级feign.hystrix feign: hystrix: enabled: true将RestTemplate注册到Spring容器中package com.sw.springcloud.config; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; /** * @Author suaxi * @Date 2020/12/28 22:15 */ @Configuration public class ConfigBean { @Bean @LoadBalanced //注册Ribbon public RestTemplate getRestTemplate(){ return new RestTemplate(); } } SpringBoot启动类package com.sw.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.context.annotation.ComponentScan; /** * @Author suaxi * @Date 2020/12/28 22:29 */ @SpringBootApplication @EnableEurekaClient @EnableFeignClients(basePackages = {"com.sw.springcloud"}) public class FeignDeptConsumer_80 { public static void main(String[] args) { SpringApplication.run(FeignDeptConsumer_80.class,args); } } 用户正常访问服务:微服务节点出现问题,服务降级:
2020年12月31日
144 阅读
0 评论
0 点赞
1
...
9
10
11
...
20