Spring Cloud
SpringCloud
Eureka
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Hoxton.SR12</version> <type>pom</type> <scope>import</scope> </dependency>
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> <version>3.1.3</version> </dependency>
|
1 2 3 4 5 6 7
| @EnableEurekaServer @SpringBootApplication public class EurekaApplication { public static void main(String[] args) { SpringApplication.run(EurekaApplication.class,args); } }
|
1 2 3 4 5 6 7
| eureka: client: fetch-registry: false register-with-eureka: false service-url: defaultZone: http://localhost:自定义端口/eureka/
|
1 2 3 4 5
| eureka: client: service-url: defaultZone: http://localhost:自定义端口/eureka/·
|
访问地址:http://localhost:自定义端口
1 2 3 4 5 6 7 8 9 10 11 12
| @Configuration public class BeanConfiguration { @Bean @LoadBalanced public RestTemplate getRestTemplate(){ return new RestTemplate(); } }
restTemplate.getForObject("http://user-service/user/", 自定义.class);
|
LoadBalancer
1 2 3 4 5 6 7 8 9 10
| @Configuration public class LoadBalancerConfig { @Bean public ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory){ String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME); return new RandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class),name); } }
|
1 2 3 4 5 6 7 8 9
| @Configuration @LoadBalancerClient(value = "user-service",configuration = LoadBalancerConfig.class) public class BeanConfiguration { @Bean @LoadBalanced public RestTemplate getRestTemplate(){ return new RestTemplate(); } }
|
OpenFeign
1 2 3 4 5 6 7 8
| @SpringBootApplication @MapperScan("com.kuang.mapper") @EnableFeignClients public class BorrowApplication { public static void main(String[] args) { SpringApplication.run(BorrowApplication.class,args); } }
|
1 2 3 4 5 6 7 8 9 10 11 12
| @FeignClient("user-service") public interface UserClient {
@RequestMapping("/user/{uid}") User getUserByid(@PathVariable("uid") Integer uid); } @FeignClient("book-service") public interface BookServier { @RequestMapping("/book/{bid}") Book getBookByid(@PathVariable("bid") Integer bid); }
|
1 2 3 4 5 6 7 8 9
| @Autowired BookServier bookServier; @Autowired UserClient userClient;
User user = userClient.getBookByid(uid);
|
Hystrix 服务熔断
Hystrix
1 2 3 4 5
| <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> <version>2.2.10.RELEASE</version> </dependency>
|
1 2 3 4 5 6 7
| @EnableHystrix public class BorrowApplication { public static void main(String[] args) { SpringApplication.run(BorrowApplication.class,args); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @RestController public class BorrowController { @Autowired BorrowService borrowService; @HystrixCommand(fallbackMethod = "onError") @RequestMapping("/borrow/{uid}") public BorrowDetail getBorrowDetailByUid(@PathVariable("uid") Integer uid){ return borrowService.getBorrowDetailByUid(uid); }
BorrowDetail onError(int uid){ return new BorrowDetail(null, Collections.emptyList()); } }
|
OpenFeign
1 2 3
| feign: circuitbreaker: enabled: true
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @FeignClient(value = "user-service",fallback = UserFallbackClient.class) public interface UserClient {
@RequestMapping("/user/{uid}") User getUserByid(@PathVariable("uid") Integer uid); }
@Component public class UserFallbackClient implements UserClient { @Override public User getUserByid(Integer uid) { return new User(0,0,"error","error"); } }
|
监控
新建工程
1 2 3 4 5
| <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId> <version>2.2.10.RELEASE</version> </dependency>
|
1 2 3 4 5
| server: port: 8888 hystrix: dashboard: proxy-stream-allow-list: "localhost"
|
1 2 3 4 5 6 7
| @SpringBootApplication @EnableHystrixDashboard public class HystrixApplication { public static void main(String[] args) { SpringApplication.run(HystrixApplication.class,args); } }
|
在要监控的工程中
1 2 3 4
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
|
1 2 3 4 5
| management: endpoints: web: exposure: include: '*'
|
Hystrix Dashboard访问地址 http://localhost:port/hystrix
监控地址 http://localhost:服务端口/actuator/hystrix.stream
Gateway
1 2 3 4 5 6 7 8
| <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
|
1 2 3 4 5 6 7 8 9 10
| server: port: 9999
eureka: client: service-url: defaultZone: http://localhost:8400/eureka/ spring: application: name: gateway
|
路由过滤器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| @Component public class MyFilter implements GlobalFilter.Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpRequest request = exchange.getRequest(); // 判断是否包含某个参数 List<String> value = request.getQueryParams().get("key"); // 进行一些逻辑的判断 if (value!=null && value.contains("value")){ return chain.filter(exchange); }else { return exchange.getResponse().setComplete(); }
} @Override public int getOreder(){ return 0; } }
|
Config
1 2 3 4 5 6 7 8
| <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> </dependency>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| eureka: client: service-url: defaultZone: http://localhost:8400/eureka/ server: port: 1010 spring: application: name: config-service cloud: config: server: git: uri: default-label: main
|
1 2 3 4 5 6 7
| @EnableConfigServer @SpringBootApplication public class ConfigServerApplication { public static void main(String[] args) { SpringApplication.run(ConfigServerApplication.class,args); } }
|
http://ip:port/{git分支}/{服务名称}-{环境}.yml
http://ip:port/{服务名称}/{环境}/{git分支}
bootstrap.yaml
1 2 3 4 5 6 7 8
| <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bootstrap</artifactId> </dependency>
|
1 2 3 4 5 6 7
| spring: cloud: config: name: uri: profile: label:
|
SpringCloud Alibaba
nacos
dependencyManagement
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>2021.0.1</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2.0.2.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency>
|
子工程
1 2 3 4
| <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>
|
1 2 3 4 5 6
| spring: cloud: nacos: discovery: server-addr: localhost:8848
|
1 2 3 4 5 6 7 8
| <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency>
|
1 2 3 4 5 6
| @FeignClient("book-service") public interface BookClient {
@RequestMapping("/book/{bid}") Book getBookByid(@PathVariable("bid") Integer bid); }
|
1 2 3 4 5
| @FeignClient("user-service") public interface UserClient { @RequestMapping("/user/{uid}") User getUserByid(@PathVariable("uid") Integer uid); }
|
常驻服务
1 2 3 4 5
| spring: cloud: nacos: discovery: ephemeral: false
|
集群分区
1 2 3 4 5
| spring: cloud: nacos: discovery: cluster-name: name
|
LoadBalance
1 2 3 4 5
| spring: cloud: loadbalancer: nacos: enable: true
|
Config
1 2 3 4 5 6 7 8 9
| <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bootstrap</artifactId> <version>3.1.3</version> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>
|
bootstrap.yaml
1 2 3 4 5 6 7 8 9 10
| spring: application: name: user-service profiles: active: dev cloud: nacos: config: file-extension: yaml server-addr: localhost:8848
|
@RefreshScope
配置文件热更新
Sentinel
1 2 3 4 5 6 7 8 9 10
| <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> <exclusions> <exclusion> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> </exclusion> </exclusions> </dependency>
|
1 2 3 4 5
| spring: cloud: sentinel: transport: dashboard: localhost:8858
|
流量控制
@SentinelResource(value=自定义名称)
1 2 3 4
| spring: cloud: sentinel: web-context-unify: false
|
1 2 3 4 5 6 7 8
| @RequestMapping("/blocked") JSONObject blocked(){ JSONObject object = new JSONObject(); object.put("code",403); object.put("success",false); object.put("message","你的请求过快,请稍后再试!"); return object; }
|
1 2 3 4
| spring: cloud: sentinel: block-page: /blocked
|
1 2 3 4 5 6 7 8 9
| @SentinelResource(value=自定义名称,blockHandle="blocked")
public BorrowDetail getBorrowDetailByUid(Integer uid) { return new BorrowDetail(user,books); }
public BorrowDetail blocked(Integer uid,lockException e) { return new BorrowDetail(null,Collections.emptyList()); }
|
1 2 3
| feign: sentinel: enable: true
|
1 2 3 4 5 6
| @FeignClient(value = "user-service",fallback = UserClientImpl.class) public interface UserClient { @RequestMapping("/user/{uid}") User getUserByid(@PathVariable("uid") Integer uid); }
|
1 2 3 4 5 6 7 8 9
| @Component public class UserClientImpl implements UserClient { @Override public User getUserByid(Integer uid) { User user = new User(); user.setName("我是替代方案"); return user; } }
|
Seata
1 2 3 4
| <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-seata</artifactId> </dependency>
|
1 2 3 4 5 6 7 8
| seata: service: vgroup-mapping: book-service-seata-service-group: default grouplist: default: localhost:8868
|
每个服务的启动类上添加@EnableAutoDataSourceProxy
在需要支持事务的方法上添加@GlobalTransactional
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| create table `undo_log` ( `id` BIGINT(20) NOT NULL AUTO_INCREMENT, `branch_id` BIGINT(20) NOT NULL, `xid` VARCHAR(100) NOT NULL, `context` VARCHAR(128) NOT NULL, `rollback_info` LONGBLOB NOT NULL, `log_status` INT(11) NOT NULL, `log_created` DATETIME NOT NULL, `log_modified` DATETIME NOT NULL, `ext` VARCHAR(100) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`) )ENGINE = InnoDB AUTO_INCREMENT =1 DEFAULT CHARSET utf8;
|
中间件
OAuth2
1 2 3 4 5 6 7 8 9 10 11 12
| <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
|
1 2 3 4 5
| spring: session: store-type: redis redis: host: 180.76.100.158
|
验证服务器
1 2 3 4 5 6 7 8 9 10 11 12
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-oauth2</artifactId> </dependency>
|
1 2 3 4
| server: port: 8500 servlet: context-path: /sso
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| package com.kuang.config;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@Configuration public class SecurityConfiguration extends WebSecurityConfigurerAdapter { @SneakyThrows @Bean @Override public UserDetailsService userDetailsService(){ return super.userDetailsServiceBean(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); auth .inMemoryAuthentication() .passwordEncoder(encoder) .withUser("test").password(encoder.encode("123456")).roles("USER"); } @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); }
@Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest().authenticated() .and() .formLogin().permitAll();
} }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| package com.kuang.config;
import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import javax.annotation.Resource;
@EnableAuthorizationServer @Configuration public class OAuth2Configuration extends AuthorizationServerConfigurerAdapter {
@Resource private AuthenticationManager manager; @Resource UserDetailsService userDetailsService;
private final BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
@Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { security .passwordEncoder(encoder) .allowFormAuthenticationForClients() .checkTokenAccess("permitAll()"); }
@Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients .inMemory() .withClient("web") .secret(encoder.encode("654321")) .autoApprove(false) .scopes("book","user","borrow") .redirectUris("http://localhost:8100/login") .authorizedGrantTypes("client_credentials","password","implicit","authorization_code","refresh_token"); }
@Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints .userDetailsService(userDetailsService) .authenticationManager(manager); } }
|
基于@EnableOAthu2Sso实现
1 2 3 4 5 6 7 8
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-oauth2</artifactId> </dependency>
|
1 2 3 4 5 6 7 8 9 10 11 12
| security: oauth2: client: client-id: web client-secret: 654321 access-token-uri: http://localhost:8500/sso/oauth/token user-authorization-uri: http://localhost:8500/sso/oauth/authorize resource: token-info-uri: http://localhost:8500/sso/oauth/check_token
|
基于@EnableResourceServer实现
1 2 3 4 5 6 7 8
| security: oauth2: client: client-id: web client-secret: 654321 resource: token-info-uri: http://localhost:8500/sso/oauth/check_token
|
1 2 3 4 5 6 7 8 9
| @Configuration public class ResourceConfiguration extends ResourceServerConfigurerAdapter { @Override public void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest().access("#oauth2.hasScope('book')"); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Configuration public class WebConfiguration {
@Resource OAuth2ClientContext context;
@Bean public OAuth2RestTemplate restTemplate(){ return new OAuth2RestTemplate(new ClientCredentialsResourceDetails(),context); }
}
|
OpenFeign 整合 OAuth2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| @Configuration public class OAuth2FeignRequestInterceptor implements RequestInterceptor { private static final String AUTHORIZATION_HEADER = "Authorization";
private static final String BEARER_TOKEN_TYPE = "Bearer";
private final OAuth2RestTemplate oAuth2RestTemplate;
public OAuth2FeignRequestInterceptor(OAuth2RestTemplate oAuth2RestTemplate) { this.oAuth2RestTemplate = oAuth2RestTemplate; }
@Override public void apply(RequestTemplate requestTemplate) { requestTemplate.header(AUTHORIZATION_HEADER, String.format("%s %s", BEARER_TOKEN_TYPE, oAuth2RestTemplate.getAccessToken().toString())); }
}
|
JWT
验证服务器
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Configuration public class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Bean public JwtAccessTokenConverter tokenConverter(){ JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); converter.setSigningKey("kuang"); return converter; } @Bean public TokenStore tokenStore(JwtAccessTokenConverter converter){ return new JwtTokenStore(converter); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| @EnableAuthorizationServer @Configuration public class OAuth2Configuration extends AuthorizationServerConfigurerAdapter {
@Resource private AuthenticationManager manager;
@Resource UserDetailsService userDetailsService;
@Resource TokenStore store;
@Resource JwtAccessTokenConverter converter;
private AuthorizationServerTokenServices serverTokenServices(){ DefaultTokenServices services = new DefaultTokenServices(); services.setSupportRefreshToken(true); services.setTokenStore(store); services.setTokenEnhancer(converter); return services; } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints .tokenServices(serverTokenServices()) .userDetailsService(userDetailsService) .authenticationManager(manager); } }
|
资源服务器
1 2 3 4 5
| security: oauth2: resource: jwt: key-value: kuang
|
Redis
主从复制
老版本slaveof ip port
新版本replicaof ip port
解除slaveof no one
或者replicaof no one
哨兵模式
创建一个redis服务
配置文件只保留sentinel monitor 名称 ip port 1
启动时添加参数redis-servier --sentinel
ShardingJDVBC
分库
1 2 3 4 5
| <dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId> <version>5.1.0</version> </dependency>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| spring: shardingsphere: datasource: names: db0,db1 db0: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.jdbc.Driver jdbc-url: jdbc:mysql://180.76.100.158:3306/shardingstudy username: root password: Kuang001102 db1: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.jdbc.Driver jdbc-url: jdbc:mysql://180.76.100.158:3305/shardingstudy username: root password: Kuang001102 mybatis: mapper-locations: classpath:mapper/*.xml
|
1 2 3 4 5 6 7 8
| @Data @AllArgsConstructor @NonDeterministic public class User { int id; String name; String password; }
|
1 2 3 4 5 6
| public interface UserMapper {
User getUserById(int id);
int addUser(User user); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.kuang.mapper.UserMapper">
<select id="getUserById" resultType="com.kuang.entity.User"> select * from user where id = #{id} </select>
<insert id="addUser" parameterType="com.kuang.entity.User"> insert into user(id,name,password) values (#{id},#{name},#{password}) </insert> </mapper>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| spring: shardingsphere: datasource: names: db0,db1 db0: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.jdbc.Driver jdbc-url: jdbc:mysql://180.76.100.158:3306/shardingstudy username: root password: Kuang001102 db1: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.jdbc.Driver jdbc-url: jdbc:mysql://180.76.100.158:3305/shardingstudy username: root password: Kuang001102 rules: sharding: tables: #这里填写表的名称 test: #填写实际的路由节点 #简写 db$->{0..1].test actual-data-nodes: db0.user,db1.user #策略 database-strategy: #使用标准配置 standard: #参与分片运算的字段 sharding-column: id #自定义算法名称 sharding-algorithm-name: my-alg sharding-algorithms: #自定义算法名称 my-alg: #算法名称,官方提供了很多种 type: MOD props: sharding-count: 2 props: #开启日志,方便观察 sql-show: true
|
分表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| spring: shardingsphere: datasource: names: db0,db1 db0: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.jdbc.Driver jdbc-url: jdbc:mysql://180.76.100.158:3306/shardingstudy username: root password: Kuang001102 db1: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.jdbc.Driver jdbc-url: jdbc:mysql://180.76.100.158:3305/shardingstudy username: root password: Kuang001102 rules: sharding: tables: user: actual-data-nodes: db0.user,db1.user table-strategy: standard: sharding-column: id sharding-algorithm-name: my-alg sharding-algorithms: my-alg: type: INLINE props: algorithm-expression: test_$->{id % 2} allow-range-query-with-inline-sharding: false props: sql-show: true
|
分布式序列算法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| spring: shardingsphere: datasource: names: db0,db1 db0: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.jdbc.Driver jdbc-url: jdbc:mysql://180.76.100.158:3306/shardingstudy username: root password: Kuang001102 db1: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.jdbc.Driver jdbc-url: jdbc:mysql://180.76.100.158:3305/shardingstudy username: root password: Kuang001102 rules: sharding: tables: user: actual-data-nodes: db0.user,db1.user database-strategy: standard: sharding-column: id sharding-algorithm-name: my-alg key-generate-strategy: column: id key-generate-name: my-gen key-generators: my-gen: type: SNOWFLAKE props: worder-id: 666 sharding-algorithms: my-alg: type: MOD props: sharding-count: 2 props: sql-show: true
|
主键类型为long,int长度不够
读写分离
前提是配置了主从模式,从机并且配置了只读模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| spring: shardingsphere: datasource: names: db0,db1 db0: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.jdbc.Driver jdbc-url: jdbc:mysql://180.76.100.158:3306/shardingstudy username: root password: Kuang001102 db1: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.jdbc.Driver jdbc-url: jdbc:mysql://180.76.100.158:3305/shardingstudy username: root password: Kuang001102 rules: readwrite-splitting: data-sources: user-db: type: Static props: write-data-source-name: db0 read-data-source-names: db1 load-balancer-name: my-load load-balancers: my-load: type: ROUND_ROBIN sharding: tables: user: actual-data-nodes: db0.user,db1.user database-strategy: standard: sharding-column: id sharding-algorithm-name: my-alg key-generate-strategy: column: id key-generate-name: my-gen key-generators: my-gen: type: SNOWFLAKE props: worder-id: 666 sharding-algorithms: my-alg: type: MOD props: sharding-count: 2 props: sql-show: true
|
RabbitMQ
docker安装rabbitmq
1 2 3 4 5 6 7
| docker pull rabbitmq:management docker run -d -p 5672:5672 -p 15672:15672 --name rabbitmq --restart=always --hostname myRabbit rabbitmq:management docker exec -it rabbitmq rabbitmq-plugins enable rabbitmq_management rabbitmqctl add_user admin Kuang001102 rabbitmqctl set_user_tags admin administrator rabbitmqctl set_permissions -p "/" username ".*" ".*" ".*"
|
1 2 3 4 5
| <dependency> <groupId>com.rabbitmq</groupId> <artifactId>amqp-client</artifactId> <version>5.14.2</version> </dependency>
|
基本步骤
创建连接工厂
1 2 3 4 5 6
| ConnectionFactory factory = new ConnectionFactory(); factory.setHost("180.76.100.158"); factory.setPort(5672); factory.setUsername("admin"); factory.setPassword("Kuang001102"); factory.setVirtualHost("/");
|
创建连接
1 2
| connection = factory.newConnection("生产者");
|
创建连接通道
1 2
| channel = connection.createChannel();
|
创建交换机
1 2 3 4 5 6 7 8 9 10 11
| String exchangeName = "fanout-exchange"; String type = "fanout";
channel.exchangeDeclare(exchangeName, type, false, false, null);
|
创建消息队列
1 2 3 4 5 6 7 8 9
|
String queueName = "queue1"; channel.queueDeclare(queueName,false,false,false,null);
|
将交换机和消息队列绑定
1 2 3
| String routeKey = "";
channel.queueBind(queueName, exchangeName, routeKey);
|
发送消息
1 2 3 4 5 6 7 8 9 10 11 12
| String message = "hello world";
channel.basicPublish(exchangeName,queueName,routeKey,null,message.getBytes());
|
关闭连接
1 2
| channel.close(); connection.close();
|
简单模式
生产者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| public class Producer { public static void main(String[] args) { ConnectionFactory factory = new ConnectionFactory(); factory.setHost("180.76.100.158"); factory.setPort(5672); factory.setUsername("admin"); factory.setPassword("Kuang001102"); factory.setVirtualHost("/"); Connection connection =null; Channel channel = null; try { connection = factory.newConnection("生产者"); channel = connection.createChannel();
String queueName = "queue1"; channel.queueDeclare(queueName,false,false,false,null); String message = "hello world"; channel.basicPublish("",queueName,null,message.getBytes()); } catch (Exception e) { e.printStackTrace(); } finally { if (channel != null && channel.isOpen()){ try { channel.close(); } catch (Exception e) { e.printStackTrace(); } } if (connection != null && connection.isOpen()){ try { connection.close(); } catch (Exception e) { e.printStackTrace(); } } }
} }
|
消费者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| public class Consumer { public static void main(String[] args) { ConnectionFactory factory = new ConnectionFactory(); factory.setHost("180.76.100.158"); factory.setPort(5672); factory.setUsername("admin"); factory.setPassword("Kuang001102"); factory.setVirtualHost("/"); Connection connection =null; Channel channel = null; try { connection = factory.newConnection("生产者"); channel = connection.createChannel(); channel.basicConsume("queue1", true, new DeliverCallback() { @Override public void handle(java.lang.String s, Delivery delivery) throws IOException { System.out.println(delivery.getBody()); } }, new CancelCallback() { @Override public void handle(java.lang.String s) throws IOException { System.out.println("接收失败"); } }); } catch (Exception e) { e.printStackTrace(); } finally { if (channel != null && channel.isOpen()){ try { channel.close(); } catch (Exception e) { e.printStackTrace(); } } if (connection != null && connection.isOpen()){ try { connection.close(); } catch (Exception e) { e.printStackTrace(); } } } } }
|
Fanout模式
自定义交换机
自定义消息队列
交换机绑定消息队列
生产者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| package com.kuang.routing;
import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory;
public class Producer { public static void main(String[] args) { ConnectionFactory factory = new ConnectionFactory(); factory.setHost("180.76.100.158"); factory.setPort(5672); factory.setUsername("admin"); factory.setPassword("Kuang001102"); factory.setVirtualHost("/"); Connection connection =null; Channel channel = null; try { connection = factory.newConnection("生产者"); channel = connection.createChannel(); String message = "hello world"; String exchangeName = "fanout-exchange"; String type = "fanout"; String routeKey = ""; channel.basicPublish(exchangeName,routeKey,null,message.getBytes()); System.out.println("发送消息成功"); } catch (Exception e) { e.printStackTrace(); System.out.println("发送消息失败"); } finally { if (channel != null && channel.isOpen()){ try { channel.close(); } catch (Exception e) { e.printStackTrace(); } } if (connection != null && connection.isOpen()){ try { connection.close(); } catch (Exception e) { e.printStackTrace(); } } }
} }
|
消费者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| package com.kuang.routing;
import com.rabbitmq.client.*;
import java.io.IOException;
public class Consumer { public static Runnable runnable = new Runnable() { @Override public void run() { ConnectionFactory factory = new ConnectionFactory(); factory.setHost("180.76.100.158"); factory.setPort(5672); factory.setUsername("admin"); factory.setPassword("Kuang001102"); factory.setVirtualHost("/"); final java.lang.String queueName = Thread.currentThread().getName(); Connection connection =null; Channel channel = null; try { connection = factory.newConnection("生产者"); channel = connection.createChannel();
channel.basicConsume(queueName, true, new DeliverCallback() { @Override public void handle(java.lang.String s, Delivery delivery) throws IOException { System.out.println(queueName+"=======>"+new String(delivery.getBody(),"UTF-8")); System.in.read(); } }, new CancelCallback() { @Override public void handle(java.lang.String s) throws IOException { System.out.println("接收失败"); } }); } catch (Exception e) { e.printStackTrace(); } finally { if (channel != null && channel.isOpen()){ try { channel.close(); } catch (Exception e) { e.printStackTrace(); } } if (connection != null && connection.isOpen()){ try { connection.close(); } catch (Exception e) { e.printStackTrace(); } } } } };
public static void main(String[] args) { new Thread(runnable,"queue1").start(); new Thread(runnable,"queue2").start(); new Thread(runnable,"queue3").start(); } }
|
direct模式
1 2 3 4 5 6 7
|
String exchangeName = "direct-exchange";
String routeKey = "wechat";
channel.basicPublish(exchangeName,routeKey,null,message.getBytes());
|
topic模式
1 2 3 4 5 6 7 8 9
|
String exchangeName = "topic-exchange";
String routeKey = "com.email.wechat";
channel.basicPublish(exchangeName,routeKey,null,message.getBytes());
|
Springboot整合rabbitmq
1 2 3 4 5 6 7 8
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency> <dependency> <groupId>org.springframework.amqp</groupId> <artifactId>spring-rabbit-test</artifactId> </dependency>
|
1 2 3 4 5 6 7 8 9 10
| server: port: 8080
spring: rabbitmq: username: admin password: Kuang001102 virtual-host: / host: 180.76.100.158:22 port: 5672
|
生产者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| @Service public class OrderService { @Resource private RabbitTemplate rabbitTemplate;
public void makeOrder(String userId,String productId,int num){ String orderId = UUID.randomUUID().toString(); System.out.println("订单生成成功"); String exchangeName = "fanout_order_exchange"; String routingKey = ""; rabbitTemplate.convertAndSend(exchangeName,routingKey,orderId); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| @Configuration public class RabbitMQConfiguration { @Bean public FanoutExchange fanoutExchange(){ return new FanoutExchange("fanout_order_exchange",true,false); } @Bean public Queue smsQueue(){ return new Queue("sms.fanout.queue",true); } @Bean public Queue emailQueue(){ return new Queue("email.fanout.queue",true); } @Bean public Queue wechatQueue(){ return new Queue("wechat.fanout.queue",true); } @Bean public Binding smsBingding(){ return BindingBuilder.bind(smsQueue()).to(fanoutExchange()); } @Bean public Binding emailBingding(){ return BindingBuilder.bind(emailQueue()).to(fanoutExchange()); } @Bean public Binding wechatBingding(){ return BindingBuilder.bind(wechatQueue()).to(fanoutExchange()); } }
|
1
| orderService.makeOrder("1","1",12);
|
消费者
1 2 3 4 5 6 7 8
| @RabbitListener(queues = {"email.fanout.queue"}) @Service public class EmailConsumer { @RabbitHandler public void receiveMessage(String message){ System.out.println("email========>"+message); } }
|