1.如何容器化部署mysql
2. 如何容器化部署nacos
为不暴露我的服务器地址,本文全部使用localhost来代替服务器地址,所有的localhost都应该调整为你自己的服务器地址。
为不暴露我的服务器地址,本文全部使用localhost来代替服务器地址,所有的localhost都应该调整为你自己的服务器地址。
容器化nacos并实现服务发现
- 本文使用技术:springclod、springcloudAlibaba、kotlin、jpa、gradle
创建项目
-
创建empty project
-
选择jdk17、语言等级17
新建provider模块
- 新建模块(命名为provider) 选择spring 3.0.2
- 依赖添加spring data jpa、spring web、lombok
- 添加mysql连接池依赖
dependencies {
// other denpendencies
implementation 'mysql:mysql-connector-java:8.0.26'
implementation("com.alibaba:druid:1.2.20")
// other denpendencies
}
- mvn官网查询springcloud的导入方式,springcloud的github页面查询版本对应关系
- mvn官网查询springcloudalibaba,引入springcloudalibaba对应版本
- 引入spring-cloud-alibaba-nacos-discovery
ext {
set('springCloudVersion', "2022.0.0")
set('springCloudAlibabaVersion', "2022.0.0.0") // 设置Spring Cloud Alibaba的版本号
}
repositories {
//阿里源
maven { url 'https://maven.aliyun.com/repository/public' }
mavenCentral()
}
dependencies {
...
implementation 'com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-discovery:2022.0.0.0'
...
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
mavenBom "com.alibaba.cloud:spring-cloud-alibaba-dependencies:${springCloudAlibabaVersion}" // 导入Spring Cloud Alibaba BOM
}
}
-
开放服务器8848、9848端口
-
配置application(更改数据库地址和账户密码即可)
spring:
cloud:
nacos:
discovery:
# nacos注册中心地址
server-addr: 127.0.0.1:8848
username: nacos
password: nacos
# 微服务名称
application:
name: depart-provider
jpa:
# 指定是否在spring容器启动时创建表,默认false
generate-ddl: true
show-sql: true
hibernate:
# 指定应用重启时不重新更新表
ddl-auto: none
# 关闭前端访问的懒加载机制
open-in-view: false
# 配置数据源
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1/rdtcloud?serverTimezone=Asia/Shanghai&autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false
username: root
password: 'your_password'
druid:
# 初始连接数
initialSize: 5
# 最小连接池数量
minIdle: 10
# 最大连接池数量
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 300000
# 配置一个连接在池中最大生存的时间,单位是毫秒
maxEvictableIdleTimeMillis: 900000
# 配置检测连接是否有效
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
# 日志
logging:
# 控制台日志输出格式
pattern:
console: level-%level %msg%n
level:
# 控制springboot 启动时显示的日志级别
root: info
# hibernate相关的日志级别
org.hibernate: info
# 控制自己写的代码运行时显示的日志级别
com.rdt: debug
# show-sql: true 的前提下显示sql中的动态参数值
org.hibernate.type.descriptor.sql.BasicBinder: trace
# show-sql: true 的前提下显示sql的查询结果
org.hibernate.type.descriptor.sql.BasicExtractor: trace
server:
port: 8081
servlet:
encoding:
charset: utf-8
# 确保字符集总是被应用
force: true
新建consumer模块
- 新建模块(命名为provider) 选择spring 3.0.2
- 依赖添加spring web、lombok
- 引入provider0引入的微服务依赖内容(spring、springcloudalibaba、nacos-discovery)
ext {
set('springCloudVersion', "2022.0.0")
set('springCloudAlibabaVersion', "2022.0.0.0") // 设置Spring Cloud Alibaba的版本号
}
repositories {
//阿里源
maven { url 'https://maven.aliyun.com/repository/public' }
mavenCentral()
}
dependencies {
...
implementation 'com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-discovery:2022.0.0.0'
...
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
mavenBom "com.alibaba.cloud:spring-cloud-alibaba-dependencies:${springCloudAlibabaVersion}" // 导入Spring Cloud Alibaba BOM
}
}
- 配置consumer的yml
spring:
cloud:
nacos:
discovery:
# nacos注册中心地址
server-addr: 127.0.0.1:8848
username: nacos
password: nacos
# 微服务名称
application:
name: depart-consumer
- 以上配置完成,启动provider和consumer,可以在注册中nacos中找到这两个服务
- 如何容器化配置并启动nacos在文章开头的链接中
consumer和provider通信
provider代码测试
使用传统的三层架构就可以
- 实体类
package com.rdt.provider8081.bean
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import jakarta.persistence.Entity
import jakarta.persistence.GeneratedValue
import jakarta.persistence.GenerationType
import jakarta.persistence.Id
@Entity
@JsonIgnoreProperties(value = ["hibernateLazyInitializer", "handler", "fieldHandler"])
class Depart {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Int? = null
var name: String? = null
}
- 服务层
package com.rdt.provider8081.service
import com.rdt.provider8081.bean.Depart
import com.rdt.provider8081.repository.DepartRepository
import lombok.RequiredArgsConstructor
import org.springframework.stereotype.Service
@Service
@RequiredArgsConstructor
class DepartService(private val departRepository: DepartRepository) {
fun saveDepart(depart: Depart) = departRepository.save(depart)
fun removeDepart(id: Int) {
if (departRepository.existsById(id) != null)
departRepository.deleteById(id)
}
fun getDepartById(id: Int): Depart {
if (departRepository.existsById(id)) {
return departRepository.getReferenceById(id)
} else {
return Depart()
}
}
fun modifyDepart(depart: Depart): Depart {
if (departRepository.existsById(depart.id!!)) {
return departRepository.save(depart)
}
return Depart()
}
fun findAllDeparts() = departRepository.findAll()
}
- 持久层
package com.rdt.provider8081.repository
import com.rdt.provider8081.bean.Depart
import org.springframework.data.jpa.repository.JpaRepository
interface DepartRepository :JpaRepository<Depart,Int>{
}
- 视图层
package com.rdt.provider8081.controller
import com.rdt.provider8081.bean.Depart
import com.rdt.provider8081.service.DepartService
import lombok.RequiredArgsConstructor
import org.springframework.cloud.client.discovery.DiscoveryClient
import org.springframework.web.bind.annotation.*
@RestController
@RequiredArgsConstructor
@RequestMapping("/provider/depart")
class DepartController(
private val departService: DepartService, private val discoveryClient: DiscoveryClient
) {
@PostMapping("/")
fun saveHandle(@RequestBody depart: Depart) {
println(depart.name)
departService.saveDepart(depart)
}
@DeleteMapping("/{id}")
fun deleteHandle(@PathVariable("id") id: Int) {
return departService.removeDepart(id)
}
@PutMapping("/")
fun updateHandle(@RequestBody depart: Depart) = departService
@GetMapping("/get/{id}")
fun getHandle(@PathVariable id: Int) = departService.getDepartById(id)
@GetMapping("/list")
fun listHandle() = departService.findAllDeparts()
@GetMapping("/discovery")
fun discoveryHandle(): List<String> {
//获取所有的服务名称
val services: List<String> = discoveryClient.services
for (service in services) {
// 获取指定微服务名称的所有微服务实例
var instances = discoveryClient.getInstances(service)
for (instance in instances) {
// val map = HashMap<String, Any>()
val map = mutableMapOf<String, Any>()
map["serviceName"] = service
map["serviceId"] = instance.serviceId
map["serviceHost"] = instance.host
map["servicePort"] = instance.port
map["uri"] = instance.uri
println(map)
}
}
return services
}
}
Consumer代码测试
- 注意,目前新版的springcloudAlibaba已经弃用了ribbon,所以负载均衡需要引入依赖
- consumer不需要持久层,consumer是调用provider的,它不与数据库交互
dependencies{
//nacos-discover引入
implementation 'org.springframework.cloud:spring-cloud-starter-loadbalancer:4.0.4'
}
- 实体层
package com.rdt.consumer8080.bean
class Depart {
var id:Int?=null
var name:String?=null
}
- 配置类
- consumer需要配置类,在视图层需要使用
package com.rdt.consumer8080.config
import org.springframework.cloud.client.loadbalancer.LoadBalanced
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.web.client.RestTemplate
@Configuration
class DepartConfig {
@LoadBalanced //以负载均衡的方式调用
@Bean
public fun restTemplate():RestTemplate{
return RestTemplate()
}
}
- 视图层
package com.rdt.consumer8080.controller
import com.google.gson.GsonBuilder
import com.rdt.consumer8080.bean.Depart
import com.rdt.consumer8080.consts.ConstTime
import lombok.RequiredArgsConstructor
import org.springframework.core.ParameterizedTypeReference
import org.springframework.web.bind.annotation.DeleteMapping
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.PutMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.client.RestTemplate
import org.springframework.web.client.getForObject
@RestController
@RequestMapping("/consumer/depart")
@RequiredArgsConstructor
class DepartController(private val template:RestTemplate) {
//直连方式
// final val SERVICE_PROVIDER_DEPART="http://localhost:8081/provider/depart/"
//微服务方式
final val SERVICE_PROVIDER_DEPART="http://depart-provider/provider/depart/"
//增
@PostMapping("/")
fun saveHandle(@RequestBody depart:Depart):Boolean?{
return template.postForObject(SERVICE_PROVIDER_DEPART, depart, Boolean::class.java)
}
//删
@DeleteMapping("/del/{id}")
fun deleteHandle(@PathVariable("id") id:Int){
val url=SERVICE_PROVIDER_DEPART+"del"
template.delete(url+id)
}
//改
@PutMapping("/")
public fun updateHandle(@RequestBody depart: Depart){
template.put(SERVICE_PROVIDER_DEPART,depart)
}
//查单个
@GetMapping("/get/{id}")
fun getHandle(@PathVariable("id") id:Int):Depart?{
val url:String= "$SERVICE_PROVIDER_DEPART/get/$id"
return template.getForObject(url,Depart::class.java)
}
//查全部
@GetMapping("/list")
fun listHandle():List<Depart>?{
val url="$SERVICE_PROVIDER_DEPART/list"
return template.getForObject(url,Array<Depart>::class.java)?.toList()
}
}
这些都完成之后就可以启动两个服务进行测试了。
有任何问题欢迎私信我,或者添加我的联系方式,我会很乐于交流!