带有Spring Boot和Spring Cloud的Java微服务

朋友不允许朋友写用户身份验证。 厌倦了管理自己的用户? 立即尝试Okta的API和Java SDK。 在几分钟之内即可对任何应用程序中的用户进行身份验证,管理和保护。

Java是开发微服务架构时使用的一种很棒的语言。 实际上,我们行业中的一些知名人士都在使用它。 您是否听说过Netflix,Amazon或Google? 那eBay,Twitter和LinkedIn呢? 是的,处理不可思议流量的主要公司正在使用Java来实现。

在Java中实现微服务架构并不适合每个人。 因此,通常不需要实现微服务。 大多数公司这样做都是为了扩展人员,而不是系统。 如果要扩大人员规模,雇用Java开发人员是做到这一点的最佳方法之一。 毕竟,比起其他大多数语言,流利的Java开发人员更多-尽管JavaScript似乎正在Swift赶上来!

Java生态系统具有一些完善的模式来开发微服务架构。 如果您熟悉Spring,则可以在家中使用Spring Boot和Spring Cloud进行开发。 由于这是上手最快的方法之一,所以我认为我将带您快速入门。

使用Spring Cloud和Spring Boot创建Java微服务

在我的大多数教程中,我向您展示了如何从头开始构建所有内容。 今天,我想采用一种不同的方法,并与您一起完成一个预先构建的示例。 希望这会更短并且更容易理解。

您可以从克隆@ oktadeveloper / java-microservices-examples存储库开始。

git clone https://github.com/oktadeveloper/java-microservices-examples.git
cd java-microservices-examples/spring-boot+cloud

spring-boot+cloud目录中,有三个项目:

  • Discovery-service :Netflix Eureka服务器,用于服务发现。
  • car-service :一个简单的Car Service,使用Spring Data REST来提供汽车的REST API。
  • api-gateway :具有/cool-cars端点的API网关,该端点与car-service进行对话并过滤出不凉爽的汽车(当然,在我看来)。

我使用start.spring.io的 REST API和HTTPie创建了所有这些应用程序。

http https://start.spring.io/starter.zip javaVersion==11 \artifactId==discovery-service name==eureka-service \dependencies==cloud-eureka-server baseDir==discovery-service | tar -xzvf -http https://start.spring.io/starter.zip \artifactId==car-service name==car-service baseDir==car-service \dependencies==actuator,cloud-eureka,data-jpa,h2,data-rest,web,devtools,lombok | tar -xzvf -http https://start.spring.io/starter.zip \artifactId==api-gateway name==api-gateway baseDir==api-gateway \dependencies==cloud-eureka,cloud-feign,data-rest,web,cloud-hystrix,lombok | tar -xzvf -

带有Java 11+的Spring Microservices

为了使discovery-service在Java 11上运行,我必须添加对JAXB的依赖

<dependency><groupId>org.glassfish.jaxb</groupId><artifactId>jaxb-runtime</artifactId>
</dependency>

其他两个应用程序可以在Java 11上开箱即用地正常运行,而无需更改依赖项。

Netflix Eureka的Java服务发现

discovery-service的配置与大多数Eureka服务器相同。 它在其主类和设置其端口并关闭发现的属性上作为@EnableEurekaServer批注。

server.port=8761
eureka.client.register-with-eureka=false

car-serviceapi-gateway项目以类似的方式配置。 两者都定义了唯一的名称,并且car-service配置为在端口8090上运行,因此它与8080不冲突。
汽车服务/src/main/resources/application.properties

server.port=8090
spring.application.name=car-service

api-gateway / src / main / resources / application.properties

spring.application.name=api-gateway

两个项目中的主类都使用@EnableDiscoveryClient注释。

使用Spring Data REST构建Java微服务

car-service提供了REST API,可让您CRUD(创建,读取,更新和删除)汽车。 当应用程序使用ApplicationRunner bean加载时,它将创建一组默认的汽车。
car-service / src / main / java / com / example / carservice / CarServiceApplication.java

