封装微服务访问

以下是我的客户端应用程序的 WebAccountService 的一部分:


@Service
public class WebAccountsService {

    @Autowired        // NO LONGER auto-created by Spring Cloud (see below)
    @LoadBalanced     // Explicitly request the load-balanced template
                      // with Ribbon built-in
    protected RestTemplate restTemplate; 

    protected String serviceUrl;

    public WebAccountsService(String serviceUrl) {
        this.serviceUrl = serviceUrl.startsWith("http") ?
               serviceUrl : "http://" + serviceUrl;
    }

    public Account getByNumber(String accountNumber) {
        Account account = restTemplate.getForObject(serviceUrl
                + "/accounts/{number}", Account.class, accountNumber);

        if (account == null)
            throw new AccountNotFoundException(accountNumber);
        else
            return account;
    }
    ...
}


注意,我的 WebAccountService 只是 restemplate 从 microservice 获取数据的包装器。有趣的部分是 serviceUrl 和 rest 模板。

访问微服务

如下所示, serviceUrl 由主程序提供给 WebAccountController (后者将其传递给 WebAccountService ):


@SpringBootApplication
@EnableDiscoveryClient
@ComponentScan(useDefaultFilters=false)  // Disable component scanner
public class WebServer {

    // Case insensitive: could also use: http://accounts-service
    public static final String ACCOUNTS_SERVICE_URL
                                        = "http://ACCOUNTS-SERVICE";

    public static void main(String[] args) {
        // Will configure using web-server.yml
        System.setProperty("spring.config.name", "web-server");
        SpringApplication.run(WebServer.class, args);
    }

    @LoadBalanced    // Make sure to create the load-balanced template
    @Bean
    RestTemplate restTemplate() {
        return new RestTemplate();
    }

    /**
     * Account service calls microservice internally using provided URL.
     */
    @Bean
    public WebAccountsService accountsService() {
        return new WebAccountsService(ACCOUNTS_SERVICE_URL);
    }

    @Bean
    public WebAccountsController accountsController() {
         return new WebAccountsController
                       (accountsService());  // plug in account-service
    }
}


需要注意的几点:

1. WebController 是一个典型的基于springmvc视图的返回HTML的控制器。应用程序使用Thymeleaf作为视图技术(用于生成动态HTML)

2. WebServer 也是一个 @EnableDiscoveryClient ,但在本例中,除了向发现服务器注册自身(这是不必要的,因为它不提供自己的服务)之外,它还使用Eureka来定位帐户服务。

3. 从Spring Boot继承的默认组件扫描程序安装程序查找 @component 类,在本例中,找到我的 WebAccountController 并尝试创建它。但是,我想自己创建它,所以我禁用了这个 @ComponentScan(usefaultfilters=false) 这样的扫描器。

4. 我传递给 WebAccountController 的服务url是用于向发现服务器注册自身的服务的名称—默认情况下,这与 spring.application.name 有关帐户服务的流程-请参阅 account-service.yml 上面。不需要使用大写,但它确实有助于强调ACCOUNTS-SERVICE是一个逻辑主机(将通过发现获得),而不是实际主机。

负载均衡RestTemplate

RestTemplate bean 将被springcloud截获并自动配置(由于 @LoadBalanced 注释),以使用使用Netflix功能区进行微服务查找的定制 HttpRequestClient 。Ribbon也是一个负载平衡器,因此如果您有多个可用的服务实例,它会为您选择一个。(Eureka和Consul都不自己执行负载平衡,所以我们使用Ribbon来代替)。

注意:在Brixton发布系列(springcloud1.1.0.Release)中,RestTemplate不再自动创建。最初它是为您创建的,这会导致混乱和潜在的冲突(有时Spring可能太有用了!)。

注意,这个实例是使用 @LoadBalanced 限定的。(注释本身用 @Qualifier 进行了注释-有关详细信息,请参见此处)。因此,如果您有多个RestTemplate bean,可以确保注入正确的一个,如下所示:


@Autowired
    @LoadBalanced     // Make sure to inject the load-balanced template
    protected RestTemplate restTemplate;


如果查看 RibbonClientHttpRequestFactory ,您将看到以下代码:


String serviceId = originalUri.getHost();
    ServiceInstance instance =
             loadBalancer.choose(serviceId);  // loadBalancer uses Ribbon
    ... if instance non-null (service exists) ...
    URI uri = loadBalancer.reconstructURI(instance, originalUri);


loadBalancer 获取逻辑服务名称(在发现服务器中注册的名称),并将其转换为所选微服务的实际主机名。

RestTemplate 实例是线程安全的,可以用于访问应用程序不同部分中的任意数量的服务(例如,我可能让 CustomerService 包装访问 customer data microservice 的同一restemplate实例)。

配置

下面是来自web的相关 web-server.yml . 用于:

