一个项目的SpringCloud微服务改造过程

SSO是公司一个已经存在了若干年的项目,后端采用SpringMVC、MyBatis,数据库使用MySQL,前端展示使用Freemark。今年,我们对该项目进行了一次革命性的改进,改造成SpringCloud架构,并且把前后端分离,前端采用Vue框架。

一、使用SpringCloud架构进行改造

1.1 为什么使用SpringCloud

SpringCloud的核心是SpringBoot,相比较于传统的Spring,SpringCloud具有以下优点:

  • 部署简单,SpringBoot内置了Tomcat容器,可以将程序直接编译成一个jar,通过java-jar来运行。
  • 编码简单,SpringBoot只需要在pom文件中添加一个starter-web依赖,即可帮助开发者快速启动一个web容器,非常方便。
  • 配置简单,SpringBoot可以通过简单的注解方式来代替原先Spring非常复杂的xml方式。如果我想把一个普通的类交给Spring管理,只需要添加@Configuration和@Bean两个注解即可。
  • 监控简单,我们可以引入spring-boot-start-actuator依赖,直接使用REST方式来获取进程的运行期性能参数,从而达到监控的目的。

1.2 一个常规项目都需要改造哪些部分

1.2.1 配置文件

SSO项目改造前充斥着大量的配置文件,主要包含以下这些部分:

  • 静态资源相关
  • 数据源
  • mybatis配置
  • redis配置
  • 事务
  • 拦截器拦截内容
  • 监听器、过滤器
  • 组件扫描路径配置

本文着重介绍以下几个部分:

1)静态资源处理

SpringMVC中,如果mvc:interceptors配置的URL规则如下,则不会拦截静态资源。

<mvc:mapping path="/*.do" />

但是如果配置的是:

<mvc:mapping path="/**" />

方案1: 在web.xml中配置&lt;servlet-name&gt;default&lt;/servlet-name&gt;,用defaultServlet先处理请求如:

   <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.jpg</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.png</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.gif</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.ico</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.gif</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.js</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.css</url-pattern>
    </servlet-mapping>

方案2:使用&lt;mvc:resources /&gt;标签声明静态资源路径

<mvc:resources mapping="/resources/js/**" location="/js/" />
<mvc:resources mapping="/resources/images/**" location="/images/" />
<mvc:resources mapping="/resources/css/**" location="/css/" />

方案3:使用mvc:default-servlet-handler/标签

SpringBoot解决方案:继承WebMvcConfigurerAdapter实现addResourceHandlers方法。

public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/**")
    .addResourceLocations("classpath:/resource/")//sso静态资源
    .addResourceLocations("classpath:/META-INF/resources/")//swagger静态资源
    .setCachePeriod(0);//0表示不缓存
}

sso静态资源文件路径如图:

2)拦截器

SpringMVC配置文件内容:

拦截任何请求并且初始化参数,有些请求是不需要拦截的,有的请求登录后不需要经过权限校验直接放行。

<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**" />
           <bean class="自定义拦截器PermissionInterceptor">
           <!-- 未登录即可访问的地址 -->
          <property name="excludeUrls">
          <list><value>请求地址<value></list>
          </property>
          <!-- 只要登录了就不需要拦截的资源 -->
          <property name="LogInExcludeUrls">
          <list><value>请求地址<value></list>
          </property>
         </bean>
   </mvc:interceptor>
 </mvc:interceptors>

SpringBoot中添加拦截器只需继承WebMvcConfigurerAdapter,并重写addInterceptors方法即可。

 /*** 拦截器
 * @param registry
 */
 @Override
 public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(permissionInterceptor).
            addPathPatterns("/**");
    super.addInterceptors(registry);
 }

自定义的拦截器需要初始化一些参数,因此需要在注册拦截器之前注册,这里我们设置为懒加载。免登录拦截的路径,以及登录后不需要判断权限的路径都写在yml文件了,通过系统环境变量Environment获取值。

@Autowired
@Lazy
private PermissionInterceptor permissionInterceptor;
@Autowired
private Environment environment;

