springcloud:成熟的微服务框架,定位为开发人员提供工具,以快速构建分布式系统

项目搭建流程:
1、新建多模块项目,开发
2、服务注册与发现Eureka,注册服务方便引用
3、利用Fegin实现服务间调用
4、服务调用正常,考虑服务的负载均衡,使用Ribbon
5、服务宕机,容灾,避免大面积服务瘫痪,使用熔断器Hystrix
6、整体系统发布统一ip端口,使用网关Zuul,也可对请求进行过滤器的编写
其他:
1、Session共享机制
2、微服务应用开发重难点环节
3、微服务子模块通过网关访问文件,需配置地址映射
4、缓存的配置类
一、Eureka服务端搭建(注册中心)
- 一、Eureka服务端搭建(引依赖、加配置、使用注解)
- // 新建子模块pom引入依赖
-
-
-
org.springframework.cloud -
spring-cloud-starter-netflix-eureka-server -
-
-
- //application.properties加配置
- spring.application.name=eureka-server 服务名
- server.port=8000 服务端口
- eureka.instance.hostname=localhost 主机名称
- eureka.client.fetch-registry=false fetch-registry获取注册表,不需要同步其他节点数据
- eureka.client.register-with-eureka=false register-with-eureka代表是否将自己注册到eureka-server,默认是true
- eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/ 服务对外所提供的地址
-
-
- //启动类加注解@EnableEurekaServer
- @EnableEurekaServer
- @SpringBootApplication
- public class EurekaServerApplication {
-
- public static void main(String[] args) {
- SpringApplication.run(EurekaServerApplication.class, args);
- }
- }
-
- ====eureka-server配置完成,访问地址http://localhost:8000/查看服务注册情况
-
二、Eureka客户端搭建(子模块服务注册)
- 二、Eureka客户端搭建(引入pom依赖,配置文件编写)
-
- //引入pom依赖
-
-
org.springframework.cloud -
spring-cloud-starter-netflix-eureka-client -
-
- //application.properties配置文件修改
- //增加服务端注册中心地址
- eureka.client.service-url.defaultZone=http://localhost:8000/eureka/
-
- =====先启动server,再启动子模块客户端服务,查看服务端网页注册情况,注册成功
三、利用Fegin实现服务间调用(子模块业务间调用,不经过网关,需要携带网关的Session信息,只用RequestInterceptor请求拦截器)
- 三、利用Fegin实现服务间调用(pom引入依赖、加配置、引注解)
-
- //引入pom
-
-
org.springframework.cloud -
spring-cloud-starter-openfeign -
-
- //启动类加注解@EnableFeignClients,拥有调用Feign的能力
- @SpringBootApplication
- @EnableFeignClients
- public class CoursePriceApplication {
-
- public static void main(String[] args) {
- SpringApplication.run(CoursePriceApplication.class, args);
- }
- }
-
- //代码新增其他模块提供的服务接口用作Feign客户端
- @FeignClient(value="course-list") value一般为要调用的子模块的服务名,接口为对外提供的接口,引用的实体可依赖其他模块
- public interface CourseListClient {
-
- @GetMapping("/courses")
- List
courseList(); - }
-
- //使用注解在其他方法内直接调用
-
-
- //子模块调用携带网关的Session信息
- /**
- * 描述: Feign请求拦截器
- */
- @EnableFeignClients
- @Configuration
- public class FeignRequestInterceptor implements RequestInterceptor {
-
- @Override
- public void apply(RequestTemplate requestTemplate) {
- //通过RequestContextHolder获取到请求
- RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
- if (requestAttributes == null) {
- return;
- }
- HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
- Enumeration
headerNames = request.getHeaderNames(); - if (headerNames != null) {
- while (headerNames.hasMoreElements()) {
- String name = headerNames.nextElement();
- Enumeration
values = request.getHeaders(name); - while (values.hasMoreElements()) {
- String value = values.nextElement();
- requestTemplate.header(name, value);
- }
- }
- }
- }
- }
四、使用Ribbon实现负载均衡