package com.example.carservice;import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.Bean;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import java.util.stream.Stream;@EnableDiscoveryClient
@SpringBootApplication
public class CarServiceApplication {public static void main(String[] args) {SpringApplication.run(CarServiceApplication.class, args);}@BeanApplicationRunner init(CarRepository repository) {return args -> {Stream.of("Ferrari", "Jaguar", "Porsche", "Lamborghini", "Bugatti","AMC Gremlin", "Triumph Stag", "Ford Pinto", "Yugo GV").forEach(name -> {repository.save(new Car(name));});repository.findAll().forEach(System.out::println);};}
}@Data
@NoArgsConstructor
@Entity
class Car {public Car(String name) {this.name = name;}@Id@GeneratedValueprivate Long id;@NonNullprivate String name;
}@RepositoryRestResource
interface CarRepository extends JpaRepository<Car, Long> {
}

API网关中的Spring Cloud + Feign和Hystrix

Feign使编写Java HTTP客户端更加容易。 Spring Cloud使得仅需几行代码即可创建Feign客户端。 Hystrix可以为您的Feign客户端添加故障转移功能,从而使它们更具弹性。

api-gateway使用Feign和Hystrix与下游car-service并在不可用时故障转移到fallback()方法。 它还公开了一个/cool-cars终结点,该终结点过滤掉了您可能不想拥有的汽车。
api-gateway / src / main / java / com / example / apigateway / ApiGatewayApplication.java

package com.example.apigateway;import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import lombok.Data;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.hateoas.Resources;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.ArrayList;
import java.util.Collection;
import java.util.stream.Collectors;@EnableFeignClients
@EnableCircuitBreaker
@EnableDiscoveryClient
@EnableZuulProxy
@SpringBootApplication
public class ApiGatewayApplication {public static void main(String[] args) {SpringApplication.run(ApiGatewayApplication.class, args);}
}@Data
class Car {private String name;
}@FeignClient("car-service")
interface CarClient {@GetMapping("/cars")@CrossOriginResources<Car> readCars();
}@RestController
class CoolCarController {private final CarClient carClient;public CoolCarController(CarClient carClient) {this.carClient = carClient;}private Collection<Car> fallback() {return new ArrayList<>();}@GetMapping("/cool-cars")@CrossOrigin@HystrixCommand(fallbackMethod = "fallback")public Collection<Car> goodCars() {return carClient.readCars().getContent().stream().filter(this::isCool).collect(Collectors.toList());}private boolean isCool(Car car) {return !car.getName().equals("AMC Gremlin") &&!car.getName().equals("Triumph Stag") &&!car.getName().equals("Ford Pinto") &&!car.getName().equals("Yugo GV");}
}

运行Java微服务架构

如果您在单独的终端窗口中使用./mvnw运行所有这些服务, ./mvnw可以导航至http://localhost:8761并查看它们是否已在Eureka中注册。

Java微服务

如果您在浏览器中导航到http://localhost:8080/cool-bars ,您将被重定向到Okta。 什么啊

使用OAuth 2.0和OIDC保护Java微服务

我已经使用OAuth 2.0和OIDC在此微服务架构中配置了安全性。 两者有什么区别? OIDC是提供身份的OAuth 2.0的扩展。 它还提供发现功能,因此可以从单个URL(称为issuer )发现所有不同的OAuth 2.0端点。

如何为所有这些微服务配置安全性? 我很高兴你问!

我在api-gatewaycar-servicepom.xml中添加了Okta的Spring Boot启动器:

<dependency><groupId>com.okta.spring</groupId><artifactId>okta-spring-boot-starter</artifactId><version>1.2.0</version>
</dependency>

然后,我在Okta创建了一个新的OIDC应用,并配置了授权代码流。 如果要查看运行中的所有内容,则需要完成以下步骤。

在Okta中创建Web应用程序

