目录
一、SpringMVC实现(未使用Dubbo)
这是比较low的微服务实现方式,多个服务之间通过RestTemplate走HTTP协议进行连接(一个服务的service调用另一个服务Controller)。
他的问题就在于不好管理,调用哪个哪个Controller实际上是通过URL区分的,要管理好这个Mapping的话,那根web.xml写servlet mapping有啥区别???
先贴一下代码,大家理解一下思想就行。
提供者(dubbo-demo-provider)
pom.xml
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.zzh</groupId>
<artifactId>dubbo-demo-provider</artifactId>
<packaging>war</packaging>
<version>1.0.0</version>
<name>dubbo-demo-provider Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.7.3</version>
</dependency>
</dependencies>
</project>
application.yaml
server:
port: 8082
SpringBoot启动程序
package com.zzh;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
public class ConsumerApplication {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class);
}
}
Controller
package com.zzh.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.zzh.service.impl.ConsumerUserImpl;
@RestController
public class UserController {
@Autowired
ConsumerUser ConsumerUser;
@GetMapping("/hello")
public String helloUser() {
return "你好," + ConsumerUser.consumerUser();
}
}
Service
package com.zzh.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.zzh.service.ConsumerUser;
@Service
public class ConsumerUser {
@Autowired
private RestTemplate restTemplate;
public String consumerUser() {
String user = restTemplate.getForObject("http://localhost:8081/user", String.class);
return user;
}
}
消费者 (dubbo-demo-consumer)
pom.xml
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.zzh</groupId>
<artifactId>dubbo-demo-consumer</artifactId>
<packaging>war</packaging>
<version>1.0.0</version>
<name>dubbo-demo-consumer Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.7.3</version>
</dependency>
</dependencies>
</project>
application.yaml
server:
port: 8081
SpringBoot启动程序
package com.zzh;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
public class ConsumerApplication {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class);
}
}
Controller
package com.zzh.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.zzh.service.impl.ConsumerUserImpl;
@RestController
public class UserController {
@Autowired
ConsumerUser ConsumerUser;
@GetMapping("/hello")
public String helloUser() {
return "你好," + ConsumerUser.consumerUser();
}
}
Service
package com.zzh.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.zzh.service.ConsumerUser;
@Service
public class ConsumerUser {
@Autowired
private RestTemplate restTemplate;
public String consumerUser() {
String user = restTemplate.getForObject("http://localhost:8081/user", String.class);
return user;
}
}
二、Dubbo(基于SpringBoot)
将上述项目改造为Dubbo项目。
Dubbo作为一个微服务框架,对我们开发人员最直接的理解就是,pom中导入了接口之后就可以像使用本地方法一样方便的调用其他微服务的方法。
Q:那么对于像我们这些初学者,和以往的单服务的MVC编码有什么不同呢?
A:配个项目里面装API,原来的Consumer和Provider的pom中导入API工程,剩下的正经的编码就只有注解变了。
先总结一下,为了让提供者的服务暴露给消费者,两种方式。
- 提供者打成Jar包丢进消费者pom.xml,但这样就不是真正微服务了
- 另建一个Maven工程,里面只放API,提供者和消费者都引入这个API工程
提供者(dubbo-demo-provider)
pom.xml
加入需要的依赖。
<!-- Dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>3.1.0</version>
</dependency>
<!-- RPC协议 -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-rpc-dubbo</artifactId>
<version>3.1.0</version>
</dependency>
<!-- Zookeeper注册中心 -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-zookeeper</artifactId>
<version>3.1.0</version>
</dependency>
<!-- API -->
<dependency>
<groupId>com.zzh</groupId>
<artifactId>dubbo-common</artifactId>
<version>1.0.0</version>
</dependency>
application.yaml
dubbo.application.name Dubbo程序名要唯一的
protocol.name 协议名选择dubbo,默认端口20880
regisdtry.address 注册中心使用Zookeeper,默认端口2181
server:
port: 8082
dubbo:
application:
name: provider-application-001
protocol:
name: dubbo
port: 20880
registry:
address: zookeeper://localhost:2181
SpringBoot启动程序
需要添加注解@EnableDubbo以实现Dubbo的配置并扫描Dubbo的组件类。
package com.zzh;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableDubbo /* (scanBasePackages = "com.zzh.service") */
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class);
}
}
Service
由原来的@Service注解修改为@DubboService,提供者只需要实现类来实现API,API工程会在后面提到。
package com.zzh.service.impl;
import org.apache.dubbo.config.annotation.DubboService;
import com.zzh.service.ProviderService;
@DubboService
public class ProviderServiceImpl implements ProviderService {
public String getUser() {
return "橙子宝宝";
}
}
消费者(dubbo-demo-consumer)
pom.xml
加入需要的依赖。
<!-- Dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>3.1.0</version>
</dependency>
<!-- RPC协议 -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-rpc-dubbo</artifactId>
<version>3.1.0</version>
</dependency>
<!-- Zookeeper注册中心 -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-zookeeper</artifactId>
<version>3.1.0</version>
</dependency>
<!-- API -->
<dependency>
<groupId>com.zzh</groupId>
<artifactId>dubbo-common</artifactId>
<version>1.0.0</version>
</dependency>
application.yaml
server:
port: 8081
dubbo:
application:
name: consumer-application-001
protocol:
name: dubbo
port: 20880
registry:
address: zookeeper://localhost:2181
SpringBoot启动程序
这里删掉了RestTemplate,因为不需要通过HTTP来连接服务了。
package com.zzh;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableDubbo /* (scanBasePackages = "com.zzh.service") */
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class);
}
}
Controller
这里都是本地调用,没什么好说的。
package com.zzh.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.zzh.service.ConsumerService;
@RestController
public class OrderController {
//@Resource(type = ConsumerServiceImpl.class) 也可以指定按类型装配
@Autowired
@Qualifier("consumerServiceImpl") //按id装配,默认名为类名首字母小写
private ConsumerService consumerService;
@GetMapping("/user")
public String getUser() {
return consumerService.getUser();
}
}
Service
本地的接口。
package com.zzh.service;
public interface ConsumerService {
String getUser();
}
实现本地的接口,并且服务消费者引用服务配置使用@DubboReference注解。
package com.zzh.service.impl;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;
import com.zzh.service.ConsumerService;
import com.zzh.service.ProviderService;
@Service
public class ConsumerServiceImpl implements ConsumerService {
@DubboReference
ProviderService providerService;
public String getUser() {
return providerService.getUser();
}
}
API(dubbo-common)
pom.xml
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.zzh</groupId>
<artifactId>dubbo-common</artifactId>
<version>1.0.0</version>
</project>
Service
只需要写暴露给提供者和消费者双方的接口就好了(他俩通过pom.xml引入)。
package com.zzh.service;
public interface ProviderService {
public String getUser();
}