- //四、指定对应服务使用ribbon负载均衡(加配置)
- course-list.ribbon.NFLoadBanlancerRuleClassName=com.netflix.loadbalancer.RoundRobinRule
-
- 要调用的服务名.ribbon.NFLoadBanlancerRuleClassName=负载均衡策略
五、 使用熔断器Hystrix
- //五、使用断路器(加依赖、加配置,加注解,代码引入)
- //在调用方加入断路器
-
- //加入pom依赖
-
-
org.springframework.cloud -
spring-cloud-starter-netflix-hystrix -
-
- //application.properties配置文件修改
- feign.hystrix.enabled=true 开启断路器配置,默认不开启
-
- //启动类加入断路器注解@EnableCircuitBreaker
- @SpringBootApplication
- @EnableFeignClients
- @EnableCircuitBreaker
- public class CoursePriceApplication {
-
- public static void main(String[] args) {
- SpringApplication.run(CoursePriceApplication.class, args);
- }
- }
-
-
- //编码引入,断路后如何进行处理
- //新建断路器实现类,针对要调用的类接口进行断路后处理实现
- @Component
- public class CourseListClientHystrix implements CourseListClient {
-
- @Override
- public List
courseList() { - return Collections.emptyList();
- }
- }
-
- //之前的Feign客户端进行断路器配置,增加fallback指定发生错误要调用的类
- @FeignClient(value = "course-list", fallback = CourseListClientHystrix.class)
- @Primary
- public interface CourseListClient {
-
- @GetMapping("/courses")
- List
courseList(); - }
-
- ===测试,要调用的服务停止,访问接口不会报错
六、使用网关Zuul实现路由功能
- //六、使用网关Zuul实现路由功能(Zuul服务注册,引入依赖,配置路由地址)
- //新建独立子模块Zuul
-
- //引入pom依赖(客户端,网关依赖)
-
-
-
org.springframework.cloud -
spring-cloud-starter-netflix-eureka-client -
-
-
org.springframework.cloud -
spring-cloud-starter-netflix-zuul -
-
-
- //新建启动类(加注解@EnableZuulProxy,@SpringCloudApplication)
- @EnableZuulProxy
- @SpringCloudApplication
- public class ZuulGatewayApplication {
-
- public static void main(String[] args) {
- SpringApplication.run(ZuulGatewayApplication.class, args);
- }
- }
-
- //application.properties加配置
- spring.application.name=course-gateway
- server.port=9000
- logging.pattern.console=%clr(%d{${LOG_DATEFORMAT_PATTERN:HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:%wEx}
- mybatis.configuration.map-underscore-to-camel-case=true
- eureka.client.service-url.defaultZone=http://localhost:8000/eureka/ //服务注册地址
-
- //配置路由地址(可不加使用默认配置,直接ip端口加注册中心子模块服务名+方法名)
- zuul.prefix=/imooc //前缀
- zuul.routes.course-list.path=/list/** //子模块路径别名
- zuul.routes.course-list.service-id=course-list //与path搭配使用,指定子服务名
- zuul.routes.course-price.path=/price/** //同上
- zuul.routes.course-price.service-id=course-price
- //配置完成 使用ip端口加配置前缀+子服务路径别名+方法名
七、使用Zuul网关实现过滤器功能

如下:
- /**
- * 描述: 前置过滤器
- */
- @Component
- public class PreRequestFilter extends ZuulFilter {
-
- @Override
- public String filterType() {
- //请求之前过滤
- return FilterConstants.PRE_TYPE;
- }
-
-
- //排序,该值越小,filter越早执行
- @Override
- public int filterOrder() {
- return 5;
- }
-
- //开关,表示是否需要执行该filter
- @Override
- public boolean shouldFilter() {
- //return true;
- //如:过滤部分请求
- RequestContext ctx = RequestContext.getCurrentContext();
- HttpServletRequest request = ctx.getRequest();
- String requestURI = request.getRequestURI();
- if (requestURI.contains("images") || requestURI.contains("pay")) {
- return false;
- }
- if (requestURI.contains("cart") || requestURI.contains("order")) {
- return true;
- }
- return false;
- }
-
- //filter具体的功能方法
- @Override
- public Object run() throws ZuulException {
- //打印请求链接
- //RequestContext currentContext = RequestContext.getCurrentContext();
- //System.out.println("URI:" + currentContext.getRequest().getRequestURI());
- //return null;
-
- //鉴定用户是否存在
- RequestContext currentContext = RequestContext.getCurrentContext();
- HttpServletRequest request = currentContext.getRequest();
- HttpSession session = request.getSession();
- User currentUser = (User)session.getAttribute(Constant.IMOOC_MALL_USER);
- if (currentUser == null) {
- currentContext.setSendZuulResponse(false);
- currentContext.setResponseBody("{\n"
- + " \"status\": 10007,\n"
- + " \"msg\": \"NEED_LOGIN\",\n"
- + " \"data\": null\n"
- + "}");
- currentContext.setResponseStatusCode(200);
- }
-
- return null;
- }
- }
-
-
-
- /**
- * 描述: 后置过滤器
- */
- @Component
- public class PostRequestFilter extends ZuulFilter {
-
- @Override
- public String filterType() {
- return FilterConstants.POST_TYPE;
- }
-
- @Override
- public int filterOrder() {
- return FilterConstants.SEND_RESPONSE_FILTER_ORDER - 1;
- }
-
- @Override
- public boolean shouldFilter() {
- return true;
- }
-
- @Override
- public Object run() throws ZuulException {
- RequestContext currentContext = RequestContext.getCurrentContext();
- int status = currentContext.getResponse().getStatus();
- System.out.println("response status:" + status);
- return null;
- }
- }
一、多模块Session共享机制(使用Redis)
- 使用redis实现多服务session共享
-
- //修改application.properties配置,增加redis配置
- //各业务模块增加session配置
- spring.session.store-type=redis session方案指定为redis
- spring.redis.host=localhost
- spring.redis.port=6379
- spring.redis.password=
-
- //网关模块增加redis配置
- spring.session.store-type=redis
- spring.redis.host=localhost
- spring.redis.port=6379
- spring.redis.password=
-
- zuul.sensitive-headers= 为空,无需要过滤的headers
- zuul.host.connect-timeout-millis=15000 网关超时时间15s
-
- //启动类增加注解@EnableRedisHttpSession
二、微服务应用开发重难点环节
重难点:模块拆分设计、公共模块、Zuul过滤器、Session处理、Feign调用
常见错误:模块粒度不合适、无公共模块、各接口独立校验、session无法共享、HTTP手动调用
三、微服务子模块通过网关访问文件,需配置地址映射
- /**
- * 描述: 配置地址映射
- */
- @Configuration
- public class ImoocMallWebMvcConfig implements WebMvcConfigurer {
-
- @Override
- public void addResourceHandlers(ResourceHandlerRegistry registry) {
- registry.addResourceHandler("/images/**")
- .addResourceLocations("file:" + ProductConstant.FILE_UPLOAD_DIR);
- registry.addResourceHandler("swagger-ui.html").addResourceLocations(
- "classpath:/META-INF/resources/");
- registry.addResourceHandler("/webjars/**").addResourceLocations(
- "classpath:/META-INF/resources/webjars/");
- }
- }
四、缓存的配置类
- /**
- * 描述: 缓存的配置类
- */
- @Configuration
- @EnableCaching
- public class CachingConfig {
-
- @Bean
- public RedisCacheManager redisCacheManager(RedisConnectionFactory connectionFactory) {
-
- RedisCacheWriter redisCacheWriter = RedisCacheWriter
- .lockingRedisCacheWriter(connectionFactory);
- RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
- cacheConfiguration = cacheConfiguration.entryTtl(Duration.ofSeconds(30));
-
- RedisCacheManager redisCacheManager = new RedisCacheManager(redisCacheWriter,
- cacheConfiguration);
- return redisCacheManager;
- }
- }