登录到您的1563开发者帐户(或者注册 ,如果你没有一个帐户)。

  1. 在“ 应用程序”页面上,选择添加应用程序
  2. 在“创建新应用程序”页面上,选择“ Web”
  3. 为您的应用提供一个令人难忘的名称,将http://localhost:8080/login/oauth2/code/okta为登录重定向URI,选择刷新令牌 (除了授权代码 ),然后点击完成

将发行者(位于API > 授权服务器下 ),客户端ID和客户端密钥复制到两个项目的application.properties中。

okta.oauth2.issuer=$issuer
okta.oauth2.client-id=$clientId
okta.oauth2.client-secret=$clientSecret

下一节中的Java代码已经存在,但是我认为我已经对其进行了解释,以便您了解正在发生的事情。

为OAuth 2.0登录和资源服务器配置Spring Security

ApiGatewayApplication.java ,我添加了Spring Security配置以启用OAuth 2.0登录并将网关作为资源服务器。

@Configuration
static class OktaOAuth2WebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {// @formatter:offhttp.authorizeRequests().anyRequest().authenticated().and().oauth2Login().and().oauth2ResourceServer().jwt();// @formatter:on}
}

在此示例中未使用资源服务器配置,但是我添加了它,以防您想将移动应用程序或SPA连接到此网关。 如果您使用的是SPA,则还需要添加一个bean来配置CORS。

@Bean
public FilterRegistrationBean<CorsFilter> simpleCorsFilter() {UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();CorsConfiguration config = new CorsConfiguration();config.setAllowCredentials(true);config.setAllowedOrigins(Collections.singletonList("*"));config.setAllowedMethods(Collections.singletonList("*"));config.setAllowedHeaders(Collections.singletonList("*"));source.registerCorsConfiguration("/**", config);FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<>(new CorsFilter(source));bean.setOrder(Ordered.HIGHEST_PRECEDENCE);return bean;
}

如果确实使用像这样的CORS过滤器,建议您将源,方法和标头更改为更具体,以提高安全性。

CarServiceApplication.java仅配置为资源服务器,因为不希望直接访问它。

@Configuration
static class OktaOAuth2WebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {// @formatter:offhttp.authorizeRequests().anyRequest().authenticated().and().oauth2ResourceServer().jwt();// @formatter:on}
}

为了使API网关能够访问Car Service,我在API网关项目中创建了UserFeignClientInterceptor.java
> api-gateway / src / main / java / com / example / apigateway / UserFeignClientInterceptor.java

package com.example.apigateway;import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.stereotype.Component;@Component
public class UserFeignClientInterceptor implements RequestInterceptor {private static final String AUTHORIZATION_HEADER = "Authorization";private static final String BEARER_TOKEN_TYPE = "Bearer";private final OAuth2AuthorizedClientService clientService;public UserFeignClientInterceptor(OAuth2AuthorizedClientService clientService) {this.clientService = clientService;}@Overridepublic void apply(RequestTemplate template) {Authentication authentication = SecurityContextHolder.getContext().getAuthentication();OAuth2AuthenticationToken oauthToken = (OAuth2AuthenticationToken) authentication;OAuth2AuthorizedClient client = clientService.loadAuthorizedClient(oauthToken.getAuthorizedClientRegistrationId(),oauthToken.getName());OAuth2AccessToken accessToken = client.getAccessToken();template.header(AUTHORIZATION_HEADER, String.format("%s %s", BEARER_TOKEN_TYPE, accessToken.getTokenValue()));}
}

我在ApiGatewayApplication.java其配置为RequestInterceptor

@Bean
public RequestInterceptor getUserFeignClientInterceptor(OAuth2AuthorizedClientService clientService) {return new UserFeignClientInterceptor(clientService);
}

并且,我在api-gateway/src/main/resources/application.properties添加了两个属性,因此Feign支持Spring Security。

feign.hystrix.enabled=true
hystrix.shareSecurityContext=true

请参阅在启用安全性的情况下运行的Java微服务

使用./mvnw在单独的终端窗口中运行所有应用程序,或者根据需要在您的IDE中运行。

