diff --git a/msb-mall/mall-commons/pom.xml b/msb-mall/mall-commons/pom.xml index a8d806e03..e18d6b279 100644 --- a/msb-mall/mall-commons/pom.xml +++ b/msb-mall/mall-commons/pom.xml @@ -56,6 +56,15 @@ com.alibaba.cloud spring-cloud-starter-alibaba-seata + + com.alibaba.cloud + spring-cloud-starter-alibaba-sentinel + + + org.springframework.boot + spring-boot-starter-actuator + 2.3.7.RELEASE + diff --git a/msb-mall/mall-coupon/pom.xml b/msb-mall/mall-coupon/pom.xml index 9205a2463..a02214169 100644 --- a/msb-mall/mall-coupon/pom.xml +++ b/msb-mall/mall-coupon/pom.xml @@ -21,6 +21,13 @@ com.msb.mall mall-commons 1.0-SNAPSHOT + + + javax.validation + validation-api + + + org.springframework.boot diff --git a/msb-mall/mall-coupon/src/main/java/com/msb/mall/coupon/MallCouponApplication.java b/msb-mall/mall-coupon/src/main/java/com/msb/mall/coupon/MallCouponApplication.java index 526cdad44..ff21fbb7a 100644 --- a/msb-mall/mall-coupon/src/main/java/com/msb/mall/coupon/MallCouponApplication.java +++ b/msb-mall/mall-coupon/src/main/java/com/msb/mall/coupon/MallCouponApplication.java @@ -3,10 +3,10 @@ package com.msb.mall.coupon; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; - +@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) @EnableDiscoveryClient -@SpringBootApplication @MapperScan("com.msb.mall.coupon.dao") public class MallCouponApplication { diff --git a/msb-mall/mall-coupon/src/main/java/com/msb/mall/coupon/controller/CouponController.java b/msb-mall/mall-coupon/src/main/java/com/msb/mall/coupon/controller/CouponController.java index 5530c9e90..ea3c8b9f3 100644 --- a/msb-mall/mall-coupon/src/main/java/com/msb/mall/coupon/controller/CouponController.java +++ b/msb-mall/mall-coupon/src/main/java/com/msb/mall/coupon/controller/CouponController.java @@ -3,6 +3,7 @@ package com.msb.mall.coupon.controller; import java.util.Arrays; import java.util.Map; +import com.msb.mall.coupon.datasource.ReadOnlyConnection; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; @@ -34,6 +35,7 @@ public class CouponController { * 列表 */ @RequestMapping("/list") + @ReadOnlyConnection public R list(@RequestParam Map params){ PageUtils page = couponService.queryPage(params); diff --git a/msb-mall/mall-coupon/src/main/java/com/msb/mall/coupon/datasource/DataSourceConfiguration.java b/msb-mall/mall-coupon/src/main/java/com/msb/mall/coupon/datasource/DataSourceConfiguration.java new file mode 100644 index 000000000..cd4c460ea --- /dev/null +++ b/msb-mall/mall-coupon/src/main/java/com/msb/mall/coupon/datasource/DataSourceConfiguration.java @@ -0,0 +1,47 @@ +package com.msb.mall.coupon.datasource; + +import com.zaxxer.hikari.HikariDataSource; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.jdbc.DataSourceBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import javax.sql.DataSource; +import java.util.HashMap; +import java.util.Map; + + +@Configuration +@EnableTransactionManagement +public class DataSourceConfiguration { + + @Bean(name = "masterDataSource") + @ConfigurationProperties(prefix = "spring.datasource.master") + public DataSource masterDataSource() { + return DataSourceBuilder.create().type(HikariDataSource.class).build(); + } + + @Bean(name = "slaveDataSource") + @ConfigurationProperties(prefix = "spring.datasource.slave") + public DataSource slaveDataSource() { + return DataSourceBuilder.create().type(HikariDataSource.class).build(); + } + + + @Bean("routingDataSource") + @Primary + public AbstractRoutingDataSource roundRobinDataSouceProxy() { + ReadWriteSplitRoutingDataSource proxy = new ReadWriteSplitRoutingDataSource(); + Map targetDataResources = new HashMap<>(); + DataSource masterDataSource = masterDataSource(); + targetDataResources.put(DbContextHolder.DbType.MASTER, masterDataSource); + DataSource slaveDataSource = slaveDataSource(); + targetDataResources.put(DbContextHolder.DbType.SLAVE, slaveDataSource); + proxy.setDefaultTargetDataSource(masterDataSource);//默认源 + proxy.setTargetDataSources(targetDataResources); + return proxy; + } +} diff --git a/msb-mall/mall-coupon/src/main/java/com/msb/mall/coupon/datasource/DbContextHolder.java b/msb-mall/mall-coupon/src/main/java/com/msb/mall/coupon/datasource/DbContextHolder.java new file mode 100644 index 000000000..beacff8be --- /dev/null +++ b/msb-mall/mall-coupon/src/main/java/com/msb/mall/coupon/datasource/DbContextHolder.java @@ -0,0 +1,25 @@ +package com.msb.mall.coupon.datasource; + +public class DbContextHolder { + + public enum DbType{ + MASTER,SLAVE + } + + private static final ThreadLocal contextHolder = new ThreadLocal<>(); + + public static void setDbType(DbType dbType){ + if(dbType==null)throw new NullPointerException(); + contextHolder.set(dbType); + } + + public static DbType getDbType(){ + DbType dbType = contextHolder.get(); + return dbType ==null? DbType.MASTER: dbType; + } + + public static void clearDbType(){ + contextHolder.remove(); + } + +} diff --git a/msb-mall/mall-coupon/src/main/java/com/msb/mall/coupon/datasource/ReadOnlyConnection.java b/msb-mall/mall-coupon/src/main/java/com/msb/mall/coupon/datasource/ReadOnlyConnection.java new file mode 100644 index 000000000..13a90a875 --- /dev/null +++ b/msb-mall/mall-coupon/src/main/java/com/msb/mall/coupon/datasource/ReadOnlyConnection.java @@ -0,0 +1,14 @@ +package com.msb.mall.coupon.datasource; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 该注解注释在service方法上,标注为链接slaves库 + */ +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface ReadOnlyConnection { +} diff --git a/msb-mall/mall-coupon/src/main/java/com/msb/mall/coupon/datasource/ReadOnlyConnectionInterceptor.java b/msb-mall/mall-coupon/src/main/java/com/msb/mall/coupon/datasource/ReadOnlyConnectionInterceptor.java new file mode 100644 index 000000000..f826c99c2 --- /dev/null +++ b/msb-mall/mall-coupon/src/main/java/com/msb/mall/coupon/datasource/ReadOnlyConnectionInterceptor.java @@ -0,0 +1,29 @@ +package com.msb.mall.coupon.datasource; + + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.core.Ordered; +import org.springframework.stereotype.Component; + +@Aspect +@Component +public class ReadOnlyConnectionInterceptor implements Ordered { + + @Around("@annotation(readOnlyConnection)") + public Object proceed(ProceedingJoinPoint proceedingJoinPoint, ReadOnlyConnection readOnlyConnection) throws Throwable { + try { + DbContextHolder.setDbType(DbContextHolder.DbType.SLAVE); + return proceedingJoinPoint.proceed(); + } finally { + DbContextHolder.clearDbType(); + } + } + + + @Override + public int getOrder() { + return 0; + } +} diff --git a/msb-mall/mall-coupon/src/main/java/com/msb/mall/coupon/datasource/ReadWriteSplitRoutingDataSource.java b/msb-mall/mall-coupon/src/main/java/com/msb/mall/coupon/datasource/ReadWriteSplitRoutingDataSource.java new file mode 100644 index 000000000..ee7c31a53 --- /dev/null +++ b/msb-mall/mall-coupon/src/main/java/com/msb/mall/coupon/datasource/ReadWriteSplitRoutingDataSource.java @@ -0,0 +1,17 @@ +package com.msb.mall.coupon.datasource; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; + +/** + */ +public class ReadWriteSplitRoutingDataSource extends AbstractRoutingDataSource { + protected final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public Object determineCurrentLookupKey() { + return DbContextHolder.getDbType(); + } + +} diff --git a/msb-mall/mall-coupon/src/main/resources/application.yml b/msb-mall/mall-coupon/src/main/resources/application.yml index 2a68a1abb..0adce27c5 100644 --- a/msb-mall/mall-coupon/src/main/resources/application.yml +++ b/msb-mall/mall-coupon/src/main/resources/application.yml @@ -1,9 +1,17 @@ spring: datasource: - username: root - password: root - url: jdbc:mysql://192.168.37.133:3306/msb-sms?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai - driver-class-name: com.mysql.cj.jdbc.Driver + master: + username: root + password: root + host: 192.168.37.133:3306 + jdbc-url: jdbc:mysql://${spring.datasource.master.host}/${spring.datasource.master.schema-name}?useUnicode=true&characterEncoding=utf8&useSSL=false + schema-name: msb-sms + slave: + username: root + password: root + host: 192.168.37.134:3306 + jdbc-url: jdbc:mysql://${spring.datasource.slave.host}/${spring.datasource.slave.schema-name}?useUnicode=true&characterEncoding=utf8&useSSL=false + schema-name: msb-sms cloud: nacos: discovery: diff --git a/msb-mall/mall-producet/src/main/java/com/msb/mall/product/MallProducetApplication.java b/msb-mall/mall-producet/src/main/java/com/msb/mall/product/MallProducetApplication.java index d52b5ed66..82bf49878 100644 --- a/msb-mall/mall-producet/src/main/java/com/msb/mall/product/MallProducetApplication.java +++ b/msb-mall/mall-producet/src/main/java/com/msb/mall/product/MallProducetApplication.java @@ -2,14 +2,18 @@ package com.msb.mall.product; import org.apache.ibatis.annotations.Mapper; import org.mybatis.spring.annotation.MapperScan; +import org.redisson.spring.session.config.EnableRedissonHttpSession; +import org.redisson.spring.session.config.EnableRedissonWebSession; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.cache.annotation.EnableCaching; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; //@EnableDiscoveryClient +@EnableRedissonHttpSession @EnableCaching -@SpringBootApplication +@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) @MapperScan("com.msb.mall.product.dao") public class MallProducetApplication { diff --git a/msb-mall/mall-producet/src/main/java/com/msb/mall/product/controller/BrandController.java b/msb-mall/mall-producet/src/main/java/com/msb/mall/product/controller/BrandController.java index e409f882d..292cc9295 100644 --- a/msb-mall/mall-producet/src/main/java/com/msb/mall/product/controller/BrandController.java +++ b/msb-mall/mall-producet/src/main/java/com/msb/mall/product/controller/BrandController.java @@ -4,6 +4,7 @@ import java.util.Arrays; import java.util.Map; +import com.msb.mall.product.datasource.ReadOnlyConnection; import com.msb.mall.product.entity.CategoryBrandRelationEntity; import com.msb.mall.product.service.CategoryBrandRelationService; import org.springframework.beans.factory.annotation.Autowired; @@ -57,6 +58,7 @@ public class BrandController { */ @Cacheable("category") @RequestMapping("/list") + @ReadOnlyConnection public R list(@RequestParam Map params){ System.out.println("==================>params = " + params); PageUtils page = brandService.queryPage(params); diff --git a/msb-mall/mall-producet/src/main/java/com/msb/mall/product/datasource/DataSourceConfiguration.java b/msb-mall/mall-producet/src/main/java/com/msb/mall/product/datasource/DataSourceConfiguration.java new file mode 100644 index 000000000..5119bbc22 --- /dev/null +++ b/msb-mall/mall-producet/src/main/java/com/msb/mall/product/datasource/DataSourceConfiguration.java @@ -0,0 +1,47 @@ +package com.msb.mall.product.datasource; + +import com.zaxxer.hikari.HikariDataSource; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.jdbc.DataSourceBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import javax.sql.DataSource; +import java.util.HashMap; +import java.util.Map; + + +@Configuration +@EnableTransactionManagement +public class DataSourceConfiguration { + + @Bean(name = "masterDataSource") + @ConfigurationProperties(prefix = "spring.datasource.master") + public DataSource masterDataSource() { + return DataSourceBuilder.create().type(HikariDataSource.class).build(); + } + + @Bean(name = "slaveDataSource") + @ConfigurationProperties(prefix = "spring.datasource.slave") + public DataSource slaveDataSource() { + return DataSourceBuilder.create().type(HikariDataSource.class).build(); + } + + + @Bean("routingDataSource") + @Primary + public AbstractRoutingDataSource roundRobinDataSouceProxy() { + ReadWriteSplitRoutingDataSource proxy = new ReadWriteSplitRoutingDataSource(); + Map targetDataResources = new HashMap<>(); + DataSource masterDataSource = masterDataSource(); + targetDataResources.put(DbContextHolder.DbType.MASTER, masterDataSource); + DataSource slaveDataSource = slaveDataSource(); + targetDataResources.put(DbContextHolder.DbType.SLAVE, slaveDataSource); + proxy.setDefaultTargetDataSource(masterDataSource);//默认源 + proxy.setTargetDataSources(targetDataResources); + return proxy; + } +} diff --git a/msb-mall/mall-producet/src/main/java/com/msb/mall/product/datasource/DbContextHolder.java b/msb-mall/mall-producet/src/main/java/com/msb/mall/product/datasource/DbContextHolder.java new file mode 100644 index 000000000..d77c6593c --- /dev/null +++ b/msb-mall/mall-producet/src/main/java/com/msb/mall/product/datasource/DbContextHolder.java @@ -0,0 +1,25 @@ +package com.msb.mall.product.datasource; + +public class DbContextHolder { + + public enum DbType{ + MASTER,SLAVE + } + + private static final ThreadLocal contextHolder = new ThreadLocal<>(); + + public static void setDbType(DbType dbType){ + if(dbType==null)throw new NullPointerException(); + contextHolder.set(dbType); + } + + public static DbType getDbType(){ + DbType dbType = contextHolder.get(); + return dbType ==null? DbType.MASTER: dbType; + } + + public static void clearDbType(){ + contextHolder.remove(); + } + +} diff --git a/msb-mall/mall-producet/src/main/java/com/msb/mall/product/datasource/ReadOnlyConnection.java b/msb-mall/mall-producet/src/main/java/com/msb/mall/product/datasource/ReadOnlyConnection.java new file mode 100644 index 000000000..856e69cd3 --- /dev/null +++ b/msb-mall/mall-producet/src/main/java/com/msb/mall/product/datasource/ReadOnlyConnection.java @@ -0,0 +1,15 @@ +package com.msb.mall.product.datasource; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 该注解注释在service方法上,标注为链接slaves库 + * Created by Dulingling on 2019/8/7 + */ +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface ReadOnlyConnection { +} diff --git a/msb-mall/mall-producet/src/main/java/com/msb/mall/product/datasource/ReadOnlyConnectionInterceptor.java b/msb-mall/mall-producet/src/main/java/com/msb/mall/product/datasource/ReadOnlyConnectionInterceptor.java new file mode 100644 index 000000000..8f40c376c --- /dev/null +++ b/msb-mall/mall-producet/src/main/java/com/msb/mall/product/datasource/ReadOnlyConnectionInterceptor.java @@ -0,0 +1,29 @@ +package com.msb.mall.product.datasource; + + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.core.Ordered; +import org.springframework.stereotype.Component; + +@Aspect +@Component +public class ReadOnlyConnectionInterceptor implements Ordered { + + @Around("@annotation(readOnlyConnection)") + public Object proceed(ProceedingJoinPoint proceedingJoinPoint, ReadOnlyConnection readOnlyConnection) throws Throwable { + try { + DbContextHolder.setDbType(DbContextHolder.DbType.SLAVE); + return proceedingJoinPoint.proceed(); + } finally { + DbContextHolder.clearDbType(); + } + } + + + @Override + public int getOrder() { + return 0; + } +} diff --git a/msb-mall/mall-producet/src/main/java/com/msb/mall/product/datasource/ReadWriteSplitRoutingDataSource.java b/msb-mall/mall-producet/src/main/java/com/msb/mall/product/datasource/ReadWriteSplitRoutingDataSource.java new file mode 100644 index 000000000..37067acfc --- /dev/null +++ b/msb-mall/mall-producet/src/main/java/com/msb/mall/product/datasource/ReadWriteSplitRoutingDataSource.java @@ -0,0 +1,18 @@ +package com.msb.mall.product.datasource; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; + +/** + * Created by Dulingling on 2019/8/7 + */ +public class ReadWriteSplitRoutingDataSource extends AbstractRoutingDataSource { + protected final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public Object determineCurrentLookupKey() { + return DbContextHolder.getDbType(); + } + +} diff --git a/msb-mall/mall-producet/src/main/resources/application.yml b/msb-mall/mall-producet/src/main/resources/application.yml index 52e851a57..58e068878 100644 --- a/msb-mall/mall-producet/src/main/resources/application.yml +++ b/msb-mall/mall-producet/src/main/resources/application.yml @@ -8,10 +8,17 @@ base: password: root #your mysql server password spring: datasource: - username: root - password: root - url: jdbc:mysql://192.168.37.133:3306/msb-pms?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai - driver-class-name: com.mysql.cj.jdbc.Driver + master: + username: root + password: root + url: jdbc:mysql://192.168.37.133:3306/msb-pms?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai + driver-class-name: com.mysql.cj.jdbc.Driver + slave: + username: root + password: root + url: jdbc:mysql://192.168.37.134:3306/msb-pms?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai + driver-class-name: com.mysql.cj.jdbc.Driver + cloud: nacos: discovery: @@ -34,6 +41,10 @@ spring: type: redis redis: time-to-live: 60000 + session: + store-type: redis + redis: + namespace: spring:session mybatis-plus: mapper-locations: classpath*:/mapper/**/*.xml global-config: diff --git a/msb-mall/mall-search/src/main/java/com/msb/mall/mallsearch/controller/TestController.java b/msb-mall/mall-search/src/main/java/com/msb/mall/mallsearch/controller/TestController.java new file mode 100644 index 000000000..25606fc3f --- /dev/null +++ b/msb-mall/mall-search/src/main/java/com/msb/mall/mallsearch/controller/TestController.java @@ -0,0 +1,17 @@ +package com.msb.mall.mallsearch.controller; + +import com.msb.mall.commons.util.R; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("test") +public class TestController { + + @GetMapping("all") + public R testApi(){ + System.out.println("=====>testApi"); + return R.ok().put("test","testApi"); + } +} diff --git a/msb-mall/mall-search/src/main/resources/application.yml b/msb-mall/mall-search/src/main/resources/application.yml index 89bba66ef..cf72407a7 100644 --- a/msb-mall/mall-search/src/main/resources/application.yml +++ b/msb-mall/mall-search/src/main/resources/application.yml @@ -1,9 +1,19 @@ spring: cloud: + sentinel: + transport: + dashboard: localhost:8080 + port: 8719 + eager: true nacos: discovery: server-addr: 192.168.37.133:8848 application: name: mall-search server: - port: 8090 \ No newline at end of file + port: 8090 +management: + endpoints: + web: + exposure: + include: '*' \ No newline at end of file