/**
*
*/
@Bean
public PermissionInterceptor permissionInterceptor() {
  PermissionInterceptor permissionInterceptor = new PermissionInterceptor();
  List<String> excludeUrls = Arrays.asList(environment.getProperty("intercept.exclude.path").split(","));
  List<String> commonUrls = Arrays.asList(environment.getProperty("intercept.login.exclude.path").split(","));
  permissionInterceptor.setCommonUrls(commonUrls);
  permissionInterceptor.setExcludeUrls(excludeUrls);
 return permissionInterceptor;
}
3)数据库和mybatis配置

A、数据源配置

数据源注入的三种情况:

【情况一】

  • 条件:不引?druid-spring-boot-starter只依赖druid.jar,不指定spring.datasource.type。
  • 结果:注入的数据源是tomcat的数据源。
  • 解析:依赖的mybatis-spring-boot-starter工程依赖了tomcat的数据源,spring-boot-autoconfigure-starter的DataSourceAutoConfiguration自动注入类会在不指定数据源的情况下,判断路径中是否存在默认的4种数据源(Hikari,Tomcat,Dbcp,Dbcp2)的其一,如果有就注入。

【情况二】

  • 条件:不引入druid-spring-boot-starter只依赖druid.jar ,指定spring.datasource.type为DruidDataSource。
  • 结果:注入了DruidDataSource数据源,但配置文件中的druid配置不会生效。
  • 解析: 指定了依赖的数据源后,spring自动注入的starter会将指定的数据源注入,yml指定了druid数据源。@ConfigurationProperties注解的DataSourceProperties没处理druid部分的性能参数属性,只处理了数据源部分的属性。

【情况三】

  • 条件:引??druid-spring-boot-starter?不依赖druid.jar,指定spring.datasource.type为DruidDataSource。
  • 结果:注入了DruidDataSource数据源, 配置文件中的druid配置也会生效。
  • 解析:druid-spring-boot-starter自动配置类会在DataSourceAutoConfiguration之前先创建数据源,并且@ConfigurationProperties注入的DataSourceProperties包含了配置文件中druid的属性。

pom.xml依赖:

    <!-- 情况一、二 测试引入的依赖 -->
    <!--<dependency>-->
        <!--<groupId>com.alibaba</groupId>-->
        <!--<artifactId>druid</artifactId>-->
        <!--<version>${druid.version}</version>-->
    <!--</dependency>-->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
        <version>1.1.10</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>RELEASE</version>
    </dependency>

yml配置:

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource            # 当前数据源操作类型
    driver-class-name: com.mysql.jdbc.Driver            # mysql驱动包
    url: jdbc:mysql://yourURL        # 数据库名称
    username: yourusername
    password: yourpassword
    druid:
      initial-size: 5  # 初始化大小
      min-idle: 5  # 最小
      max-active: 20  # 最大
      max-wait: 60000  # 连接超时时间
      time-between-eviction-runs-millis: 60000  # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
      min-evictable-idle-time-millis: 300000  # 指定一个空闲连接最少空闲多久后可被清除,单位是毫秒
      validationQuery: select ‘x‘
      test-while-idle: true  # 当连接空闲时,是否执行连接测试
      test-on-borrow: false  # 当从连接池借用连接时,是否测试该连接
      test-on-return: false  # 在连接归还到连接池时是否测试该连接
      filters: config,wall,stat

B、MyBatis配置

通过引入mybatis-spring-boot-starter依赖,可以简单配置mybatis上手使用。

下面简单分析mybatis-starter的源码以及如何配置mybatis。

先看mybatis-spring-boot-starter中mybatis-spring-boot-autoconfigure的spring.factories文件

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration

可以看到自动注入类是MybatisAutoConfiguration,我们从这个类入手分析可以知道,必须先创建好了数据源后,才会加载mybatis的sqlSessionFactory。

@EnableConfigurationProperties({MybatisProperties.class})注解指定了配置文件中
prefix = "mybatis" 那部分属性有效,这部分属性值将注入到已创建的SqlSessionFactoryBean中,最后生成SqlSessionFactory对象。