为了简化在IDE中的运行,根目录中有一个聚合器pom.xml 。 如果安装了IntelliJ IDEA的命令行启动器 , idea pom.xml需要运行idea pom.xml

导航到http://localhost:8080/cool-cars ,您将被重定向到Okta进行登录。

Java微服务

输入您的Okta开发人员帐户的用户名和密码,您应该会看到凉爽的汽车清单。

Java微服务

如果您到此为止并成功运行了示例应用程序,那么恭喜! 你真酷! 😎

使用Netflix Zuul和Spring Cloud代理路由

Netflix Zuul是您可能希望在微服务体系结构中使用的另一个便捷功能。 Zuul是一项网关服务,可提供动态路由,监视,弹性等。

为了添加Zuul,我将其作为依赖项添加到api-gateway/pom.xml

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

然后,我将@EnableZuulProxy添加到ApiGatewayApplication类。

import org.springframework.cloud.netflix.zuul.EnableZuulProxy;@EnableZuulProxy
@SpringBootApplication
public class ApiGatewayApplication {...
}

为了将访问令牌传递到代理路由,我创建了一个AuthorizationHeaderFilter类,该类扩展了ZuulFilter

package com.example.apigateway;import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.springframework.core.Ordered;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.core.oidc.OidcUserInfo;import java.util.Optional;import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;public class AuthorizationHeaderFilter extends ZuulFilter {private final OAuth2AuthorizedClientService clientService;public AuthorizationHeaderFilter(OAuth2AuthorizedClientService clientService) {this.clientService = clientService;}@Overridepublic String filterType() {return PRE_TYPE;}@Overridepublic int filterOrder() {return Ordered.LOWEST_PRECEDENCE;}@Overridepublic boolean shouldFilter() {return true;}@Overridepublic Object run() {RequestContext ctx = RequestContext.getCurrentContext();Optional<String> authorizationHeader = getAuthorizationHeader();authorizationHeader.ifPresent(s -> ctx.addZuulRequestHeader("Authorization", s));return null;}private Optional<String> getAuthorizationHeader() {Authentication authentication = SecurityContextHolder.getContext().getAuthentication();OAuth2AuthenticationToken oauthToken = (OAuth2AuthenticationToken) authentication;OAuth2AuthorizedClient client = clientService.loadAuthorizedClient(oauthToken.getAuthorizedClientRegistrationId(),oauthToken.getName());OAuth2AccessToken accessToken = client.getAccessToken();if (accessToken == null) {return Optional.empty();} else {String tokenType = accessToken.getTokenType().getValue();String authorizationHeaderValue = String.format("%s %s", tokenType, accessToken.getTokenValue());return Optional.of(authorizationHeaderValue);}}
}

您可能会注意到, getAuthorizationHeader()方法中的代码与UserFeignClientInterceptor的代码非常相似。 由于只有几行,因此我选择不将其移至实用程序类。 Feign拦截器用于@FeignClient ,而Zuul过滤器用于Zuul代理的请求。

为了使Spring Boot和Zuul知道此过滤器,我在主应用程序类中将其注册为Bean。

public AuthorizationHeaderFilter authHeaderFilter(OAuth2AuthorizedClientService clientService) {return new AuthorizationHeaderFilter(clientService);
}

为了将请求从API网关代理到汽车服务,我添加了到api-gateway/src/main/resources/application.properties路由。

zuul.routes.car-service.path=/cars
zuul.routes.car-service.url=http://localhost:8090zuul.routes.home.path=/home
zuul.routes.home.url=http://localhost:8090zuul.sensitive-headers=Cookie,Set-Cookie

我在/home路线的car-service项目中添加了HomeController

package com.example.carservice;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;import java.security.Principal;@RestController
public class HomeController {private final static Logger log = LoggerFactory.getLogger(HomeController.class);@GetMapping("/home")public String howdy(Principal principal) {String username = principal.getName();JwtAuthenticationToken token = (JwtAuthenticationToken) principal;log.info("claims: " + token.getTokenAttributes());return "Hello, " + username;}
}

