封装微服务访问
以下是我的客户端应用程序的 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
文件.