@Configuration
//当SqlSessionFactory,SqlSessionFactoryBean存在的情况下加载当前Bean
@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})
//当指定数据源在容器中只有一个或者有多个但是只指定首选数据源
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties({MybatisProperties.class})
//当数据源注入到Spring容器后才开始加载当前Bean
@AutoConfigureAfter({DataSourceAutoConfiguration.class})
public class MybatisAutoConfiguration implements InitializingBean {
    private final MybatisProperties properties;
    @Bean
    @ConditionalOnMissingBean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
        factory.setDataSource(dataSource);
        factory.setVfs(SpringBootVFS.class);
       //设置mybatis配置文件所在路径
        if (StringUtils.hasText(this.properties.getConfigLocation())) {
          factory.setConfigLocation(this.resourceLoader.getResource
          (this.properties.getConfigLocation())); }
        }
      //设置其他MyBatisProperties对象中有的属性略....
       return factory.getObject();
   }
}

MybatisProperties含有的属性:

@ConfigurationProperties(prefix = "mybatis" )
public class MybatisProperties {
 public static final String MYBATIS_PREFIX = "mybatis";
 private static final ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
 private String configLocation;
 private String[] mapperLocations;
 private String typeAliasesPackage;
 private Class<?> typeAliasesSuperType;
 private String typeHandlersPackage;
 private boolean checkConfigLocation = false;
 private ExecutorType executorType;
 private Properties configurationProperties;
 @NestedConfigurationProperty
 private Configuration configuration;
}

C、使用mybatis

  • 配置文件:

application.yml

mybatis:
config-location: classpath:mybatis.xml        # mybatis配置文件所在路径
type-aliases-package: com.creditease.permission.model    # 所有Entity别名类所在包
mapper-locations: classpath:mybatis/**/*.xml

从上面的MybatisProperties可以看出,mybatis可以指定一些configuration,比如自定义拦截器pageHelper。

mybatis.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
        <plugin interceptor="com.creditease.permission.manager.MybatisInterceptor"></plugin>
    </plugins>
</configuration>
  • 在启动类上加入@MapperScan注解
@MapperScan("com.creditease.permission.dao")//mapper类所在目录
public class SsoApplication {
    public static void main(String[] args) {
        SpringApplication.run(SsoApplication.class, args);
    }
}
4)事务

Spring事务有两种处理方式:

  • 编程式

用TransactionTemplate或者直接使用底层的PlatformTransactionManager将事务代码写在业务代码中。

优点:可以在代码块中处理事务,比较灵活。

缺点:对代码具有侵入性。

  • 声明式

采用@Transactional注解或者基于配置文件方式,在方法前后进行拦截。

优点:非侵入性不会污染代码。

缺点:事务只能在方法和类上控制,粒度较小。

A、使用@Transactional注解

非SpringBoot工程,需要在配置文件中加入配置:

  <tx:annotation-driven/>

SpringBoot工程可以用@EnableTransactionManagement注解代替上面的配置内容。

B、采用配置文件方式

之前的sso是基于配置的方式,配置代码如下:

   <aop:config>
        <aop:pointcut expression="execution(public * com.creditease.permission.service.impl.*Impl.*(..))" id="pointcut"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
    </aop:config>
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="query*" propagation="REQUIRED" read-only="true"/>
            <tx:method name="find*" propagation="REQUIRED" read-only="true"/>
            <tx:method name="save*" propagation="REQUIRED"/>
            <tx:method name="delete*" propagation="REQUIRED"/>
            <tx:method name="add*" propagation="REQUIRED"/>
            <tx:method name="modify*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

改造后的SpringBoot基于Java代码:

  @Aspect
@Configuration
public class TransactionAdviceConfig {

    /**
     * 指定切入点
     */
    private static final String AOP_POINTCUT_EXPRESSION = "execution(public * com.creditease.permission.service.impl.*Impl.*(..))";

    @Resource
    DruidDataSource dataSource;

    /**
     * 指定处理事务的PlatformTransactionManager
     * @return
     */
    @Bean
    public DataSourceTransactionManager transactionManager() {

        return new DataSourceTransactionManager(dataSource);

    }