1. 设置应用程序名称

2. 定义用于访问发现服务器的URL

3. 将Tomcat端口设置为 3333


# Spring Properties
spring:
  application:
     name: web-service

# Discovery Server Access
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:1111/eureka/

# HTTP Server
server:
  port: 3333   # HTTP (Tomcat) portCOPY


如何运行Demo

 克隆它,或者加载到您喜爱的IDE中,或者直接使用maven。关于如何运行演示的建议包含在项目主页的自述文件中。

视图模板引擎

Eureka仪表板( RegistrationServer 内部)使用 FreeMarker 模板实现,但其他两个应用程序使用Thymeleaf。为了确保每个使用正确的视图引擎,在每个YML文件中都有额外的配置。

这是在 registration-server.yml 禁用Thymeleaf。


...
# Discovery Server Dashboard uses FreeMarker.  Don't want Thymeleaf templates
spring:
  thymeleaf:
    enabled: false     # Disable Thymeleaf spring:


因为 AccountService 和 WebService 都使用thymeleaf,所以我们还需要分别指向它们自己的模板。这是 account-server.yml 的一部分:


# Spring properties
spring:
  application:
     name: accounts-service  # Service registers under this name
  freemarker:
    enabled: false      # Ignore Eureka dashboard FreeMarker templates
  thymeleaf:
    cache: false        # Allow Thymeleaf templates to be reloaded at runtime
    prefix: classpath:/accounts-server/templates/
                        # Template location for this application only
...


web-server.yml 类似,但其模板由


prefix: classpath:/web-server/templates/


记下每一页末尾的“ / ” spring.thymeleaf.prefix 前缀类路径-这是至关重要的。

命令行执行

jar被编译为自动运行 io.pivotal.microservices.services.Main 。主要从命令行调用时-请参阅 Main.java .

可以在POM中看到设置 start-class 的Spring Boot选项:


<properties>
        <!-- Stand-alone RESTFul application for testing only -->
        <start-class>io.pivotal.microservices.services.Main</start-class>
    </properties>


AccountsConfiguration类


@SpringBootApplication
@EntityScan("io.pivotal.microservices.accounts")
@EnableJpaRepositories("io.pivotal.microservices.accounts")
@PropertySource("classpath:db-config.properties")
public class AccountsWebApplication {
...
}


这是 AccountService 的主要配置类, AccountService 是使用Spring数据的经典Spring Boot application。注释完成了大部分工作:

1. @SpringBootApplication -将其定义为SpringBoot应用程序。这个方便的注释结合了 @EnableAutoConfiguration 、 @Configuration 和 @ComponentScan (默认情况下,这会导致Spring在包含此类的包及其子包中搜索组件——潜在的springbean: AccountController 和 AccountRepository )。

2. @EntityScan("io.pivotal.microservices.accounts") —因为我使用的是JPA,所以需要指定 @Entity 类的位置。通常这是您在JPA中指定的选项 persistence.xml 或者在创建 LocalContainerEntityManagerFactoryBean 时。springboot将为我创建这个工厂bean,因为springbootstarter数据jpa依赖关系位于类路径上。因此,指定在何处查找 @Entity 类的另一种方法是使用 @EntityScan 。这将找到帐户。

3. @EnableJpaRepositories("io.pivotal.microservices.accounts") —查找扩展SpringData的 Repository 标记接口的类,并使用JPA自动实现它们。

4. @PropertySource("classpath:db-config.properties") -properties来配置我的数据源。

配置属性

如上所述,Spring Boot applications寻找应用程序属性或者 application.yml 配置自己。由于此应用程序中使用的所有三个服务器都在同一个项目中,因此它们将自动使用相同的配置。

为了避免这种情况,每个文件都通过设置 spring.config.name 属性。

例如,这里是 WebServer.java .


public static void main(String[] args) {
  // Tell server to look for web-server.properties or web-server.yml
  System.setProperty("spring.config.name", "web-server");
  SpringApplication.run(WebServer.class, args);
}


在运行时,应用程序将查找并使用 web-server.yml 在 src/main/resources 中。

登录中

springboot默认为Spring设置 info 级日志记录。因为我们需要检查日志以找到我们的微服务工作的证据,所以我提高了警告级别以减少日志记录的数量。

为此,需要在每个xxxx中指定日志记录级别- xxxx-server.yml 配置文件。这通常是定义它们的最佳位置,因为不能在属性文件中指定日志属性(在处理 @PropertySource 指令之前,日志已经初始化)。在SpringBoot手册中有一个关于这个的注释,但是很容易错过。

我没有在每个YAML文件中复制日志配置,而是选择将其放在logback配置文件中,因为Spring引导使用 logback —请参阅 src/main/resources/logback.xml 文件. 这三项服务将共享相同的服务 logback.xml 文件.