springCloud-复习

Mybatis-plus依赖:1是mybatis-plus-boot-starter本身的依赖,2是mysql-connector-java驱动,3是druid-spring-boot-starter连接池,
4是mybatis-plus-generator生成器。
父项目的<dependencyManagement>只是引入的管理,并不会做任何引入,所以在子项目必须再引入一遍。
!-- 资源引入 ,把src/main/java下的xml文件,打包的时候,打包到src/main/resources下面-->
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
            </resource>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
        </resources>
backend-common不在tomcat里面运行,给别人使用的公共模块。
@RunWith(SpringRunner.class)
@SpringBootTest     //写@Test时候,就可以依赖注入Mapper了。
public class PplicationTests {
    @Test
    public void contextLoads() {
    }
}

//其他类可以继承PplicationTests,也可以依赖注入Mapper了。
public class Test extends PplicationTests {
    @Autowired
    private MoocBackendUserTMapper mapper;

    public void select(){
    }
}
Lombok是插件,@Data是get set方法的注解。@Data注解是在编译时候生成set get方法,但是开发时候是在编译之前,为了可以使用get set方法,就要用到Lombok插件。
@Builder注解,就可以使用User.build().id().name().age().build();   build模式。
@Slf4j注解,就可以直接使用log.info(“......”);
parent工程里面的dependencies,子工程都会有。parent的dependencyManagement子工程不会有,需要再引入一遍,只是管理版本号。

module A和module B之间用dependencie引用,跟正常引用junit包一样,才可以使用它里面的方法。parent里面通过modules引入其他所有module是正常写法,只要是父子工程就必须这么写。

module A通过 dependencie引入module B,
module C只需要 dependencie引入module A,就可以同时dependencie module A和module B。
module C,module B,module A都有parent的包,不会冲突,会依据最短路径,只引入一个包。
@MapperScan(basePackages = {"com.mooc.meetingfilm.film.dao"}), MapperScan最好每个模块都加一个。
eureka server: 
<dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

server:
    port: 8761
eureka:
    instance:
        hostname: localhost
        prefer-ip-address: true
    client:
        register-with-eureka: false
        fetch-registry: false
    service-url:
        defaultZone: http://localhost:8761/

@EnableEurekaServer
@SpringBootApplication
public class BackendEurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(BackendEurekaServerApplication.class, args);
    }
}    就可以了。
Eureka Client:生产者和消费者都要配置 

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

server:
    port: 8201
eureka:
    client:
        service-url:
            defaultZone: http://localhost:8761/eureka/
spring:
    application:
        name: hello-service-consumer

@EnableFeignClients
@EnableDiscoveryClient  // DiscoverClient可以集成大部分注册中心
// @EnableEurekaClient  只对Eureka使用
@SpringBootApplication
public class BackendShowConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(BackendShowConsumerApplication.class, args);
    }
}
消费端远程调用:
@Service
public class ConsumerServiceImpl implements ConsumerServiceAPI{
    @Autowired
    private RestTemplate restTemplate;  //依赖注入

    @Override
    public String sayHello(String message) {  
        String result = restTemplate.getForObject
        ("http://hello-service-provider/provider/sayhello?message=111", String.class);
        return result;
    }
}
消费端远程调用:
@Service
public class ConsumerServiceImpl implements ConsumerServiceAPI{
    @Autowired
    private RestTemplate restTemplate;  //依赖注入

    @Override
    public String sayHello(String message) {  
        String result = restTemplate.getForObject
        ("http://hello-service-provider/provider/sayhello?message=111", String.class);
        return result;
    }
}
@Configuration
public class RestConfig {
    @Bean //注册成bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();   //被依赖注入
    } 
}
Eureka心跳是30s,90s没有收到心跳就剔除。Eureka退出时会发生cancel命令给server。Kill-9是不会发生cancel的。

Eureka client会缓存注册信息,30s定期更新,

Ribbon:客户端的负债均衡,需要有serverList