    /**
     * 指定切入点处理逻辑,执行事务
     * @return
     */
    @Bean
    public TransactionInterceptor txAdvice() {

        DefaultTransactionAttribute txAttrRequired = new DefaultTransactionAttribute();
        txAttrRequired.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

        DefaultTransactionAttribute txAttrRequiredReadonly = new DefaultTransactionAttribute();
        txAttrRequiredReadonly.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        txAttrRequiredReadonly.setReadOnly(true);

        NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
        source.addTransactionalMethod("query*", txAttrRequiredReadonly);
        source.addTransactionalMethod("find*", txAttrRequiredReadonly);
        source.addTransactionalMethod("save*", txAttrRequired);
        source.addTransactionalMethod("delete*", txAttrRequired);
        source.addTransactionalMethod("add*", txAttrRequired);
        source.addTransactionalMethod("modify*", txAttrRequired);
        return new TransactionInterceptor(transactionManager(), source);
    }

    /**
     * Advisor组装配置,将Advice的代码逻辑注入到Pointcut位置
     * @return
     */
    @Bean
    public Advisor txAdviceAdvisor() {

        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
        return new DefaultPointcutAdvisor(pointcut, txAdvice());
    }
5)全局异常处理

一般编码时有异常我们都会try-catch捕获异常,有时为了区分不同的异常还会一次catch多个异常,大量的try-catch语句,这样使得代码也不够优雅;一个相同的异常处理写多次代码也比较冗余,所以引入全局的异常处理非常必要。

改造前的异常处理配置文件:

<!--定义异常处理页面-->
<bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <property name="exceptionMappings">
            <props>
                <prop key="com.creditease.permissionapi.exception.NopermissionException">/permission/noSecurity</prop>
            </props>
        </property>
 </bean>

使用SimpleMappingExceptionResolver类处理异常,设置自定义异常类型NopermissionException,以及异常发生后的请求路径/permission/noSecurity。

SpringBoot中采用@RestControllerAdvice或者@ControllerAdvice设置全局异常类。这两者区别类似于@Controller和@RestController注解。

SSO中定义了三种全局的异常处理:普通的Exception处理;自定的NopermissionException异常和参数校验异常。

全局异常处理代码如下:

@Configuration
@Slf4j
@RestControllerAdvice
public class GlobalExceptionConfig {

    //无权限处理
    @ExceptionHandler(value = {NopermissionException.class})
    public void noPermissionExceptionHandler(HttpServletRequest request, Exception ex, HttpServletResponse response, @Value("${sso.server.prefix}") String domain) throws  IOException {
        printLog(request,ex);
        response.sendRedirect("跳转到无权限页面地址");
    }

     //参数校验处理
    @ExceptionHandler(value = {BindException.class})
    public ResultBody BindExceptionHandler(BindException  bindException){
        List<ObjectError> errors = bindException.getBindingResult().getAllErrors();
        //这个ResultBody是一个返回结果对象,这里需要返回json,里面包含了状态码和提示信息
        return  ResultBody.buildFailureResult(errors.get(0).getDefaultMessage());
    }

    //所有未捕获的异常处理逻辑
    @ExceptionHandler(value = {Exception.class})
    public ResultBody exceptionHandler(HttpServletRequest request,Exception ex){
        printLog(request,ex);
        return  ResultBody.buildExceptionResult();
    }

    //将请求参数和异常打印出来,结合@slf4j注解
    public void printLog(HttpServletRequest request,Exception ex){
        String parameters = JsonHelper.toString(request.getParameterMap());
        log.error("url>>>:{},params>>>:{} ,printLog>>>:{}",request.getRequestURL(),parameters,ex);
    }

}

