SpringCloud搭建应用

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

项目搭建流程:

1、新建多模块项目,开发

2、服务注册与发现Eureka,注册服务方便引用

3、利用Fegin实现服务间调用

4、服务调用正常,考虑服务的负载均衡,使用Ribbon

5、服务宕机,容灾,避免大面积服务瘫痪,使用熔断器Hystrix

6、整体系统发布统一ip端口,使用网关Zuul,也可对请求进行过滤器的编写

其他:

1、Session共享机制

2、微服务应用开发重难点环节

3、微服务子模块通过网关访问文件,需配置地址映射

4、缓存的配置类

一、Eureka服务端搭建(注册中心)

一、Eureka服务端搭建(引依赖、加配置、使用注解)
// 新建子模块pom引入依赖
  <dependencies>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
  </dependencies>

//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依赖
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>

//application.properties配置文件修改
//增加服务端注册中心地址
eureka.client.service-url.defaultZone=http://localhost:8000/eureka/

=====先启动server,再启动子模块客户端服务,查看服务端网页注册情况,注册成功

三、利用Fegin实现服务间调用(子模块业务间调用,不经过网关,需要携带网关的Session信息,只用RequestInterceptor请求拦截器)

三、利用Fegin实现服务间调用(pom引入依赖、加配置、引注解)

//引入pom
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>

//启动类加注解@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<Course> 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<String> headerNames = request.getHeaderNames();
        if (headerNames != null) {
            while (headerNames.hasMoreElements()) {
                String name = headerNames.nextElement();
                Enumeration<String> 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依赖
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>

//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<Course> courseList() {
        return Collections.emptyList();
    }
}

//之前的Feign客户端进行断路器配置,增加fallback指定发生错误要调用的类
@FeignClient(value = "course-list", fallback = CourseListClientHystrix.class)
@Primary
public interface CourseListClient {

    @GetMapping("/courses")
    List<Course> courseList();
}

===测试,要调用的服务停止,访问接口不会报错

六、使用网关Zuul实现路由功能

//六、使用网关Zuul实现路由功能(Zuul服务注册,引入依赖,配置路由地址)
//新建独立子模块Zuul

//引入pom依赖(客户端,网关依赖)
  <dependencies>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
    </dependency>
  </dependencies>

//新建启动类(加注解@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;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值