@GetMapping("/movie/{id}")
  public User findById(@PathVariable Long id) {
    // http://localhost:7900/simple/,microservice-provider-user是注册到eureka之后的一个虚拟主机名(页面有,microservice-provider-user工程的虚拟主机名)。
     //microservice-provider-user工程的配置文件中spring.application.name中定义。
    // VIP virtual IP。不再是通过服务提供者的ip和端口访问了。
    // HAProxy Heartbeat
    //spring:application:name:microservice-provider-user
    return this.restTemplate.getForObject("http://microservice-provider-user/simple/" + id, User.class);
  }

  @GetMapping("/test")
  public String test() {
      //如果microservice-provider-user微服务有多个,可以看出命中的是哪个ip端口
    ServiceInstance serviceInstance = this.loadBalancerClient.choose("microservice-provider-user");
    System.out.println("111" + ":" + serviceInstance.getServiceId() + ":" + serviceInstance.getHost() + ":" + serviceInstance.getPort());

    ServiceInstance serviceInstance2 = this.loadBalancerClient.choose("microservice-provider-user2");
    System.out.println("222" + ":" + serviceInstance2.getServiceId() + ":" + serviceInstance2.getHost() + ":" + serviceInstance2.getPort());

    return "1";
  }
@SpringBootApplication
@EnableEurekaClient
public class ConsumerMovieRibbonApplication {

  @Bean
  @LoadBalanced//就一个注解。@LoadBalanced整合了ribbon,让RestTemplate具备负载均衡的能力
  public RestTemplate restTemplate() {
    return new RestTemplate();
  }

@Bean
  public IRule ribbonRule() {
    return new RandomRule(); //随机选取一个微服务,也可以自己定义路由规则。  }
}

  public static void main(String[] args) {
    SpringApplication.run(ConsumerMovieRibbonApplication.class, args);
  }
}

Iping: NIWSDiscoverPingPingURLDummyPingNoOpPing

Hystrix : 熔断,提高系统可用性,避免级联故障。

两种命令模式:HystrixCommandHystrixObservableCommand

GroupKeyCommandKey。请求缓存。

目前使用eureka server完成了服务注册和服务发现,ribbon完成了客户端负载均衡。如果服务提供者的响应很慢那么服务消费者会强制等待,一直等到http请求超时,如果服务消费者还是其他的服务提供者,那么就会产生级联的雪崩。

超时机制:等待几秒还是没响应,就直接返回了。

断路器模式:A如果有大量的超时,B一直去请求A是没有意义的,不再去请求A直接返回异常。保证B不会拖死

@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker  //启用断路器
public class ConsumerMovieRibbonApplication {

  @Bean
  @LoadBalanced  //ribbon的客户端负载均衡
  public RestTemplate restTemplate() {
    return new RestTemplate();
  }

  public static void main(String[] args) {
    SpringApplication.run(ConsumerMovieRibbonApplication.class, args);
  }
}
@RestController
public class MovieController {
  @Autowired
  private RestTemplate restTemplate;

  //http://localhost:8010/movie/1
  //查看hystrix的状态http://localhost:8010/hystrix.stream
  //第一次会进fallbackMethod方法,后面走microservice-provider-user。因为Hystrix默认超时时间是1秒。
  //microservice-provider-user挂了就进fallbackMethod
  @GetMapping("/movie/{id}")
  @HystrixCommand(fallbackMethod = "findByIdFallback")  //参数和返回值类型一样,当用户微服务挂了就走fallbackMethod。进入了fallbackMethod不代表断路器打开。
  public User findById(@PathVariable Long id) {
    return this.restTemplate.getForObject("http://microservice-provider-user/simple/" + id, User.class);
  }

  public User findByIdFallback(Long id) {
    User user = new User();
    user.setId(0L);
    return user;
  }
}

