1. How to deploy mysql in a container
2. How to deploy nacos in a container
In order not to expose my server address, this article uses localhost instead of the server address. All localhosts should be adjusted to your own server addresses.
In order not to expose my server address, this article uses localhost instead of the server address. All localhosts should be adjusted to your own server addresses.
Containerize nacos and implement service discovery
- Technologies used in this article: springclod, springcloudAlibaba, kotlin, jpa, gradle
Create project
-
Create empty project
-
Select jdk17, language level 17
New provider module
- Create a new module (named provider) and select spring 3.0.2
- Depend on adding spring data jpa, spring web, lombok
- Add mysql connection pool dependency
dependencies {<!-- --> // other denpendencies implementation 'mysql:mysql-connector-java:8.0.26' implementation("com.alibaba:druid:1.2.20") // other denpendencies }
- The mvn official website queries the import method of springcloud, and the github page of springcloud queries the version correspondence.
- mvn official website queries springcloudalibaba and introduces the corresponding version of springcloudalibaba
- Introducing spring-cloud-alibaba-nacos-discovery
ext {<!-- --> set('springCloudVersion', "2022.0.0") set('springCloudAlibabaVersion', "2022.0.0.0") // Set the version number of Spring Cloud Alibaba } repositories {<!-- --> //Alibaba source 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}" // Import Spring Cloud Alibaba BOM } }
-
Open server ports 8848 and 9848
-
Configure the application (just change the database address and account password)
spring: cloud: nacos: discovery: # nacos registration center address server-addr: 127.0.0.1:8848 username: nacos password: nacos #Microservice name application: name: depart-provider jpa: # Specify whether to create the table when the spring container starts, the default is false generate-ddl: true show-sql: true hibernate: # Specify not to re-update the table when the application is restarted ddl-auto: none # Turn off the lazy loading mechanism for front-end access open-in-view: false # Configure data source 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 & amp;autoReconnect=true & amp;useUnicode=true & amp;characterEncoding=UTF-8 & amp;allowMultiQueries=true & amp;useSSL= false username: root password: 'your_password' druid: #Initial number of connections initialSize: 5 #Minimum number of connection pools minIdle: 10 #Maximum number of connection pools maxActive: 20 #Configure the timeout to wait for the connection to be obtained maxWait: 60000 # Configure how often to detect idle connections that need to be closed. The unit is milliseconds. timeBetweenEvictionRunsMillis: 60000 # Configure the minimum survival time of a connection in the pool, the unit is milliseconds minEvictableIdleTimeMillis: 300000 # Configure the maximum survival time of a connection in the pool, in milliseconds maxEvictableIdleTimeMillis: 900000 #Configure to check whether the connection is valid validationQuery: SELECT 1 FROM DUAL testWhileIdle: true testOnBorrow: false testOnReturn: false # log logging: #Console log output format pattern: console: level-%level %msg%n level: #Control the log level displayed when springboot starts root: info # hibernate related log levels org.hibernate: info #Control the log level displayed when the code you write is run com.rdt:debug # Show-sql: true displays dynamic parameter values in sql org.hibernate.type.descriptor.sql.BasicBinder: trace # Display sql query results under the premise of show-sql: true org.hibernate.type.descriptor.sql.BasicExtractor: trace server: port: 8081 servlet: encoding: charset: utf-8 # Ensure character set is always applied force: true
New consumer module
- Create a new module (named provider) and select spring 3.0.2
- Depend on adding spring web and lombok
- Introduce the microservice dependencies introduced by provider0 (spring, springcloudalibaba, nacos-discovery)
ext {<!-- --> set('springCloudVersion', "2022.0.0") set('springCloudAlibabaVersion', "2022.0.0.0") // Set the version number of Spring Cloud Alibaba } repositories {<!-- --> //Alibaba source 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}" // Import Spring Cloud Alibaba BOM } }
- Configure consumer yml
spring: cloud: nacos: discovery: # nacos registration center address server-addr: 127.0.0.1:8848 username: nacos password: nacos #Microservice name application: name: depart-consumer
- After the above configuration is completed, start the provider and consumer. These two services can be found in nacos during registration.
- How to containerize configuration and start nacos is in the link at the beginning of the article
Communication between consumer and provider
provider code test
Just use the traditional three-tier architecture
- Entity class
package com.rdt.provider8081.bean import com.fasterxml.jackson.annotation.JsonIgnoreProperties import jakarta.persistence.Entity import jakarta.persistence.GeneratedValue import jakarta.persistence.GenerationType importjakarta.persistence.Id @Entity @JsonIgnoreProperties(value = ["hibernateLazyInitializer", "handler", "fieldHandler"]) class Depart {<!-- --> @Id @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Int? = null var name: String? = null }
- service layer
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 {<!-- --> returnDepart() } } fun modifyDepart(depart: Depart): Depart {<!-- --> if (departRepository.existsById(depart.id!!)) {<!-- --> return departRepository.save(depart) } returnDepart() } fun findAllDeparts() = departRepository.findAll() }
- persistence layer
package com.rdt.provider8081.repository import com.rdt.provider8081.bean.Depart import org.springframework.data.jpa.repository.JpaRepository interface DepartRepository :JpaRepository<Depart,Int>{<!-- --> }
- view layer
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> {<!-- --> //Get all service names val services: List<String> = discoveryClient.services for (service in services) {<!-- --> // Get all microservice instances with the specified microservice name 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 code testing
- Note that the current new version of springcloudAlibaba has deprecated ribbon, so load balancing needs to introduce dependencies.
- The consumer does not need a persistence layer. The consumer calls the provider and does not interact with the database.
dependencies{<!-- --> //nacos-discover introduction implementation 'org.springframework.cloud:spring-cloud-starter-loadbalancer:4.0.4' }
- entity layer
package com.rdt.consumer8080.bean class Depart {<!-- --> var id:Int?=null var name:String?=null }
- Configuration class
- Consumer needs configuration class, which needs to be used in the view layer
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 //Called in a load balancing manner @Bean public fun restTemplate():RestTemplate{<!-- --> return RestTemplate() } }
- view layer
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) {<!-- --> //Direct connection mode // final val SERVICE_PROVIDER_DEPART="http://localhost:8081/provider/depart/" //Microservice approach final val SERVICE_PROVIDER_DEPART="http://depart-provider/provider/depart/" //increase @PostMapping("/") fun saveHandle(@RequestBody depart:Depart):Boolean?{<!-- --> return template.postForObject(SERVICE_PROVIDER_DEPART, depart, Boolean::class.java) } //delete @DeleteMapping("/del/{id}") fun deleteHandle(@PathVariable("id") id:Int){<!-- --> val url=SERVICE_PROVIDER_DEPART + "del" template.delete(url + id) } //change @PutMapping("/") public fun updateHandle(@RequestBody depart: Depart){<!-- --> template.put(SERVICE_PROVIDER_DEPART,depart) } //Check a single @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) } //Check all @GetMapping("/list") fun listHandle():List<Depart>?{<!-- --> val url="$SERVICE_PROVIDER_DEPART/list" return template.getForObject(url,Array<Depart>::class.java)?.toList() } }
After these are completed, you can start the two services for testing.
If you have any questions, please feel free to message me privately, or add my contact information, I will be happy to communicate!