SpringCloud之服务发现

2023-10-31

1.服务提供者接口

  • 以获取一个订单接口为例,order服务对user服务进行远程调用获取user基本信息
  • user服务提供的接口如下:
package com.acx.controller;

import com.acx.pojo.vo.ActorInfoVO;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("user")
public class UserController {

    @GetMapping("getUser/{id}")
    public ActorInfoVO getActor(@PathVariable("id") int id) {
        if ((id % 2) == 1) {
            ActorInfoVO actorInfoVO = new ActorInfoVO();
            actorInfoVO.setAge(34);
            actorInfoVO.setGender("男");
            actorInfoVO.setHead("http:localhost:8080/head/");
            actorInfoVO.setNickname("别名:杀马特");
            actorInfoVO.setUsername("张三");
            return actorInfoVO;
        }
        return null;
    }
    
}

2.RestTemplate

2.1.配置RestTemplate实例
package com.acx.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;

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

}
2.2.远程调用业务接口
package com.acx.controller;

import com.acx.pojo.vo.ActorInfoVO;
import com.acx.pojo.vo.OrderInfoVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
@RequestMapping("order")
public class OrderController {

    private static final Logger logger = LoggerFactory.getLogger(OrderController.class);

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("getOne")
    public OrderInfoVO getOne() {
        logger.info("开始查询订单");
        OrderInfoVO orderInfoVO = new OrderInfoVO();
        orderInfoVO.setOrderName("订单123");
        orderInfoVO.setOrderSn("046b399937ad4271bcd5ed275f2b4682");
        orderInfoVO.setProductName("商品123");
        orderInfoVO.setProductNum(23);
        int userId = 1;
        String getUserUrl = "http://127.0.0.1:8083/user/getUser/" + userId;
        //服务发现
        ActorInfoVO actor = restTemplate.getForObject(getUserUrl, ActorInfoVO.class);
        orderInfoVO.setUser(actor);
        return orderInfoVO;
    }
    
}
2.3.前端调用获取订单接口
  • http://localhost:8081/order/getOne
{
	"orderSn": "046b399937ad4271bcd5ed275f2b4682",
	"orderName": "订单123",
	"productNum": 23,
	"productName": "商品123",
	"user": {
		"username": "张三",
		"nickname": "别名:杀马特",
		"head": "http:localhost:8080/head/",
		"age": 34,
		"gender": "男"
	}
}

3.RestTemplate优化

  • 前面我们order服务远程调用user接口时使用的是http://127.0.0.1:8083这种硬编码的方式进行调用的。
  • 硬编码远程调用会存在不灵活的问题,比如user服务部署了多个节点,如user8083、user8084、user8085。如果仍然使用http://127.0.0.1:8083的方式来进行远程调用,则请求就只会命中到user8083这个服务器上面。
  • 解决方案:将http://127.0.0.1:8083替换成http://user-service/ 并且配置远程调用负载均衡策略
3.1.RestTemplate实例加上@LoadBalanced标签配置
@Configuration
public class RestTemplateConfig {

    @Bean
    @LoadBalanced //开启ribbon负载均衡策略
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

}
3.2.更改order服务远程调用接口
package com.acx.controller;

import com.acx.pojo.vo.ActorInfoVO;
import com.acx.pojo.vo.OrderInfoVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
@RequestMapping("order")
public class OrderController {

    private static final Logger logger = LoggerFactory.getLogger(OrderController.class);

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("getOne")
    public OrderInfoVO getOne() {
        logger.info("开始查询订单");
        OrderInfoVO orderInfoVO = new OrderInfoVO();
        orderInfoVO.setOrderName("订单123");
        orderInfoVO.setOrderSn("046b399937ad4271bcd5ed275f2b4682");
        orderInfoVO.setProductName("商品123");
        orderInfoVO.setProductNum(23);
        int userId = 1;
//        String getUserUrl = "http://127.0.0.1:8083/user/getUser/" + userId;
        String getUserUrl = "http://user-service/user/getUser/" + userId;
        //服务发现
        ActorInfoVO actor = restTemplate.getForObject(getUserUrl, ActorInfoVO.class);
        orderInfoVO.setUser(actor);
        return orderInfoVO;
    }

}
3.3.user服务开启多实例测试
  • 使用idea开始多个user服务实例以后,如user8083、user8084、user8085,然后我们多请求几次order接口,发现order接口调用user服务器的请求均匀的路由到了每个节点之上。测试请自己实现。