Feign:是一个HTTP客户端。简化了HTTP调用方式。Feign整合了RibbonHystrixFeign只有接口。

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients  //Feign的客户端
public class ConsumerMovieFeignApplication {
  public static void main(String[] args) {
    SpringApplication.run(ConsumerMovieFeignApplication.class, args);
  }
}
@RestController
public class MovieController {
  @Autowired
  private UserFeignClient userFeignClient;
/*  原来是通过restTemplate来调用
  @GetMapping("/movie/{id}")
  public User findById(@PathVariable Long id) {
        return this.restTemplate.getForObject(this.userServicePath + id, User.class);
  }*/
  
  @GetMapping("/movie/{id}")
  public User findById(@PathVariable Long id) {
    return this.userFeignClient.findById(id);
  }

  @GetMapping("/test")
  public User testPost(User user) {
    return this.userFeignClient.postUser(user);
  }
}
//Configuration2作为他的配置文件
@FeignClient(name = "xxxx", url = "http://localhost:8761/", configuration = Configuration2.class)
public interface FeignClient2 {
  @RequestMapping(value = "/eureka/apps/{serviceName}")
  public String findServiceInfoFromEurekaByServiceName(@PathVariable("serviceName") String serviceName);
}
@Configuration
public class Configuration2 {
  @Bean
  public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
    return new BasicAuthRequestInterceptor("user", "password123");
  }
}

Feign整合Hystrix

@RestController
public class MovieController {
  @Autowired
  private UserFeignClient userFeignClient;

  @GetMapping("/movie/{id}")
  public User findById(@PathVariable Long id) {
    return this.userFeignClient.findById(id);
  }
}
@FeignClient(name = "microservice-provider-user", fallback = HystrixClientFallback.class)
public interface UserFeignClient {
  @RequestMapping(value = "/simple/{id}", method = RequestMethod.GET)
  public User findById(@PathVariable("id") Long id);
}
@Component
public class HystrixClientFallback implements UserFeignClient {
  @Override
  public User findById(Long id) {
    User user = new User();
    user.setId(0L);
    return user;
  }
}

feign整合hystrix_factory

@RestController
public class MovieController {
  @Autowired
  private UserFeignClient userFeignClient;

  @GetMapping("/movie/{id}")
  public User findById(@PathVariable Long id) {
    return this.userFeignClient.findById(id);
  }
}
@FeignClient(name = "microservice-provider-user", /*fallback = HystrixClientFallback.class, */fallbackFactory = HystrixClientFactory.class)
public interface UserFeignClient {//请求microservice-provider-user的/simple/{id}方法。失败回调调用的是HystrixClientFactory的findById方法
  @RequestMapping(value = "/simple/{id}", method = RequestMethod.GET)
  public User findById(@PathVariable("id") Long id);
}
@Component
public class HystrixClientFactory implements FallbackFactory<UserFeignClient> {
  @Override
  public UserFeignClient create(Throwable cause) {
    HystrixClientFactory.LOGGER.info("fallback; reason was: {}", cause.getMessage());
    return new UserFeignClientWithFactory() {
      @Override
      public User findById(Long id) {
        User user = new User();
        user.setId(-1L);
        return user;
      }
    };
  }
}

Feign默认使用的是JDKHTTP方式,所以最好优化HTTP的方式,Apache HTTPClient是个不错的选择。OKHTTP也是可以的。

<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-httpclient</artifactId>
</dependency>

Feign的解压缩,可以优化网络带宽。

feign:
  hystrix:
    enabled: true
  httpclient:
    enabled: true
  compression:
    request:
      enabled: true
      mime-types: text/xml,application/xml,application/json
      min-request-size: 2048
    response:
      enabled: true

Zuul:网关,客户端只需要知道网关的ip和端口就可以了,网关知道后面微服务的ip和端口Ribbon是客户端的负载均衡器,Zuul是服务端的负载均衡器。

使用http://192.168.88.1:7901/simple/1直接访问user微服务(7901user的微服务地址),

http://192.168.88.1:8040/microservice-provider-user/simple/18040zuul的端口,microservice-provider-useruser微服务的application:name)。通过zuul就可以访问user服务了。

