美文网首页
一个精简的微服务项目总结

一个精简的微服务项目总结

作者: _给我一支烟_ | 来源:发表于2020-08-23 10:34 被阅读0次

一个提供SDK接口的精简微服务项目的总结,使用的是SSM(springboot + springMVC + Mybatis)框架,配合Nacos进行服务发现和注册以及服务配置,项目主要包括两个服务:一个网关服务(server_gateway)和一个接口服务(server_appsdk)。

一、IDEA环境相关

  1. Maven Helper 插件安装
    操作maven 命令,如使用maven 打包等

  2. Lombok 插件安装
    lombok 能够减少大量的模板代码,使用
    @Data 注解时可以不用书写
    getter,setter方法,
    toString方法
    hashCode方法
    equals方法等
    @NoArgsConstructor, @AllArgsConstructor 可以不用写构造函数
    需要添加依赖

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
  1. MyBatisCodeHelperPro 插件安装
    设计完表后可以使用该插件自动生成dao层的表对应实体domain、mapper、以及mapper对应sql的xml文件,
    也可以生成service这个看个人需要,前面生成的dao层非常好用

  2. 如果IDEA底部找不到service面板,解决方法:
    打开.idea目录里面的 workspace.xml文件,找到 RunDashboard 项,用下面内容替换下

<component name="RunDashboard">
    <option name="configurationTypes">
      <set>
        <option value="SpringBootApplicationConfigurationType" />
      </set>
    </option>
    <option name="ruleStates">
      <list>
        <RuleState>
          <option name="name" value="ConfigurationTypeDashboardGroupingRule" />
        </RuleState>
        <RuleState>
          <option name="name" value="StatusDashboardGroupingRule" />
        </RuleState>
      </list>
    </option>
  </component>

二、项目结构

1.多模块项目结构

项目名为 server-starter,是一个 新建项目 -》选择 Maven 创建的一个 maven 项目目录作为整个项目的workspace和父pom
一个多模块项目通过一个父POM 引用一个或多个子模块来定义。在父项目的pom.xml中通过以下配置,将子项目关联。

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.7.RELEASE</version>
        <relativePath/>
    </parent>

    <groupId>com.hp</groupId>
    <artifactId>server-starter</artifactId>
    <version>1.0.0</version>
    <packaging>pom</packaging>  
    
    <modules>  
        <module> server_common </module>  
        <module> server_gateway </module> 
        <module> server_appsdk </module> 
    </modules>  

其中 <packaging>pom</packaging> 这个父项目不是创建一个JAR 或者一个WAR,它仅仅是一个引用其它 Maven 项目的POM。
pom.xml 中 modules 列出了项目的子模块。每个modules 元素对应了一个 server-starter 目录下的子目录。Maven知道去这些
子目录寻找pom.xml 文件,并且在构建的 server-starter 的时候,它会将这些子模块包含到要构建的项目中。
子项目的创建:在父项目目录右击new-》Module-》Spring Initalizer 创建相应的子项目

仅仅在父项目配置子项目是不能够真正实现关联的,子项目中需要配置

<parent>  
    <groupId>com.hp</groupId>  
    <artifactId>server-starter</artifactId>  
    <version>1.0.0</version>  
</parent>  

2.编译打包

现在,通过父pom.xml将多个子项目进行了关联,在server-starter上面右键 Run Maven -> clean/package 或者 clean install。
如果右键没有 Run Maven 选项,检查Maven Helper 插件是否安装好
将多个子项目打包,每个子项目都是一个独立的springboot服务都可以打成 JAR包直接在Linux 上面使用 java 命令运行

编译打包,把resources下面面的资源全部打包,并且打包到指定的目录路径下,在各个子项目的pom.xml中添加