3.4.微服务调用流程
  • 远程调用发起方会向eureka注册中心拉取当前注册服务列表,然后根据服务名找到目标服务的所有服务节点
  • 找到目标服务所有节点以后,服务发起方会通过ribbon负载均衡策略选择具体调用哪一个目标服务节点。

在这里插入图片描述

4.Ribbon负载均衡

4.1.Ribbon核心类:LoadBalancerInterceptor
  • 最重要的是loadBalancer.execute方法
public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {

	private LoadBalancerClient loadBalancer;

	private LoadBalancerRequestFactory requestFactory;

	public LoadBalancerInterceptor(LoadBalancerClient loadBalancer,
			LoadBalancerRequestFactory requestFactory) {
		this.loadBalancer = loadBalancer;
		this.requestFactory = requestFactory;
	}

	public LoadBalancerInterceptor(LoadBalancerClient loadBalancer) {
		// for backwards compatibility
		this(loadBalancer, new LoadBalancerRequestFactory(loadBalancer));
	}

	@Override
	public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
			final ClientHttpRequestExecution execution) throws IOException {
		final URI originalUri = request.getURI();
		String serviceName = originalUri.getHost();
		Assert.state(serviceName != null,
				"Request URI does not contain a valid hostname: " + originalUri);
		//执行负载均衡核心方法
        return this.loadBalancer.execute(serviceName,
				this.requestFactory.createRequest(request, body, execution));
	}

}
4.2. LoadBalancerClient.execute方法
  • 最核心的方法就是:getServer方法,实际上就是调用的ILoadBalancer.chooseServer方法,而执行这个方法实际上是执行其子类BaseLoadBalancer.chooseServer方法。
public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {
        return this.execute(serviceId, (LoadBalancerRequest)request, (Object)null);
    }

    public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint) throws IOException {
        ILoadBalancer loadBalancer = this.getLoadBalancer(serviceId);
        //根据服务名称获取具体的服务节点对象
        Server server = this.getServer(loadBalancer, hint);
        if (server == null) {
            throw new IllegalStateException("No instances available for " + serviceId);
        } else {
            RibbonLoadBalancerClient.RibbonServer ribbonServer = new RibbonLoadBalancerClient.RibbonServer(serviceId, server, this.isSecure(server, serviceId), this.serverIntrospector(serviceId).getMetadata(server));
            return this.execute(serviceId, (ServiceInstance)ribbonServer, (LoadBalancerRequest)request);
        }
    }

    protected Server getServer(ILoadBalancer loadBalancer, Object hint) {
        return loadBalancer == null ? null : loadBalancer.chooseServer(hint != null ? hint : "default");
    }

4.3.BaseLoadBalancer.chooseServer方法
  • 最重要的方法就是rule.choose(key)方法,即IRule类,这里springboot默认给的是轮询RoundRobinRule。
  • 备注:在更高版本的spring cloud和springboot里面,ribbon默认的负载均衡策略是ZoneAvoidanceRule。即使用Zone对服务器分类,这个Zone可以理解为一个机房/区域,会先选择一个Zone,然后对这个Zone内的服务器进行轮询。
 protected IRule rule = DEFAULT_RULE;
 private final static IRule DEFAULT_RULE = new RoundRobinRule(); //轮询

public Server chooseServer(Object key) { 
        if (counter == null) {
            counter = createCounter();
        }
        counter.increment();
        if (rule == null) {
            return null;
        } else {
            try {
                //通过路由规则选择节点
                return rule.choose(key);
            } catch (Exception e) {
                logger.warn("LoadBalancer [{}]:  Error choosing server for key {}", name, key, e);
                return null;
            }
        }
    }

4.4.IRule类
  • 它有一下几个子类:
ZoneAvoidanceRule: 按区域轮询策略
RoundRobinRule: 轮询
RandomRule: 随机轮询
RetryRule: 重试轮询

4.5.配置负载均衡策略
  • 因为我们现在使用的这个版本的springboot和springcloud的负载均衡策略默认就是轮询的,如果我们想配置其余的负载均衡策略,也可以自定义配置文件就行了
  • 全局配置:即调用者调用服务A、B、C等提供者接口都采用此负载均衡策略
//方式一
@Bean
public IRule retryRule(){
    return new RetryRule();
}

ribbon: # 方式二
  NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RetryRule

  • 局部配置:即调用者服务给单独的服务配置负载均衡的策略,如下只对user-service服务有效:
userservice:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RetryRule

4.6.Ribbon饥饿加载
  • Ribbon默认采用的是懒加载,即第一次访问时才会去创建LoadBalancerClient对象,第一次请求时间会很长
  • 饥饿加载:项目启动时就会创建LoadBalancerClient对象
  • 开启饥饿加载:
ribbon:
	eager-load:
		enable: true # 开启饥饿加载
		clients: 
		    - user-service # 指明主要饥饿加载的服务

5.OpenFeign

5.1.为什么要用OpenFeign替换RestTemplate

OpenFeign是一种声明式的HTTP客户端,而RestTemplate具有代码可读性差、调用参数复杂难维护等缺点。故选择OpenFeign更适合我们的微服务远程调用场景。

5.2.OpenFeign实践

步骤一:Order服务调用方引入OpenFeign的依赖

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

步骤二:在启动类上加上@EnableFeignClients标签开启Feign功能

package com.acx;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableFeignClients
public class OrderApplication {

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

}

步骤三:编写Feign客户端接口代码:使用@FeignClient()指明调用那个服务,接口按照spring mvc写就行。

package com.acx.client;

import com.acx.pojo.vo.ActorInfoVO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient("USER-SERVICE")
public interface UserClient {

    @GetMapping("/user/getUser/{id}")
    ActorInfoVO getUser(@PathVariable("id") int id);

}

最后:在业务代码里面使用Feign接口进行User服务调用

package com.acx.controller;

import com.acx.client.UserClient;
import com.acx.pojo.vo.ActorInfoVO;
import com.acx.pojo.vo.OrderInfoVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
@RequestMapping("order")
public class OrderController {

    private static final Logger logger = LoggerFactory.getLogger(OrderController.class);

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private UserClient userClient;

    @GetMapping("getOne")
    public OrderInfoVO getOne() {
        logger.info("开始查询订单");
        OrderInfoVO orderInfoVO = new OrderInfoVO();
        orderInfoVO.setOrderName("订单123");
        orderInfoVO.setOrderSn("046b399937ad4271bcd5ed275f2b4682");
        orderInfoVO.setProductName("商品123");
        orderInfoVO.setProductNum(23);
        int userId = 1;
//        String getUserUrl = "http://127.0.0.1:8083/user/getUser/" + userId;
//        String getUserUrl = "http://user-service/user/getUser/" + userId;
        //服务发现
//        ActorInfoVO actor = restTemplate.getForObject(getUserUrl, ActorInfoVO.class);
        ActorInfoVO actor = userClient.getUser(userId);
        orderInfoVO.setUser(actor);
        return orderInfoVO;
    }

}

5.3.Feign的自定义配置

主要的可配置项

配置项 说明
Level:日志级别 有4中级别:NONE(不输出远程调用日志) BASIC(只输出请求URL和响应状态码及请求 时间) HEADERS(将BASIC信息和请求头信息输出), FULL(输出完成的请求)
Decoder:响应结果解析器 默认使用SpringDecoder解码器,会调用Spring MVC 中的消息转换器HttpMessageConverter进行解码。
Encoder:请求参数编码器 默认使用SpringEncoder编码器,它会调用Spring MVC 中的消息转换器(HttpMessageConverter)进行编码
Contract:契约配置 OpenFeign中默认使用的是springmvc的注解
Retryer:失败重试机制 默认没有重试机制,可以使用Ribbon配置重置机制

文件方式配置

  • 以设置level等级为例:一般采用basic或者none即可,这样日志少,OpenFeign的性能就越高
  • 配置全局生效:即所有被调用的服务都生效
feign:
  client:
    config:
      default: # 全局
        loggerLevel: FULL

  • 配置局部生效:
feign:
  client:
    config:
      userservice: # 局部生效 userservice
        loggerLevel: FULL

代码方式配置

  • 编写配置代码
package com.acx.config;

import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FeignConfig {

    @Bean
    public Logger.Level feignLevel() {
        return Logger.Level.FULL;
    }

}

  • 配置全局生效:@EnableFeignClients更换默认配置;这样配置是全局生效的,即不管Order服务调用那个服务的接口,日志打印规则都按照FeignConfig配置的打印。
package com.acx;

import com.acx.config.FeignConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableFeignClients(defaultConfiguration = FeignConfig.class)
public class OrderApplication {

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

}

  • 配置局部生效:如下@FeignClient标签里面配置user-service和feign配置类,这样这个日志配置就只对调用user-service接口时生效。
package com.acx.client;

import com.acx.config.FeignConfig;
import com.acx.pojo.vo.ActorInfoVO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(value = "USER-SERVICE",configuration = FeignConfig.class)
public interface UserClient {

    @GetMapping("/user/getUser/{id}")
    ActorInfoVO getUser(@PathVariable("id") int id);

}

5.4.Feign的性能优化

Feign的底层HTTP客户端选型:

URLConnection:feign默认集成的HTTP客户端,JDK自带,不支持连接池,性能不好

Apache HttpClient:支持连接池

OKHttp:支持连接池

Feign性能优化

  • 思路:使用支持连接池的客户端替换URLConnection

  • Order服务引入依赖:这个jar包包括了Apache HttpClient和OKHttp两大客户端,选择一种即可

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

  • 编写Apache HttpClient配置
feign:
  httpclient:
    enabled: true # 开启feign对Apache HttpClient的支持
    max-connections: 200 # 最大的连接数
    max-connections-per-route: 50 # 每个路径的最大连接数

  • 编写OKHttp配置
feign:
  okhttp:
    enabled: true # 开启feign对Apache HttpClient的支持

5.5.Feign的最佳实践

方式一(耦合):服务提供者定义一个API接口,写一个Feign接口和Controller接口都集成此API接口,然后服务消费者引入服务提供者的依赖来调用Feign客户端。

缺点:服务提供方和服务消费方紧耦合了。参数列表中的注解映射并不会被集成,所以我们再Controller接口里面还要再次声明方法、参数列表、注解。故此方式不推荐使用。

方式二(抽取):将 FeignClient 抽取为独立模块,并且把接口有关的 POJO、默认的 Feign 配置都放到这个模块中,提供给所有消费者使用。

在这里插入图片描述

步骤一:新建feign-api包,并将前面的UserClient转移到这个包中,pom.xml配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cloud-demo</artifactId>
        <groupId>com.acx</groupId>
        <version>1.0.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.acx</groupId>
    <artifactId>feign-api</artifactId>
    <version>1.0.0</version>

    <dependencies>
        <dependency>
            <groupId>com.acx</groupId>
            <artifactId>cloud-common</artifactId>
            <version>1.0.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-httpclient</artifactId>
        </dependency>
    </dependencies>

</project>

步骤二:Order项目引入feign-api包进行微服务调用

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cloud-demo</artifactId>
        <groupId>com.acx</groupId>
        <version>1.0.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.acx</groupId>
    <artifactId>order-service</artifactId>
    <version>1.0.0</version>
    <packaging>jar</packaging>

    <dependencies>
        <dependency>
            <groupId>com.acx</groupId>
            <artifactId>cloud-common</artifactId>
            <version>1.0.0</version>
        </dependency>
        <dependency>
            <groupId>com.acx</groupId>
            <artifactId>feign-api</artifactId>
            <version>1.0.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>
</project>

5.6.FeignClient接口扫描报错
  • 当我们写的FeignClient接口不在SpringBootApplication的扫描包范围内时,一般有两种解决方案:
  • 方案1(全局生效):在@EnableFeignClients指明basePackages为FeignClient接口所在的包,这样就能够扫描到了。此种方式全局生效的,即不管是调用哪个微服务都按照这个配置进行FeignClient接口扫描。
package com.acx;

import com.acx.config.FeignConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableFeignClients(defaultConfiguration = FeignConfig.class,basePackages = "com.acx.client")
public class OrderApplication {

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

}

  • 方案2(局部生效): 在@EnableFeignClients指明具体的FeignClient字节码(clients)。这样就能扫描到UserClient接口了,但是这个不是全局的,只对UserClient包扫描不到生效。
package com.acx;

import com.acx.client.UserClient;
import com.acx.config.FeignConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableFeignClients(defaultConfiguration = FeignConfig.class,clients = {UserClient.class})
public class OrderApplication {

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

}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SpringCloud之服务发现 的相关文章