确认您的Zuul路线工作

由于这些更改已经在您克隆的项目中,因此您应该能够在浏览器中查看https://localhost:8080/carshttp://localhost:8080/home

Java微服务

Spring Cloud Config呢?

在此示例中您可能已经注意到的一件事是,您必须在每个应用程序中配置OIDC属性。 如果您有500个微服务,这可能是一个真正的痛苦。 是的,您可以将它们定义为环境变量,这样就可以解决问题。 但是,如果您具有使用不同OIDC客户端ID的不同微服务堆栈,则此方法将很困难。

Spring Cloud Config是一个为分布式系统提供外部化配置的项目。 与其在本示例中添加它,不如在以后的教程中介绍它。

那Kotlin呢?

我用Java写这篇文章是因为它是Java生态系统中最受欢迎的语言。 然而,根据RedMonk从2019年1月开始的编程语言排名, Kotlin呈上升趋势 。

至少在本季度,Kotlin大幅增长,而所有三个基于JVM的同行均下降。 实际上,Kotlin跳了这么远,以至于它最终进入了第20名的前20名,并在此同时超越了Clojure(#24)和Groovy(#24)。 它仍然远远落后于Scala(#13),但在这些排名的历史上,Kotlin的增长仅次于Swift,因此很有趣的发现下一轮还是接下来的比赛。

Spring对Kotlin有很好的支持,您可以在start.spring.io上选择它作为语言。 如果您希望我们使用Kotlin写更多帖子,请在评论中告诉我们!

刷新令牌的已知问题

默认情况下,Okta的访问令牌在一小时后过期。 这是预期的,并且在使用OAuth 2.0时建议使用短期访问令牌。 刷新令牌的寿命通常更长(思考几天或几个月),并且可用于获取新的访问令牌。 使用Okta的Spring Boot启动器时,这应该会自动发生,但事实并非如此。

我配置了Okta组织,使其访问令牌在五分钟内到期。 您可以通过以下方法执行此操作:转到“ API” >“ 授权服务器” >“ 访问策略” ,单击“ 默认策略” ,然后编辑其规则。 然后将访问令牌的生存期从1小时更改为5分钟。

在浏览器中点击http://localhost:8080/cool-cars ,您将被重定向到Okta进行登录。 登录后,您应该会看到汽车的JSON字符串。

去做其他事情超过5分钟。

回来,刷新浏览器,您会看到[]而不是所有的汽车。

我仍在努力解决此问题,一旦找到我将更新此帖子。 如果您碰巧知道解决方案,请告诉我!

更新: Spring Security 5.1尚未自动刷新OAuth访问令牌。 它应该在Spring Security 5.2中可用 。

通过Spring Boot,Spring Cloud和微服务获得更多乐趣

我希望您喜欢这个关于如何使用Spring Boot和Spring Cloud构建Java微服务架构的教程。 您学习了如何以最少的代码构建所有内容,然后使用Spring Security,OAuth 2.0和Okta将其配置为安全。

您可以在GitHub上找到本教程中显示的所有代码。

我们是此博客上的Spring Boot,Spring Cloud和微服务的忠实拥护者。 这是您可能会发现有趣的其他几篇文章:

  • 带有Spring Cloud Config和JHipster的Java微服务
  • Angular 8 + Spring Boot 2.2:立即构建一个CRUD应用程序!
  • Spring Boot登录选项快速指南
  • 使用Spring Boot和Kubernetes构建微服务架构
  • 使用HTTPS和OAuth 2.0保护服务到服务的Spring微服务
  • 构建Spring微服务并对其进行Dockerize生产

请在Twitter @oktadev上关注我们,并订阅我们的YouTube频道,以了解更多有关Spring Boot和微服务的知识。

“带有Spring Boot和Spring Cloud的Java微服务”最初于2019年5月22日发布在Okta开发者博客上

朋友不允许朋友写用户身份验证。 厌倦了管理自己的用户? 立即尝试Okta的API和Java SDK。 在几分钟之内即可对任何应用程序中的用户进行身份验证,管理和保护。

翻译自: https://www.javacodegeeks.com/2019/06/java-microservices-spring-boot-spring-cloud.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/341277.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

修改typora主题的字体

简 述&#xff1a; 在 mac 中修改 typora 主题的英文和中文的字体&#xff0c;使得码字更加舒服&#xff08;win 也有效&#xff09;。 [TOC] 本文初发于 “偕臧的小站“&#xff0c;同步转载于此。 书写环境&#xff1a; &#x1f4bb;&#xff1a; MacOS 10.14.6 &#x1…

在ADF 12.2.1.3中使用基于JSON的REST Web服务

以前&#xff0c;我曾发布过有关在ADF中使用基于ADF BC的REST Web服务的信息。 现在&#xff0c;本文讨论使用通用数据控件使用基于JSON的REST Web服务。 您也可以查看有关Web服务的先前文章&#xff0c;以获取更多信息。 在ADF 12.2.1中使用应用程序模块快速创建SOAP Web服务…

C++中字符型和整型的关系

文章目录结论测试字符与字符字符与数字实用小技巧字符转数字数字转字符ASCII的特点结论 字符型就是整型&#xff0c;对应的整数由ASCII(美国信息交换标准代码)规定。字符和整数&#xff0c;或者字符和字符进行运算时&#xff0c;结果为int。与整型的运算规则完全一样。 测试 …

专业QA如何实施可靠的CI / CD管道?

过时的传统软件开发方法并不能接管不断升级的市场趋势&#xff0c;并且这些方法缺乏解决方案&#xff0c;这些解决方案无法满足引入“ 持续集成&#xff08;CI&#xff09;和持续交付&#xff08;CD&#xff09; ”的快速软件发布的日益增长的需求。 除CI / CD之外&#xff0c;…

solr analyzer_查看您的Solr缓存大小:Eclipse Memory Analyzer

solr analyzerSolr使用不同的缓存来防止请求期间过多的IO访问和计算。 如果索引不是很频繁发生&#xff0c;则可以通过使用这些缓存来获得巨大的性能提升。 根据索引数据的结构和缓存的大小&#xff0c;它们可能会变得很大&#xff0c;并占用堆内存的很大一部分。 在本文中&…

好用的电脑软件总结

一 科研 1 阅读软件 Citavi 文献阅读软件小绿鲸SCI 文献翻译软件文献翻译阅读软件 &#xff1a;Quicker沙拉查词 来自 https://mubu.com/doc/vWDgwhwdg0 注&#xff1a;沙拉查词可能出现翻译后仍然保持选中的状态&#xff0c;鼠标无法自由移动&#xff0c;针对这种情况&#…

lucene快速入门_为Lucene选择快速唯一标识符(UUID)

lucene快速入门大多数使用Apache Lucene的搜索应用程序都会为每个索引文档分配一个唯一的ID&#xff08;即主键&#xff09;。 尽管Lucene本身不需要这样做&#xff08;它可能不太在乎&#xff01;&#xff09;&#xff0c;但应用程序通常需要它以后通过其外部ID替换&#xff0…

使用eclipse调试ns3-配置说明

Tips&#xff1a; 1&#xff0c; 安装eclipse时注意选择C开发组件&#xff1b; 环境配置参考&#xff1a;https://www.cnblogs.com/zlcxbb/p/3852810.html 第一步&#xff0c;新建C工程&#xff1b; 第二步&#xff0c;在project explorer中右键属性&#xff0c;如下图&#…

singleton 类_在Java中对Singleton类进行双重检查锁定

singleton 类Singleton类在Java开发人员中非常常见&#xff0c;但是它给初级开发人员带来了许多挑战。 他们面临的主要挑战之一是如何使Singleton保持为Singleton&#xff1f; 也就是说&#xff0c;无论出于何种原因&#xff0c;如何防止单个实例的多个实例。 对Singleton进行双…

将 Citavi 笔记按需要导出

文章目录简要介绍导出某一条笔记导出按条件筛选的一类笔记导出某一篇 PDF 的笔记导出全部笔记简要介绍 Citavi 的笔记功能相比其他文献管理软件较为完善&#xff0c;对 PDF 的标注是一种双链标注&#xff0c;阅读论文更方便&#xff0c;这也是当下很多笔记软件在做的功能之一&…

Window10:不能建立到远程计算机的连接。你可能需要更改此连接的网络设置。

解决步骤&#xff1a; 第一步&#xff1a;在桌面找到此电脑&#xff0c;鼠标右键点击&#xff0c;选择管理 第二步&#xff1a;进入计算机管理界面 第三步&#xff1a;点击设备管理器-再点击网络适配器 第四步&#xff1a;卸载WAN MIniport&#xff08;ip) 重启电脑。重新拨号&…

C盘爆红的解决方法

C盘爆红的原因 1. 系统存在的过多功能 2. 安装的软件占用 3. 聊天软件文件占用 4. 临时文件占用 5. 软件缓存占用 针对不同的原因进行处理 一.关闭不用的系统功能 1. 从1903版本开始,win10 C盘就有~7G的保留空间占用&#xff1b; 提供dism命令关闭方法&#xff0c;命令…

OneNote使用说明

Microsoft OneNote&#xff0c;是一套用于自由形式的信息获取以及多用户协作工具。OneNote最常用于笔记本电脑或台式电脑&#xff0c;但这套软件更适合用于支持手写笔操作的平板电脑&#xff0c;在这类设备上可使用触笔、声音或视频创建笔记。 感觉onenote就像纸质的笔记本&…

雷柏MT750S鼠标使用总结(驱动|连接|模式|续航)

【什么值得买 摘要频道】下列精选内容摘自于《无线办公好帮手 雷柏MT750S无线蓝牙鼠标体验》的片段&#xff1a; 驱动 雷柏MT750S的驱动软件界面比较简单&#xff0c;因为没有灯光的原因&#xff0c;软件主要是鼠标按键功能的设置&#xff0c;在左侧显示了各种功能&#xff0c…

通过Main的Checkpoint Restore加快Java启动速度

Java虚拟机为已编译为字节码 &#xff08;但不一定是用Java编写&#xff09;的应用程序提供了托管运行时环境。 与为特定平台静态编译的代码相比&#xff0c;这为应用程序开发人员提供了许多好处&#xff0c;并且通常可以提高性能。 JVM通过垃圾回收器 &#xff08;GC&#xff…

“操作无法完成因为其中的文件夹或文件已在另一个程序中打开”解决办法

在windows系统中&#xff0c;我们经常会遇到这样一个问题&#xff1a;删除某一个文件或者文件夹&#xff0c;被提醒&#xff1a;操作无法完成&#xff0c;因为其中的文件夹或文件已在另一个程序中打开。 这个时候我们一般会先检查是否真的有程序或者文件打开了没有关闭&#xf…

【CLion】如何编译运行单个文件 (C/C++ Single File Execution插件的使用)

如果你知道如何使用 C/C Single File Execution 插件但仍然无法找到运行按钮 请直接看第五张图片 一、 这里我首先新建了一个项目&#xff0c;名为Demo 又在项目文件夹内新建了一个代码文件&#xff0c;名为TestCode 二、 然后在 File - Settings - Plugins 中搜索 C/C Single…

使用Mocks进行需求驱动的软件开发

jmock作者撰写的有关模拟框架的优秀论文 。 本文写于18年前的2004年&#xff0c;但其中有许多构建可维护软件系统的技巧。 在这篇文章中&#xff0c;我将重点介绍本文中的关键思想&#xff0c;但建议您阅读本文&#xff0c;以获取有关模拟和编程实践的重要思想。 模拟对象是测…