<build>
    <finalName>hp-${project.artifactId}</finalName>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>true</filtering>
            <includes>
                <include>**/*.*</include>
            </includes>
        </resource>
    </resources>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
        <!--打包到指定目录下-->
        <plugin>
            <artifactId>maven-antrun-plugin</artifactId>
            <executions>
                <execution>
                    <id>copy-jar</id>
                    <phase>package</phase>
                    <configuration>
                        <tasks>
                            <copy todir="../bin">
                                <fileset dir="./target">
                                    <include name="*.jar"/>
                                </fileset>
                            </copy>
                        </tasks>
                    </configuration>
                    <goals>
                        <goal>run</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

3. 服务模块代码结构

大致的结构jave目录下
com.ali.hp包下面创建以下几个包

  • config
    配置包,如 mybatis,redis,swagger 等相关配置类放在该包下

  • pojo
    自定义的各个对象数据包

  • dao
    数据库相关的数据层包,里面有 domain, mapper, mapperxml等目录,这个包可以放在 server_common 公共模块中,这一各个服务都可以使用

  • service
    提供服务包,主要的业务逻辑的处理都在该包下面,一般用接口 + 实现的层次结构,即在包下面的各个具体服务目录下 建一个接口和一个 impl 包,impl包下写接口的实现

  • controller
    提供前端访问的接口包

  • schedule
    提供定时任务的包

  • 以及其他一些需要的包

4. 多环境配置

比如配置三个环境:dev 开发环境,test 测试环境, prod 生成环境
在 resources 目录下创建4个配置文件
application.yml,application-dev.yml,application-test.yml,application-prod.yml
具体使用哪个配置文件是根据 application.yml 里面的 spring.profiles.active 值决定的。
这样在开发的时候 application-dev.yml 不需要提交到svn,其他的配置可以提交到svn
举例:
application.yml

server:
  port: 8001
spring:
  profiles:
    active: test
  application:
    name: mser-service

application-dev.yml

env:
  serv-addr: 192.168.121.223
spring:
  cloud:
    nacos:
      discovery:
        server-addr: ${env.serv-addr}:8848

application-test.yml

env:
  serv-addr: 47.96.16.xxx
spring:
  cloud:
    nacos:
      discovery:
        server-addr: ${env.serv-addr}:8848

5. 常用注解

@Data
自动生成对象属性的get,set等方法
@NoArgsConstructor, @RequiredArgsConstructor, @AllArgsConstructor
注解在类上, 为类提供无参,有指定必须参数, 全参构造函数
@PostConstruct
注解在方法上会在服务器加载Servlet的时候运行,并且只会被服务器调用一次,类似于Serclet的inti()方法。被@PostConstruct修饰的方法会在构造函数之后,init()方法之前运行。
@PreConstruct
注解在方法上会在服务器卸载Servlet的时候运行,并且只会被服务器调用一次,类似于Servlet的destroy()方法。被@PreConstruct修饰的方法会在destroy()方法之后运行,在Servlet被彻底卸载之前
@Autowired
默认按照类型装配的,属于spring的
@Resource
默认按照名字装配的,属于J2EE的
@Controller
@ResponseBody
@RestController
相当于 @Controller 和 @ResponseBody的组合, 用于 controller 层
@RequestMapping("/api/user/")
@Value("${server.port}")
读取yml里面的配置值

三、Mybatis

封装数据库相关的操作,配合MyBatisCodeHelperPro 插件非常好用
如果是多表联合查询,可以单独写个Mapper,根据需要自定义一个对象用来返回sql查询的结果

1.添加依赖

<!-- mybatis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.4.4</version>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>1.3.1</version>
</dependency>
<!-- mybatis pagehelper -->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>4.2.1</version>
</dependency>

2.添加配置项

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://${env.serv-addr}:3306/gpsdk?characterEncoding=UTF-8&useTimezone=true&serverTimezone=GMT%2B8
    username: root
    password: 123456
    hikari:
      minimum-idle: 5 #最小连接数
      idle-timeout: 600000 #超时时间
      maximum-pool-size: 10 #连接池大小
      auto-commit: true #是否自动提交
      pool-name: MyHikariCP #连接池名字
      max-lifetime: 1800000
      connection-timeout: 30000
      connection-test-query: SELECT 1

3.创建配置类

创建一个config包,在包下建一个 MybatisConfig 配置类(在各自的服务模块上创建,不能在公共模块上建,依赖可以放到公共模块上)
在配置类中配置好MyBatisCodeHelperPro 插件自动生成dao层的domain、mapper、以及mapper对应sql的xml文件

@Configuration
@EnableTransactionManagement
@MapperScan("com.hp.common.dao.mapper")
public class MybatisConfig implements TransactionManagementConfigurer {

    @Autowired
    private DataSource dataSource;

    public MybatisConfig() {
    }

    @Override
    public PlatformTransactionManager annotationDrivenTransactionManager() {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean(name = "sqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory() {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        bean.setTypeAliasesPackage("com.hp.common.dao.domain");

        //分页插件
        PageHelper pageHelper = new PageHelper();
        Properties properties = new Properties();
        properties.setProperty("reasonable", "false");
        properties.setProperty("supportMethodsArguments", "true");
        properties.setProperty("returnPageInfo", "check");
        properties.setProperty("params", "count=countSql");
        pageHelper.setProperties(properties);
        bean.setPlugins(new Interceptor[]{pageHelper});

        try {
            ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
            // mybatis配置
            org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
            configuration.setLazyLoadingEnabled(true);
            configuration.setUseGeneratedKeys(true);
            configuration.setDefaultExecutorType(ExecutorType.REUSE);
            configuration.setDefaultStatementTimeout(30);
            configuration.setMapUnderscoreToCamelCase(true);
            configuration.setAutoMappingBehavior(AutoMappingBehavior.FULL);
            bean.setConfiguration(configuration);

            bean.setMapperLocations(resolver.getResources("classpath*:mapper/*.xml"));
            return bean.getObject();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

四、Redis

1.添加依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2.添加配置

spring:
  datasource:
    redis:
        database: 0
        host: ${env.serv-addr}
        port: 6379
        password: 
        jedis:
          pool:
            max-active: 20
            min-idle: 0
            max-idle: 20
            max-wait: -1ms

3.使用注意

redis模板对象注入 不要使用 @Autowired 会报错,应该使用 @Resource
StringRedisTemplate 可以使用@Autowired注入

    @Resource
    RedisTemplate<String, Integer> redisTemplate;

五、Swagger

生成api接口文档,再也不用单独在写一个接口文档了,直接通过注解的方式生成文档

1.添加依赖

<!-- swagger依赖 -->
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.8.0</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.8.0</version>
</dependency>

2.创建配置类

在配置类中配置好controller包的全路径名

@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @Value("${spring.profiles.active:dev}")
    private String env;
    @Value("${server.port}")
    private String serverPort;

    @Bean
    public Docket createAppRestApi() {
        List<Parameter> pars = new ArrayList<>();

        return new Docket(DocumentationType.SWAGGER_2)
                .enable("dev".equals(env) || "test".equals(env))
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.hp.mser.controller"))
                .paths(PathSelectors.any())
                .build()
                .globalOperationParameters(pars)
                .apiInfo(apiInfo());
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("开放平台服务文档")
                .description("提供开放平台服务")
                .termsOfServiceUrl("http://localhost:" + serverPort + "/v2/api-docs")
                .contact(new Contact("x", "", ""))
                .version("1.0.0")
                .build();
    }
}

3.使用

1.数据对象
在数据对象类上添加注解
@ApiModel(value = "xxxDTO", description = "xxx请求/应答")
在对象属性字段上添加注解
@ApiModelProperty(value = "小游戏ID", name = "id")
2.访问接口
在controller里面的类上添加注解
@Api(tags = "用户接口")
在访问接口类的方法上添加注解
@ApiOperation(value = "swagger测试")

六、Nacos

Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您实现动态服务发现、服务配置管理、服务及流量管理。

1. 下载安装

前往 https://github.com/alibaba/nacos/releases 下载

tar -xvf nacos-server-1.x.x.tar.gz

启动:解压后在 nacos/bin目录下 执行如下命令启动

Linux/Unix/Mac 下

sh startup.sh -m standalone

Windows 下

cmd startup.cmd

测试:打开 http://localhost:8848/nacos/#/login ,默认账号密码都是nacos

2. 添加依赖包

    <!-- nacos 发现服务 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!-- nacos 配置服务 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>

3. 增加配置项

spring:
  cloud:
    nacos:
      discovery:
        server-addr: ${env.address}:8848

4. 添加注解

在程序的main方法上添加:
@EnableDiscoveryClient 开启服务注册发现功能

5. 导入配置

server-appsdk.jar 运行启动时优先会读取同级目录下的启动配置文件,然后根据该配置文件找到nacos上配置的程序需要的配置文件

bootstrap.properties

# nacos配置服务地址
spring.cloud.nacos.config.server-addr=localhost:8848
# 配置文件名
spring.cloud.nacos.config.prefix=server-appsdk
# 环境
spring.profiles.active=test
# 后缀
spring.cloud.nacos.config.file-extension=yaml
#最终生成的文件名规则
# ${spring.cloud.nacos.config.prefix}-${spring.profile.active}.${file-extension}

在 nacos 控制台中 配置管理 | 配置列表 | 导入配置 上传 server-appsdk-test.yaml 配置文件,这样jar包程序就可以读取到这个配置了。

6. 服务管理

程序启动后,在 nacos 控制台中 服务管理 | 服务列表 中查看启动的服务是否已经在列表中了,在说明服务已经注册成功了,可以在控制台中管理该服务了

七、Gateway

Spring Cloud Gateway,相比之前我们使用的 Zuul(1.x) 它有哪些优势呢?Zuul(1.x) 基于 Servlet,使用阻塞 API,它不支持任何长连接,如 WebSockets。
Spring Cloud Gateway 使用非阻塞 API,支持 WebSockets,支持限流等新特性。

1.网关的路由配置

spring:
  application:
    name: gateway-client
  cloud:
    gateway:
      routes:
      - id: route_server_appsdk
        # uri以lb://开头(lb代表从注册中心获取服务),后面接的就是你需要转发到的服务名称
        uri: lb://server_appsdk
        predicates:
        - Path=/api/user/**

id:我们自定义的路由 ID,保持唯一
uri:目标服务地址
predicates:路由条件,Predicate 接受一个输入参数,返回一个布尔值结果。该接口包含多种默认方法来将 Predicate 组合成其他复杂的逻辑(比如:与,或,非)
- Path 通过请求路径匹配
filters:过滤规则

2.过滤器 filter

过滤器可以在路由请求之前对请求进行处理,也可以在请求响应之后对响应进行处理
在请求路由之前可以做比如参数校验,鉴权,日志记录,协议转换,请求参数修改,路径修改等
在请求响应之后可以做比如记录响应消息,修改响应,修改响应头等
过滤器最常见的功能就是鉴权,日志记录,限流和权重路由
Filter分为Gateway Filter和Global Filter

Global Filter是全局的过滤器,配置之后对所有路由都有效

过滤器 说明
LoadBalancerClientFilter 负载均衡过滤器
Netty Routing Filter 默认使用netty的底层
RouteToRequestUrlFilter 新的请求路由
Websocket Routing Filter websocket路由
Gateway Metrics Filter 路由监控,配合spring-boot-starter-actuator

自定义全局过滤器

@Slf4j
@Component
public class MyFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("this is a pre filter");
        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
            log.info("this is a post filter");
        }));
    }

    @Override
    public int getOrder() {
        return -1;
    }
}

注意:

1.这里的order不能使用@order 的注解

2.在fitler里面的是pre类型,会在路由前执行,在then里面的是post类型会在路由后执行

3.order 的数值越小pre越先执行,post越后执行

相关文章

  • 一个精简的微服务项目总结

    一个提供SDK接口的精简微服务项目的总结,使用的是SSM(springboot + springMVC + Myb...

  • 几个相关的服务项目放在一个套餐里还是分成几个不同的套餐?

    在云初起微方案中,一个套餐至少要包含一个服务项目,也可包含多个服务项目。一个服务项目可添加一个或多个选项,也可以没...

  • 微信的精简

    做减法吧 远离深渊的注视 那种吸引力法则 让毛孔被寒霜封锁 一个单纯的眼神 是想要的暖 有色眼镜的寒光 不喜欢更是...

  • 企业如何从内部提升确定性

    组织精简:精简公司数量,精简上下层级,精简部门、精简岗位,打造一个真正的精简高效组织。 授权灵活:越来越多的企业...

  • 复盘+反馈=成长助推器

    最近参加一个政府购买公共服务项目的评估,在查阅被评对象服务档案的时候,发现他们在撰写活动总结的时候,往往简短概述,...

  • 总结精简版

    1.HTML5中我们如何实现应用缓存? 首先我们需要指定”manifest”文件,“manifest”文件帮助你定...

  • GIT命令精简总结

    一、最基本命令 1. git配置 2. 创建文件夹与进入 3. 设置当前位置为git仓库 4. 添加至仓库(又名版...

  • 精简xpath定位总结

    原理: 基于html的文档目录结构进行定位元素。(如果对于html的DOM树结构不理解,可以百度一下,其实就是...

  • 20161204

    【极简】 本着信息极简的原则,对微博关注列表进行精简,精细分组,之后进行分组阅读。 取关了一季能总结出28部电视剧...

  • 2017-03-20晨读笔记

    三个一分钟 第一个一分钟,我理解为精简。说话精简,任务精简,目标精简。因为精简,所以目标更加清晰;因为精简,所以重...

网友评论

      本文标题:一个精简的微服务项目总结

      本文链接:https://www.haomeiwen.com/subject/fxbbjktx.html