微服务实战之春云与刀客(三)—— 面向接口调用代码结构实例
2018-01-05 00:00
567 查看
概述
在上一篇中提到了spring cloud 面向接口调用的开发风格,这一篇会举一个简单的但完整的例子来说明整个代码结构。代码已上传到 https://github.com/maruixiang/spring-cloud-demo/tree/master/demo1
代码结构
整个代码在demo1目录下面,包含了一个根级的parent pom文件和三个maven应用。
根pom文件:所有应用的parent pom文件。
eureka :注册中心,用于服务注册和发现。
demo :demo微服务,它本身包含了两个模块,demo-api提供给第三方使用的接口;demo-service是服务的具体实现。
为什么每个微服务多加了一层目录结构呢?因为从微服务职责划分来说,不同团队负责不同的微服务开发,每个微服务独立成项目,代码可以随时分离,不混合在一起。
client : 客户端调用服务。
每个应用maven代码结构可以通过http://start.spring.io/ 、IDE工具或手动生成,这里不多述。
统一的根级的pom.xml
这个文件是手工创建的,把spring boot基本信息都统一移到这里面来定义。spring-boot 1.5.7.RELEASE
spring-cloud Dalston.SR3 。
为了方便测试,我把三个应用的modules定义也放入了这里。而实际项目开发中,这个文件是不应该包含modules(实际开发中,这是一个基本不会修改的公共pom文件,不可能新加的微服务都放来来。正确做法是去掉modules,加入发布节点distributionManagement信息,把这个pom 通过mvn deploy 到maven 服务器上供所有的微服务使用即可)。
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.cehome.cloud</groupId> <artifactId>cehome-cloud-parent</artifactId> <version>1.0.0-SNAPSHOT</version> <packaging>pom</packaging> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.7.RELEASE</version> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>1.5.7.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Dalston.SR3</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <finalName>${project.artifactId}</finalName> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <modules> <module>eureka</module> <module>demo</module> <module>client</module> </modules> </project>
eureka注册中心
读音[ ju:`rika:]定义pom
继承spring-cloud-parent ,引入依赖 spring-cloud-starter-eureka-server即可<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.cehome.cloud</groupId> <artifactId>spring-cloud-parent</artifactId> <version>1.0.0-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> </parent> <groupId>com.cehome.cloud</groupId> <artifactId>eureka</artifactId> <version>1.0.0-SNAPSHOT</version> <packaging>jar</packaging> <name>eureka</name> <description>Demo project for Spring Boot</description> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka-server</artifactId> </dependency> </dependencies> </project>
添加spring配置
tomcat端口使用eureka约定的8761server.port=8761 spring.application.name=eureka eureka.client.serviceUrl.defaultZone = http://localhost:8761/eureka/ #是不是client?肯定不是啦。为true时,可以启动,但报异常:Cannot execute request on any known server eureka.client.fetch-registry=false #单注册中心设为false,集群是需要设为true以便多eureka互相同步 eureka.client.eureka-with-eureka=false
启动类
package com.cehome.cloud.eureka; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @EnableEurekaServer @SpringBootApplication public class EurekaApplication { public static void main(String[] args) { SpringApplication.run(EurekaApplication.class, args); } }
启动
运行main 方法,然后访问 http://localhost:8761/开发demo微服务
demo 本身是包含两个模块的maven应用,一个是api供第三方调用,一个是具体逻辑。接口模块 demo-api
因为需要用到Feign,所以引入Feign依赖即可。在pom文件中,还要引入spring-boot-thin-layout 一个很重要的maven插件。因为spring boot 缺省是编译成fat jar(60m左右),而api是要打成jar包给第三方使用的,如果打成一个spring boot结构的fat jar,第三方肯定无法使用了,所以引入了这个maven插件,会把api打成一个我们普通使用的jar包(可能就10多K),这样才能真正实现接口跟逻辑分离的效果。
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.cehome.cloud</groupId> <artifactId>demo-api</artifactId> <version>1.0.0-SNAPSHOT</version> <packaging>jar</packaging> <parent> <groupId>com.cehome.cloud</groupId> <artifactId>demo-parent</artifactId> <version>1.0.0-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> </parent> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> <scope>provided</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <dependencies> <dependency> <groupId>org.springframework.boot.experimental</groupId> <artifactId>spring-boot-thin-layout</artifactId> <version>1.0.5.RELEASE</version> </dependency> </dependencies> </plugin> </plugins> </build> </project>
定义接口类。接口就只有一个get()方法,访问后返回一个固定字符串。
package com.cehome.cloud.demo.api; import org.springframework.cloud.netflix.feign.FeignClient; import org.springframework.web.bind.annotation.RequestMapping; @FeignClient(name= "demo-service" ) public interface Demo1Service { @RequestMapping("/demo1/get") String get(); }
需要继续添加一个包含main()方法的类,这个可以随意定义。编译时spring boot 会取找一个main()方法,没有的话编译会报错。
package com.cehome.cloud.demo.api; public class DemoAPI { public static void main(String[] args) { } }
服务模块demo-service
定义pom.xml。除了spring-cloud-starter-eureka、spring-boot-starter-web、spring-cloud-starter-feign 这几个基本的微服务依赖,还要依赖上面定义的接口demo-api。<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.cehome.cloud</groupId> <artifactId>demo-service</artifactId> <version>1.0.0-SNAPSHOT</version> <packaging>jar</packaging> <name>demo-service</name> <description>Demo project for Spring Boot</description> <parent> <groupId>com.cehome.cloud</groupId> <artifactId>demo-parent</artifactId> <version>1.0.0-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> </parent> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> </dependency> <dependency> <groupId>com.cehome.cloud</groupId> <artifactId>demo-api</artifactId> <version>1.0.0-SNAPSHOT</version> </dependency> </dependencies> </project>
定义配置文件application.properties。 spring.application.name就是service Id,跟上面@Feign注解中的名字一样。
eureka.client.serviceUrl.defaultZone = http://localhost:8761/eureka/ server.port = 8762 spring.application.name = demo-service
实现main方法。
@EnableEurekaClient 让服务跟eureka注册中心关联,可以作为服务提供者也可以作为消费者。
package com.cehome.cloud.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.netflix.feign.EnableFeignClients; import org.springframework.context.annotation.ComponentScan; @SpringBootApplication //-- provider and consumer service @EnableEurekaClient @ComponentScan("com.cehome.cloud.demo") public class DemoServiceApplication { public static void main(String[] args) { SpringApplication.run(DemoServiceApplication.class); } }
继承Demo1Service 接口,实现服务Demo1ServiceImpl。注意这里的服务实际上是一个Controller,我们为了规范和便于管理,让其继承api中定义的接口Demo1Service ;且Demo1ServiceImpl的包名也是用service,不用controller,这就是一种约定,强调这是一个服务。
package com.cehome.cloud.demo.service; import com.cehome.cloud.demo.api.Demo1Service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RestController; @RestController public class Demo1ServiceImpl implements Demo1Service { @Override public String get() { return "This is Demo1 Service"; } }
验证。访问 http://localhost:8762/demo1/get
客户端调用
pom.xml<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <groupId>com.cehome.cloud</groupId> <artifactId>spring-cloud-parent</artifactId> <version>1.0.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <groupId>com.cehome.cloud</groupId> <artifactId>client</artifactId> <packaging>jar</packaging> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> </dependency> <dependency> <groupId>com.cehome.cloud</groupId> <artifactId>demo-api</artifactId> <version>1.0.0-SNAPSHOT</version> </dependency> </dependencies> </project>
application.properties
eureka.client.serviceUrl.defaultZone = http://localhost:8761/eureka/ server.port = 8763 spring.application.name = client-demo
spring boot主程序。
@EnableDiscoveryClient - 仅作为消费者(客户端),如果既作为消费端又同时作为服务提供者,则用@EnableEurekaClient。
@EnableFeignClients - 指定了Feign扫描api接口的范围。Feign扫描到包含@Feign注解的interface,然后会实例化一个spring代理bean,代理各种方法调用并转成URL发送请求。
package com.cehome.cloud.client; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.netflix.feign.EnableFeignClients; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.ComponentScan; import org.springframework.web.bind.annotation.RestController; @SpringBootApplication //-- consumer http://blog.didispace.com/spring-cloud-tips-feign-rpc/ @EnableDiscoveryClient @EnableFeignClients(basePackages = {"com.cehome.cloud"}) @RestController @ComponentScan("com.cehome.cloud.client") public class ClientApplication { public static void main(String[] args) { SpringApplication springApplication=new SpringApplication(ClientApplication.class); ConfigurableApplicationContext applicationContext=springApplication.run(args); } }
调用服务。可以看到,在pom.xml 引入demo-api后,通过
“@Autowired private Demo1Service demo1Service;” 方式,就像调用本地bean一样调用微服务。用户只要引入api jar包就行,不用关心服务部署在哪台机器,也不用care怎样拼接URL去调用服务,这是不是很符合java面向对象开发的要求?
阅读原文 http://click.aliyun.com/m/38898/
相关文章推荐
- 微服务实战之春云与刀客(三)—— 面向接口调用代码结构实例
- 微服务实战之春云与刀客(三)—— 面向接口调用代码结构实例
- 微服务实战之春云与刀客(二)—— Spring cloud 实现仿RPC面向接口调用方式
- 深入浅出微信公众平台实战开发(微网站、LBS云、Api接口调用、服务号高级接口)
- 基于php的银行卡实名认证接口调用代码实例
- eoLinker-API_Shop_短信服务接口-调用示例代码,支持PHP、Python、Java等语言
- 金蝶EAS,代码调用编码规则,注意上下文及接口实例
- 如何避免不同的用户调用接口时出现多个服务程序实例
- C#.NET 大型通用信息化系统集成快速开发平台 4.1 版本 - SOA面向安全的服务调用接口
- AXIS1客户端调用CXF服务接口-代码展示和问题解决
- springMVC框架下如何实现移动端接口调用——代码实例
- 基于php的基金财务数据接口调用代码实例
- Java编程实现NBA赛事接口调用实例代码
- 基于php的身份证实名认证接口调用代码实例
- Android(java)学习笔记229:服务(service)之绑定服务调用服务里面的方法 (采用接口隐藏代码内部实现)
- 代码笔记 | 基于Python的净值数据接口调用代码实例
- springcloud服务调用其它服务接口实例及ribbon均衡负载
- 基于JAVA的黄金数据接口调用代码实例
- php调用快递鸟接口实例代码
- 微服务实战之春云与刀客(一)—— 微服务开篇