@RestControllerAdvice结合@Validation,可以对Bean进行校验,校验不通过会抛出BindException异常。通过注解可以少写if-else代码,判断请求的接口参数是否为空,提高代码的美观性。例如:

    //常规做法
    if(StringUtils.isEmpty(ssoSystem.getSysCode())

    //SSO做法
    //在Controller请求方法上添加@Valid注解
    @RequestMapping(value = "/add", method = RequestMethod.POST)
    public ResultBody add(@Valid @RequestBody SsoSystem ssoSystem) {

    }

    //在需要处理的SsoSystem Bean的属性上加@NotNull注解
    @NotNull(message = "系统编号不能为空")
    private String sysCode;

当sysCode传入参数为空时,就会抛出BindException被全局的异常处理类,捕获处理返回json格式的参数:

{
    "resultCode":2,
    "resultMsg":"系统编号不能为空",
    "resultData":null
}

1.3 注意事项

1.3.1 内置tomcat版本太高引发的问题

SpringBoot1.5默认使用内嵌tomcat8.5版本,而原来SpringMVC的SSO部署在tomcat7上。tomcat的升级对这次改造影响最明显的就是cookie。
tomcat8后采用的cookie校验协议是Rfc6265CookieProcessor。该协议要求domain的命名必须遵循以下规则:

  • 必须是1-9、a-z、A-Z、. 、- 这几个字符组成。
  • 必须是数字或字母开头 (之前是以.creditease.corp 会报错tomcat cookie domain validation异常,最后改成了 creditease.corp)。
  • 必须是数字或字母结尾。

二、前后端分离

2.1 解决跨域问题

由于是两个不同的应用,必然会有两个不同的端口。不同的端口就会有跨域问题,SSO采用的方式是通过nginx区分来自前后端的请求,反向代理请求对应到不同的服务去。

  • sso.creditease.com对应的是后端的应用服务。
  • sso.creditease.com/web对应的是前端的静态资源应用服务。

2.2 方便联调效率,引入swagger

swagger是后端接口展示的插件,通过修改拦截器代码,mock登录对象免登录,直接访问接口进行前后端的调试。在swagger插件上可以看到具体接口请求路径和参数、参数是否必须、返回值、接口统计信息等。

  • 接口统计信息
  • 请求参数和路径

  • 返回值

2.3 跳转接口修改

之前是通过SpringMvc的modeAndview方式跳转的,现在做了两种处理:

  • 改成restful接口的形式,前端控制跳转然后直接获取数据。
  • 直接通过response.sendRedirect跳转页面。

注意:老代码跳转采用的是通过SpringMvc在return的页面路径前加redirect的形式,如:return "redirect:index",这样默认会在return的URL后加jessionID。

2.4 静态资源地址变更可能引发的问题

特别需要注意代码中的相关校验路径的地方。比如在这次改造过程中路径修改会影响以下几个方面。

  • 菜单权限校验的时候,之前人、角色和路径已经绑定了,修改菜单访问路径会导致没权限。
  • 扫码登录的接口判断了refer来源,修改路径会导致请求失败。
  • 之前的sso-dome工程引用了静态资源,修改路径会报404。

作者: 黄玲峰

来源:宜信技术学院

原文地址:https://blog.51cto.com/14159827/2426929

时间: 2024-10-07 13:51:43

一个项目的SpringCloud微服务改造过程的相关文章

使用 Dubbo 对遗留单体系统进行微服务改造

摘要: 在 2016 年 11 月份的<技术雷达>中,ThoughtWorks 给予了微服务很高的评价.同时,也有越来越多的组织将实施微服务作为架构演进的一个必选方向.只不过在拥有众多遗留系统的组织内,将曾经的单体系统拆分为微服务并不是一件容易的事情. Credit: Justin Kenneth Rowley. You can find the original photo at flickr. The microservices style of architecture highligh

单体式应用微服务改造经验谈【上】

昨日好评博文:<如何设计出优美的Web API?> 截止目前阅读量近 2000,获得好评无数,小伙伴们不要错过哦! 微服务是当下最流行的应用架构技术了,它跟容器服务.DevOps合称云时代的三剑客,可以帮我们化解业务发展过快导致的产品迭代压力,让我们可以自由选择最适合团队的技术栈,让系统能够承载互联网海量用户的访问,让我们可以更加轻松地运维大型的互联网系统.近些年在厂商.社区和用户等各方努力推动下,微服务相关的理论和产品都日趋成熟,不同语言的微服务开发及治理套件(例如:Spring Cloud

springcloud微服务系列之服务注册与发现组件Eureka

一.Eurake的简介二.使用Eureka进行服务的注册消费1.创建一个服务注册中心2.创建服务的提供者3.创建服务的消费者总结 一.Eurake的简介 今天我们来介绍下springcloud的核心组件Eureka,Eurake是负责微服务架构中服务治理的功能,负责各个服务实例的注册与发现. Eureka包含了服务器端和客户端组件.服务器端,也被称作是服务注册中心,用于提供服务的注册与发现. 客户端组件包含服务消费者与服务生产者.在应用程序运行时,服务生产者向注册中心注册自己的服务实例,当消费者

微服务改造中解决跨库问题的思路

今年一直在和团队做微服务的架构改造(相关的一些详情,有兴趣的朋友,可以参见之前的这篇分享).但是做过改造的朋友都知道 从“All-In-One” 到 “Micro-Service” 都需要迈过的一个坎,那就是垂直分库, 根据不同的子服务,将数据库拆分为不同的子服务库. 那么问题就来了,在开始做微服务改造前,我发现在摇旺的老系统中,有很多后台报表或者前端详情页所需的数据是通过SQL Join来完成的.但是,我们微服务改造后,每个服务背后的数据库已经在分布不同的实例中了,所以我们已经不能继续简单在S

springcloud微服务系列——服务网关组件Zuul

前言 通过前几篇教程的介绍,我们基本上认识了构建一个微服务系统所需要的组件,通过这些组件的结合,我们已经可以搭建一个较为简略的微服务系统了,比如下面的架构图: https://img-blog.csdn.net/20180803175652889?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3lleWF6aGlzaGFuZw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70 可以看

15年资深架构师详解:一个大型互联网公司的微服务转型实践

微服务是一个比较大的话题,基于我的过往经历,本文将以 Netflix 为例,分享一个大型互联网公司如何从一个 Monolithic 的 APP 成功转型到微服务.文章主要涉及微服务的产生历史,应用场景,与单片服务区别,微服务带来的技术.企业组织结构等方面挑战,以及如何合理地选择单片服务构架和微服务构架等内容. 微服务的产生历史 如下图,是微服务在 Google 的搜索结果: 自 2014 年以来,微服务开始被关注,搜索的人越来越多,并在 2016 年左右达到顶峰.从地域来看,很多国家都在关注,如

springcloud微服务实战:Eureka+Zuul+Ribbon+Hystrix+SpringConfig

原文地址:http://blog.csdn.net/yp090416/article/details/78017552 springcloud微服务实战:Eureka+Zuul+Ribbon+Hystrix+SpringConfig 相信现在已经有很多小伙伴已经或者准备使用springcloud微服务了,接下来为大家搭建一个微服务框架,后期可以自己进行扩展.会提供一个小案例: 服务提供者和服务消费者 ,消费者会调用提供者的服务,新建的项目都是用springboot,附源码下载. coding仓库

【微服务】之四:轻松搞定SpringCloud微服务-负载均衡Ribbon

对于任何一个高可用高负载的系统来说,负载均衡是一个必不可少的名称.在大型分布式计算体系中,某个服务在单例的情况下,很难应对各种突发情况.因此,负载均衡是为了让系统在性能出现瓶颈或者其中一些出现状态下可以进行分发业务量的解决方案.在SpringCloud 体系当中,加入了Netflix公司的很多优秀产品,其中一个就是针对于服务端进行负载均衡的Ribbon. 本系列博文目录 [微服务]之三:轻松搞定SpringCloud微服务目录 本系列为连载文章,阅读本文之前强烈建议您先阅读前面几篇. 相关简介

【微服务】之五:轻松搞定SpringCloud微服务-调用远程组件Feign

上一篇文章讲到了负载均衡在Spring Cloud体系中的体现,其实Spring Cloud是提供了多种客户端调用的组件,各个微服务都是以HTTP接口的形式暴露自身服务的,因此在调用远程服务时就必须使用HTTP客户端.我们可以使用JDK原生的URLConnection.Apache的Http Client.Netty的异步HTTP Client, Spring的RestTemplate.但是,用起来最方便.最优雅的还是要属Feign了.今天这一篇文章是系列教程中第五篇,也是对负载均衡的第二篇,主