随机推荐

  • ARTS挑战打卡第十六周

    Algorithm 一周至少一道算法题 Review 阅读并点评至少一篇英文技术文章 Tip 学习至少一个技术技巧 总结和归纳在日常工作中所遇到的知识点 Share 分享一篇有观点和思考的技术文章 01 Algorthm https lee
  • 用java写个管理系统

    如果要用 Java 写一个管理系统 可以这样做 首先 确定管理系统的功能 然后设计系统的数据结构和架构 这可以通过绘制 UML 类图或流程图来完成 安装 Java 开发工具包 JDK 和集成开发环境 IDE 比如 Eclipse 或 Int
  • python报错:RuntimeError

    python报错 RuntimeError fails to pass a sanity check due to a bug in the windows runtime这种类型的错误 这种错误原因 1 当前的python与numpy版本
  • Gradle项目运行报错Could not find method XXX及解决方案

    Could not find method testCompile for arguments dependencies testCompile group junit name junit version 4 13 1 原因是较新版的gr
  • 计算机截屏窗口快捷键,电脑截屏的快捷键是什么

    电脑截屏的快捷键是什么 截屏是一种截取图片或文字的途径 也是一种计算机运用技术 通过这种技术可以从网上截取下自己感兴趣的文章图片供自己使用观看 可以帮助人们更好的去理解使用知识 是一种人人都能使用并且学会方法 可以通过一些软件实现截屏功能
  • XSS-Game level 7

    第七关过滤了 script 但未过滤尖括号 lt gt 使用双写绕过 源码中过滤了大小写 script 以及一些属性 并将参数拼接到 value 值 使用 htmlspecialchars 过滤标签 但未重新赋值给 str 所以不会产生影响
  • Google Play Services Location:显示位置的地址

    在前面的blog中讲述了怎样获取最后已知位置和接收位置更新后如何从location对象中获取用户的位置 包含经纬度的坐标 虽然纬度和经度是用于计算距离或显示地图的位置 在许多情况下 位置的地址是更为有用的 例如 如果你想让你的用户知道他们是
  • Wireshark零基础使用教程(超详细)

    Wireshark零基础使用教程 一 Wireshark是什么 二 Wireshark抓包原理 三 Wireshark安装入门 1 选择网卡 2 停止抓包 3 保存数据 四 界面介绍 五 基础操作 1 调整界面大小 2 设置显示列 1 添加
  • 一个仿 github for windows 及 windows 8 的进度条

    https github com wly2014 ProgressBar 转载于 https www cnblogs com eustoma p 4470396 html
  • dubbo_异常Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException

    Exception in thread main org springframework beans factory UnsatisfiedDependencyException Error creating bean with name
  • BES2300x笔记(27) -- 声道设定与声道切换

    哈喽大家好 这是该系列博文的第二十七篇 篇 lt lt 系列博文索引 快速通道 gt gt 一 前言 前几天 有道友私信问到 BES2300如何进行声道设定 想通过硬件进行固定 那么 这一篇我们就讲讲BES平台有关声道的设定 以及如何进行硬
  • 计算机程序设计语言教案,计算机程序设计(C语言)课程教案讲稿概要.doc

    计算机程序设计 C 语言 课程教案 讲稿 教师姓名 纪澍琴 学院 部 中心 信息传播工程学院 教研室 实验室计算机基础教研室 2008年3月 长春工业大学课程教案 讲稿 与课程有关的信息 教师编号 000361 课程名称 计算机程序设计 C
  • android listview 图片闪烁,listView异步加载图片导致图片错位、闪烁、重复的问题的解决...

    androidListView是android中重要的控件 几乎每一个项目都会用到 但是在使用中我们避免不 了会出现一些问题 包括一些滑动事件的处理 例如 ListView中嵌套scrollView 容易出现listView 展现数据不全的
  • adb关闭手机系统自动更新

    下载adb工具 https mclub lenovo com cn forum php mod attachment aid NDg5ODc1Nnw4MWRhZDE4OHwxNjU0NTI0OTY1fDB8NzgzNzg5OQ 3D 3D
  • Android jni ndk crash c++bug定位

    最近遇到了一个底层c 库的问题 然而看不到是在哪里报错的 有一个方法就是用 ndk stack的方法 在cmd里面切换到adb 在电脑上的目录 然后输入adb logcat ndk stack sym F whl MyApp 替换为你的项目
  • 【C++】递归

    1 什么是递归 程序调用自身的编程技巧称为递归 递归做为一种算法在程序设计语言中广泛应用 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法 它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解 递归策略只需
  • 前端学习之原生JS实现addClass及removeClass方法的封装

    addclass方法封装 HTML代码 div class two div div class two three div JS代码 var o1 document querySelector b1 var o2 document quer
  • python 选择结构

    选择 用于判断 注意符号 单分支 If 条件 条件成立就执行if缩进的代码 双分支 If 条件 条件成立就执行if缩进的代码 Else 条件 条件不成立就执行else缩进的代码
  • 调整计算机硬盘大小,详细教您怎么调整硬盘分区

    新买的电脑很多磁盘只有一两个 很多时候需要对资料分区管理 甚至有些磁盘容量的分配不是很合理的 这时候怎么解决呢 就要我们对硬盘重新分区大小了 下面由小编给你带来硬盘分区的详细操作步骤 新买的笔记本 有时候会发现整个硬盘只有一个分区 如果将所
  • SpringCloud之服务发现

    1 服务提供者接口 以获取一个订单接口为例 order服务对user服务进行远程调用获取user基本信息 user服务提供的接口如下 package com acx controller import com acx pojo vo Act