经过zuul的请求都会通过hysitrcs包裹,所以zuul会有断路器功能。zuul还使用了ribbon做负载均衡。

Zuul过滤器:Zuul4中过滤器,PREROUTINGPOSTERRORPre先执行然后routing,然后post然后error.

prezuul请求别的微服务之前鉴权routing是请求过程中的数据增强post是请求到微服务之后可以添加一些headererror是抛异常了。也可以自定义过滤器。

@SpringBootApplication
@EnableZuulProxy     //使用这一个注解就可以注册到eureka,zuul要从eruka拉取注册的服务信息,
public class ZuulApplication {
  public static void main(String[] args) {
    SpringApplication.run(ZuulApplication.class, args);
  }
}
spring:
  application:
    name: microservice-gateway-zuul
server:
  port: 8040
eureka:
  client:
    service-url:
      defaultZone: http://user:password123@localhost:8761/eureka  
instance:
    prefer-ip-address: true
zuul:
  routes:
    abc:                            # abc随意,只要唯一就可以
      path: /user-path/**               # 使用user-path访问user微服务
      serviceId: microservice-provider-user        # 注册到eureka的服务的application名字
    
# http://localhost:8040/routes : 查看zuul代理的微服务
# {"/user-path/**":"microservice-provider-user","/microservice-provider-user/**":"microservice-provider-user"}
# 就可以使用zuul来代理user微服务:http://localhost:8040/microservice-provider-user/simple/1
# zuul的请求都用hystrix包裹:http://localhost:8040/hystrix.stream

Zuul拦截器:

@Slf4j
public class MyFilter extends ZuulFilter {
    @Override
    public String filterType() {//Filter类型
        return "pre";
    }

    @Override
    public int filterOrder() {//filter的执行顺序
        return 0;
    }

    @Override
    public boolean shouldFilter() {//是否要拦截
        return true;
    }

    @Override
    public Object run() throws ZuulException {// Filter的具体业务逻辑
        RequestContext requestContext = RequestContext.getCurrentContext();// ThreadLocal
        HttpServletRequest request = requestContext.getRequest();
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()){
            String headName = headerNames.nextElement();
            log.info("headName:{}, headValue:{}", headName, request.getHeader(headName));
        }
        return null;
    }
}
@Configuration
public class ZuulConfig {
    @Bean
    public MyFilter initMyFilter(){
        return new MyFilter();
    }

    @Bean
    public JWTFilter initJWTFilter(){
        return new JWTFilter();
    }
}

Zuul的Hystics的降级处理:超时降级

//Zuul的Hystics的降级处理:超时降级
@Component
public class MyFallback implements FallbackProvider {
    //针对哪一个路由进行降级, return可以写 *
    @Override
    public String getRoute() {
        return "film-service";
    }

    //降级时处理方式
    public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
        return new ClientHttpResponse() {
            @Override
            public HttpStatus getStatusCode() throws IOException {
                return HttpStatus.OK;
            }

            @Override
            public int getRawStatusCode() throws IOException {
                return 200;
            }

            @Override
            public String getStatusText() throws IOException {
                return "OK";
            }

            @Override
            public void close() {
            }

            //业务降级处理方式
            @Override
            public InputStream getBody() throws IOException {
                BaseResponseVO responseVO = BaseResponseVO.serviceException(
                        new CommonServiceException(404, "No Films!~"));
                String result = JSONObject.toJSONString(responseVO);
                return new ByteArrayInputStream(result.getBytes());
            }

            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.APPLICATION_JSON);
                return headers;
            }
        };
    }
}

https://gitee.com/yw672530440/maven-spring-cloudm.git

Mybatis-plus依赖:1mybatis-plus-boot-starter本身的依赖,2mysql-connector-java驱动,3druid-spring-boot-starter连接池,4mybatis-plus-generator生成器。

posted @ 2023-03-21 10:58  无天666  阅读(33)  评论(0编辑  收藏  举报