# okgomall **Repository Path**: enjoycode10/okgomall ## Basic Information - **Project Name**: okgomall - **Description**: init okgomall - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-08-12 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # okgomall ### Nacos 如何使用Nacos作为配置中心统一管理配置 1)、引入依赖, com.alibaba.cloud spring-cloud-starter-alibaba-nacos-config 2)、创建一个bootstrap.properties。 spring.application.name=okgomall-coupon spring.cloud.nacos.config.server-addr=127.0.0.1:8848 3)、需要给配置中心默认添加一个叫 数据集(Data Id)okgomall-coupon.properties。默认规则,应用名.properties 4)、给 应用名.properties 添加任何配置 5)、动态获取配置。 @RefreshScope:动态获取并刷新配置 @Value("${配置项的名}"):获取到配置。 如果配置中心和当前应用的配置文件中都配置了相同的项,优先使用配置中心的配置。 细节 1)、命名空间:配置隔离; 默认:public(保留空间);默认新增的所有配置都在public空间。 1、开发,测试,生产:利用命名空间来做环境隔离。 注意:在bootstrap.properties;配置上,需要使用哪个命名空间下的配置, spring.cloud.nacos.config.namespace=9de62e44-cd2a-4a82-bf5c-95878bd5e871 2、每一个微服务之间互相隔离配置,每一个微服务都创建自己的命名空间,只加载自己命名空间下的所有配置 2)、配置集:所有的配置的集合 3)、配置集ID:类似文件名。 Data ID:类似文件名 4)、配置分组: 默认所有的配置集都属于:DEFAULT_GROUP; 1111,618,1212 项目中的使用:每个微服务创建自己的命名空间,使用配置分组区分环境,dev,test,prod 同时加载多个配置集 1)、微服务任何配置信息,任何配置文件都可以放在配置中心中 2)、只需要在bootstrap.properties说明加载配置中心中哪些配置文件即可 3)、@Value,@ConfigurationProperties。。。 以前SpringBoot任何方法从配置文件中获取值,都能使用。 配置中心有的优先使用配置中心中的, ### feign 想要远程调用别的服务 1)、引入open-feign 2)、编写一个接口,告诉SpringCloud这个接口需要调用远程服务 3) 、声明接口的每一个方法都是调用哪个远程服务的那个请求 4)、开启远程调用功能 ### gateway 版本 spring-cloud.version=Hoxton.SR6, spring-boot.version=2.3.1.RELEASE or spring-cloud.versio n=Hoxton.SR6, spring-boot.version=2.2.1.RELEASE + io.projectreactor.netty reactor-netty 0.9.4.RELEASE ### Validate 1、整合MyBatis-Plus 1)、导入依赖 com.baomidou mybatis-plus-boot-starter 3.2.0 2)、配置 1、配置数据源; 1)、导入数据库的驱动。https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-versions.html 2)、在application.yml配置数据源相关信息 2、配置MyBatis-Plus; 1)、使用@MapperScan 2)、告诉MyBatis-Plus,sql映射文件位置 2、逻辑删除 1)、配置全局的逻辑删除规则(省略) 2)、配置逻辑删除的组件Bean(省略) 3)、给Bean加上逻辑删除注解@TableLogic 3、JSR303 1)、给Bean添加校验注解:javax.validation.constraints,并定义自己的message提示 2)、开启校验功能@Valid 效果:校验错误以后会有默认的响应; 3)、给校验的bean后紧跟一个BindingResult,就可以获取到校验的结果 4)、分组校验(多场景的复杂校验) 1)、 @NotBlank(message = "品牌名必须提交",groups = {AddGroup.class,UpdateGroup.class}) 给校验注解标注什么情况需要进行校验 2)、@Validated({AddGroup.class}) 3)、默认没有指定分组的校验注解@NotBlank,在分组校验情况@Validated({AddGroup.class})下不生效,只会在@Validated生效; 5)、自定义校验 1)、编写一个自定义的校验注解 2)、编写一个自定义的校验器 ConstraintValidator 3)、关联自定义的校验器和自定义的校验注解 * @Documented * @Constraint(validatedBy = { ListValueConstraintValidator.class【可以指定多个不同的校验器,适配不同类型的校验】 }) * @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE }) * @Retention(RUNTIME) * public @interface ListValue { 4、统一的异常处理 @ControllerAdvice 1)、编写异常处理类,使用@ControllerAdvice。 2)、使用@ExceptionHandler标注方法可以处理的异常。 ### SpringCache简化缓存开发 1). 引入依赖 spring-boot-starter-cache, spring-boot-starter-data-redis 2). 写配置 1. 自动配置了CacheAutoConfiguration会导入RedisCacheConfiguration // 获取缓存类型 CacheConfigurations.getConfigurationClass(types[i]); static { Map> mappings = new EnumMap<>(CacheType.class); mappings.put(CacheType.GENERIC, GenericCacheConfiguration.class); mappings.put(CacheType.EHCACHE, EhCacheCacheConfiguration.class); mappings.put(CacheType.HAZELCAST, HazelcastCacheConfiguration.class); mappings.put(CacheType.INFINISPAN, InfinispanCacheConfiguration.class); mappings.put(CacheType.JCACHE, JCacheCacheConfiguration.class); mappings.put(CacheType.COUCHBASE, CouchbaseCacheConfiguration.class); mappings.put(CacheType.REDIS, RedisCacheConfiguration.class); mappings.put(CacheType.CAFFEINE, CaffeineCacheConfiguration.class); mappings.put(CacheType.SIMPLE, SimpleCacheConfiguration.class); mappings.put(CacheType.NONE, NoOpCacheConfiguration.class); MAPPINGS = Collections.unmodifiableMap(mappings); } 2. RedisCacheConfiguration 自动配好了缓存管理器 RedisCacheManager cacheManager():返回RedisCacheManager bean 3. cacheManager() 初始化缓存配置 4. 缓存配置: spring.cache.type=redis 5. 测试使用缓存 @Cacheable: Triggers cache population.触发将数据保存到缓存的操作 代表当前的方法需要缓存,如果缓存中有,方法不调用执行;如果缓存中没有,会调用方法,并将结果放入缓存 每一个需要缓存的数据我们要指定缓存cacheNames或value, 即缓存的分区(按照业务类型分) * 默认行为 * 如果缓存中有,方法不再调用 * key是默认生成的:缓存的名字::SimpleKey::[](自动生成key值) * 缓存的value值,默认使用jdk序列化机制,将序列化的数据存到redis中 * TTL默认时间是 -1: * * 自定义操作:key的生成 * 指定生成缓存的key:key属性指定,接收一个SpEL,如果是一个字符串,用单引号 * 指定缓存的数据的存活时间:配置文档中修改存活时间,spring.cache.redis.time-to-live=3600000 * 将数据保存为json格式 @CacheEvict: Triggers cache eviction.触发将数据从缓存移除的操作 @CachePut: Updates the cache without interfering with the method execution.不影响方法执行更新缓存 @Caching: Regroups multiple cache operations to be applied on a method.组合以上多个操作 @CacheConfig: Shares some common cache-related settings at class-level.在类级别共享缓存的相同配置 1). 启动类开启缓存功能:@EnableCaching 2). 6. 原理 CacheAutoConfiguration -> RedisCacheConfiguration -> 自动配置了RedisCacheManager -> 初始化所有的缓存 -> 每个缓存决定使用什么配置 -> 如果 redisCacheConfiguration 有就用已有的,没有就用默认配置 -> 想修改缓存的配置,只需要给容器中存放一个 RedisCacheConfiguration 即可 -> 就会应用到当前RedisCacheManager管理的所有缓存分区中 7. Spring-Cache的不足 1)、读模式 缓存穿透:查询一个null数据。解决方案:缓存空数据。spring.cache.redis.cache-null-values=true 缓存击穿:大量并发进来同时查询一个正好过期的数据。解决方案:加锁 ? 默认是无加锁的;使用sync = true来解决击穿问题 缓存雪崩:大量的key同时过期。解决:加随机时间。加上过期时间。spring.cache.redis.time-to-live=3600000 2)、写模式:(缓存与数据库一致) 1)、读写加锁,适合读多写少的系统。 2)、引入Canal,感知到MySQL的更新去更新Redis 3)、读多写多,直接去数据库查询就行 总结: 常规数据(读多写少,即时性、一致性要求不高的数据,完全可以使用Spring-Cache):写模式(只要缓存的数据有过期时间就足够了) 特殊数据:特殊设计 原理: CacheManager(RedisCacheManager)->Cache(RedisCache)->Cache负责缓存的读写 ### ThreadLocal 同一个线程内共享数据:每一个http请求过来,Tomcat会开一个线程处理请求(从拦截器的执行,到调用controller,service,dao)直到请求结束给浏览器进行响应,从始至终都是同一个线程。 在同一个线程期间,ThreadLocal内的数据共享。 ### RabbitMQ 1. 引入AMQP场景启动器,RabbitAutoConfiguration就会自动生效 org.springframework.boot spring-boot-starter-amqp 2. 给容器中自动配置 CachingConnectionFactory RabbitConnectionFactoryBean RabbitTemplate AmqpAdmin RabbitMessagingTemplate 3. 所以属性都是配置在 @EnableConfigurationProperties(RabbitProperties.class) @ConfigurationProperties(prefix = "spring.rabbitmq") public class RabbitProperties {} 4. 开启注解 @EnableRabbit 5. 监听消息:使用@RabbitListener(前提必须开启@EnableRabbit) @RabbitListener 可以加在类和方法上:表明当前类种的方法可以接收多个队列中的多种消息 @RabbitHandler 只能加在方法上:根据消息体的类型来判断要执行哪个方法 ### Seata控制分布式事务 1)、每一个微服务对应的数据库必须创建undo_Log 2)、安装事务协调器:seate-server https://github.com/seata/seata/releases 3)、整合 1、导入依赖 spring-cloud-starter-alibaba-seata seata-all:1.1.0 2、解压并启动seata-server: registry.conf:注册中心配置 修改 registry : nacos file.conf:配置文件 3、所有想要用到分布式事务的微服务使用seata DataSourceProxy 代理自己的数据源 4、每个微服务,都必须导入 registry.conf file.conf vgroup_mapping.{application.name}-fescar-server-group = "default" 5、启动测试分布式事务 6、给分布式大事务的入口标注@GlobalTransactional 7、每一个远程的小事务用@Trabsactional #### Sentinel 1. 整合 1)、导入依赖 spring-cloud-starter-alibaba-sentinel 2)、下载sentinel控制台 3)、配置 sentinel 控制台地址信息 4)、在控制台调整参数、【默认所有的流控规则保存在内存中,重启失效】 2、每一个微服务都导入 actuator :并配合 management.endpoints.web.exposure.include=* 3、自定义 sentinel 流控返回的数据 4、使用Sentinel来保护feign远程调用,熔断; 1)、调用方的熔断保护:feign.sentinel.enable=true 2)、调用方手动指定远程服务的降级策略。远程服务被降级处理。触发我们的熔断回调方法 3)、超大浏览的时候,必须牺牲一些远程服务。在服务的提供方(远程服务)指定降级策略; 提供方是在运行,但是不允许自己的业务逻辑,返回的是默认的降级数据(限流的数据) 5、自定义受保护的资源 1)、代码 try (Entry entry = SphU.entry("seckillSkus")) { //业务逻辑 } catch(Exception e) {} 2)、基于注解 Windows 查看所有端口:netstat -ano Windows 查看指定端口:netstat -ano|findstr 端口号 Windows 查看指定端口的进程:tasklist|findstr 进程号 #### 介绍 OKGO商城 #### 软件架构 软件架构说明 #### 安装教程 1. xxxx 2. xxxx 3. xxxx #### 使用说明 1. xxxx 2. xxxx 3. xxxx #### 参与贡献 1. Fork 本仓库 2. 新建 Feat_xxx 分支 3. 提交代码 4. 新建 Pull Request #### 码云特技 1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md 2. 码云官方博客 [blog.gitee.com](https://blog.gitee.com) 3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解码云上的优秀开源项目 4. [GVP](https://gitee.com/gvp) 全称是码云最有价值开源项目,是码云综合评定出的优秀开源项目 5. 码云官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) 6. 码云封面人物是一档用来展示码云会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)