├── .gitignore ├── README.md ├── common ├── pom.xml └── src │ └── main │ └── java │ └── top │ └── ylonline │ └── common │ ├── cache │ ├── annotation │ │ └── Expired.java │ ├── interceptor │ │ ├── TCacheErrorHandler.java │ │ ├── TCacheResolver.java │ │ └── TKeyGenerator.java │ └── util │ │ └── CacheUtils.java │ └── util │ └── StrUtils.java ├── dom4j-example ├── README.md ├── pom.xml └── src │ ├── main │ └── java │ │ └── top │ │ └── ylonline │ │ └── dom4j │ │ ├── Dom4jUtils.java │ │ └── XMLParserConfiguration.java │ └── test │ ├── java │ └── top │ │ └── ylonline │ │ └── dom4j │ │ ├── CrmTest.java │ │ ├── CspTest.java │ │ └── TestCase.java │ └── resources │ ├── crm.receive.cdata.txt │ ├── crm.receive.txt │ ├── crm.send.cdata.txt │ ├── crm.send.txt │ ├── csp.receive.cdata.txt │ ├── csp.receive.txt │ ├── csp.send.cdata.txt │ └── csp.send.txt ├── dubbo-examples ├── dubbo-sca │ ├── dubbo-sca-api │ │ ├── pom.xml │ │ └── src │ │ │ └── main │ │ │ └── java │ │ │ └── top │ │ │ └── ylonline │ │ │ └── dubbo │ │ │ └── sca │ │ │ └── api │ │ │ ├── DubboService.java │ │ │ ├── EchoService.java │ │ │ └── RestService.java │ ├── dubbo-sca-consumer │ │ ├── pom.xml │ │ └── src │ │ │ └── main │ │ │ ├── java │ │ │ └── top │ │ │ │ └── ylonline │ │ │ │ └── dubbo │ │ │ │ └── sca │ │ │ │ └── DubboScaConsumerApp.java │ │ │ └── resources │ │ │ ├── application-consul.yml │ │ │ ├── application-zk.yml │ │ │ ├── bootstrap.yml │ │ │ └── logback.xml │ ├── dubbo-sca-provider │ │ ├── pom.xml │ │ └── src │ │ │ └── main │ │ │ ├── java │ │ │ └── top │ │ │ │ └── ylonline │ │ │ │ └── dubbo │ │ │ │ └── sca │ │ │ │ ├── DubboScaProviderApp.java │ │ │ │ └── service │ │ │ │ ├── DubboServiceImpl.java │ │ │ │ ├── EchoServiceImpl.java │ │ │ │ └── RestServiceImpl.java │ │ │ └── resources │ │ │ ├── application-consul.yml │ │ │ ├── application-zk.yml │ │ │ ├── bootstrap.yml │ │ │ └── logback.xml │ └── pom.xml ├── dubbo-v2.6.x │ ├── README.md │ ├── dubbo-v2.6.x-api │ │ ├── pom.xml │ │ └── src │ │ │ └── main │ │ │ └── java │ │ │ └── top │ │ │ └── ylonline │ │ │ └── dubbo │ │ │ └── spring │ │ │ └── boot │ │ │ └── api │ │ │ ├── DubboService.java │ │ │ ├── MultipleService.java │ │ │ └── RestService.java │ ├── dubbo-v2.6.x-consumer │ │ ├── pom.xml │ │ ├── pom.xml.nacos │ │ ├── pom.xml.zk │ │ └── src │ │ │ └── main │ │ │ ├── java │ │ │ └── top │ │ │ │ └── ylonline │ │ │ │ └── dubbo │ │ │ │ └── spring │ │ │ │ └── boot │ │ │ │ ├── DubboConsumer.java │ │ │ │ └── controller │ │ │ │ └── DemoController.java │ │ │ └── resources │ │ │ ├── application.yml │ │ │ ├── dubbo-consumer-nacos.xml │ │ │ ├── dubbo-consumer-zk.xml │ │ │ └── logback-spring.xml │ ├── dubbo-v2.6.x-provider │ │ ├── pom.xml │ │ ├── pom.xml.nacos │ │ ├── pom.xml.zk │ │ └── src │ │ │ └── main │ │ │ ├── java │ │ │ └── top │ │ │ │ └── ylonline │ │ │ │ └── dubbo │ │ │ │ └── spring │ │ │ │ └── boot │ │ │ │ ├── DubboProvider.java │ │ │ │ └── service │ │ │ │ ├── DubboServiceImpl.java │ │ │ │ ├── MultipleServiceImpl.java │ │ │ │ └── RestServiceImpl.java │ │ │ └── resources │ │ │ ├── application-nacos.yml │ │ │ ├── application-zk.yml │ │ │ ├── application.yml │ │ │ └── logback-spring.xml │ └── pom.xml ├── dubbo-v2.7.x │ ├── README-v2.7.0.md │ ├── README.md │ ├── dubbo-v2.7.x-api │ │ ├── pom.xml │ │ └── src │ │ │ └── main │ │ │ └── java │ │ │ └── top │ │ │ └── ylonline │ │ │ └── dubbo27x │ │ │ └── api │ │ │ ├── DubboService.java │ │ │ ├── MultipleService.java │ │ │ └── RestService.java │ ├── dubbo-v2.7.x-consumer │ │ ├── pom.xml │ │ └── src │ │ │ └── main │ │ │ ├── java │ │ │ └── top │ │ │ │ └── ylonline │ │ │ │ └── dubbo27x │ │ │ │ ├── DubboConsumer270.java │ │ │ │ └── controller │ │ │ │ └── DemoController.java │ │ │ └── resources │ │ │ ├── application-zk.yml │ │ │ ├── application.yml │ │ │ ├── dubbo-consumer-zk.xml │ │ │ └── logback-spring.xml │ ├── dubbo-v2.7.x-provider │ │ ├── pom.xml │ │ └── src │ │ │ └── main │ │ │ ├── java │ │ │ └── top │ │ │ │ └── ylonline │ │ │ │ └── dubbo27x │ │ │ │ ├── DubboProvider270.java │ │ │ │ └── service │ │ │ │ ├── DubboServiceImpl.java │ │ │ │ ├── MultipleServiceImpl.java │ │ │ │ └── RestServiceImpl.java │ │ │ └── resources │ │ │ ├── application-nacos.yml │ │ │ ├── application-zk.yml │ │ │ ├── application.yml │ │ │ └── logback-spring.xml │ ├── pom.xml │ └── 元数据中心配置.md └── pom.xml ├── encrypt-examples ├── frontend-backend-encrypt-with-rsa │ ├── README.md │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── top │ │ │ │ └── ylonline │ │ │ │ └── encrypt │ │ │ │ ├── FrontendBackendEncryptWithRsaApp.java │ │ │ │ ├── common │ │ │ │ └── Const.java │ │ │ │ ├── controller │ │ │ │ └── DemoController.java │ │ │ │ └── util │ │ │ │ ├── AesUtils.java │ │ │ │ ├── EncryptException.java │ │ │ │ └── RsaUtils.java │ │ └── resources │ │ │ ├── application.yml │ │ │ ├── logback.xml │ │ │ ├── static │ │ │ ├── crypto-js │ │ │ │ ├── aes.js │ │ │ │ ├── cipher-core.js │ │ │ │ ├── core.js │ │ │ │ ├── enc-base64.js │ │ │ │ ├── enc-utf16.js │ │ │ │ ├── evpkdf.js │ │ │ │ ├── format-hex.js │ │ │ │ ├── hmac.js │ │ │ │ ├── lib-typedarrays.js │ │ │ │ ├── md5.js │ │ │ │ ├── mode-cfb.js │ │ │ │ ├── mode-ctr-gladman.js │ │ │ │ ├── mode-ctr.js │ │ │ │ ├── mode-ecb.js │ │ │ │ ├── mode-ofb.js │ │ │ │ ├── pad-ansix923.js │ │ │ │ ├── pad-iso10126.js │ │ │ │ ├── pad-iso97971.js │ │ │ │ ├── pad-nopadding.js │ │ │ │ ├── pad-zeropadding.js │ │ │ │ ├── pbkdf2.js │ │ │ │ ├── rabbit-legacy.js │ │ │ │ ├── rabbit.js │ │ │ │ ├── rc4.js │ │ │ │ ├── ripemd160.js │ │ │ │ ├── sha1.js │ │ │ │ ├── sha224.js │ │ │ │ ├── sha256.js │ │ │ │ ├── sha3.js │ │ │ │ ├── sha384.js │ │ │ │ ├── sha512.js │ │ │ │ ├── tripledes.js │ │ │ │ └── x64-core.js │ │ │ ├── rsa.js │ │ │ └── rsa.min.js │ │ │ └── templates │ │ │ ├── aes.html │ │ │ ├── error │ │ │ ├── 404.html │ │ │ └── 500.html │ │ │ ├── rsa-and-aes.html │ │ │ └── rsa.html │ │ └── test │ │ └── java │ │ └── top │ │ └── ylonline │ │ └── encrypt │ │ ├── AppTest.java │ │ └── util │ │ ├── AesUtilsTest.java │ │ └── RsaUtilsTest.java └── pom.xml ├── feign-examples ├── openfeign │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── top │ │ │ │ └── ylonline │ │ │ │ └── feign │ │ │ │ ├── OpenFeignApp.java │ │ │ │ └── client │ │ │ │ ├── CspClient.java │ │ │ │ ├── Github.java │ │ │ │ └── GithubClient.java │ │ └── resources │ │ │ ├── application.yml │ │ │ └── logback-spring.xml │ │ └── test │ │ └── java │ │ └── top │ │ └── ylonline │ │ └── feign │ │ └── client │ │ ├── CspClientTest.java │ │ ├── GithubClientTest.java │ │ └── GithubTest.java └── pom.xml ├── flow-examples ├── pom.xml └── src │ └── main │ └── java │ └── top │ └── ylonline │ └── App.java ├── gateway-examples ├── gateway-nacos │ ├── README.md │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── top │ │ │ └── ylonline │ │ │ └── nacos │ │ │ └── spring │ │ │ └── cloud │ │ │ └── gateway │ │ │ └── example │ │ │ └── NacosGatewayApp.java │ │ └── resources │ │ ├── application.yml │ │ ├── bootstrap.yml │ │ └── logback-spring.xml ├── gateway-simple │ ├── README.md │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── top │ │ │ └── ylonline │ │ │ └── spring │ │ │ └── cloud │ │ │ └── gateway │ │ │ └── example │ │ │ └── GatewayApp.java │ │ └── resources │ │ ├── application-dev.yml │ │ ├── application-local.yml │ │ ├── application-pro.yml │ │ ├── application.yml │ │ └── logback-spring.xml └── pom.xml ├── nacos-examples ├── nacos-spring-boot-example │ ├── README.md │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── top │ │ │ └── ylonline │ │ │ └── nacos │ │ │ └── spring │ │ │ └── boot │ │ │ └── example │ │ │ └── NacosBootApp.java │ │ └── resources │ │ ├── application-dev.yml │ │ ├── application-local.yml │ │ ├── application-pro.yml │ │ ├── application.yml │ │ └── logback-spring.xml ├── nacos-spring-cloud-example │ ├── README.md │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── top │ │ │ └── ylonline │ │ │ └── nacos │ │ │ └── spring │ │ │ └── cloud │ │ │ └── example │ │ │ ├── NacosCloudApp.java │ │ │ └── controller │ │ │ └── DemoController.java │ │ └── resources │ │ ├── application-nacos.yml │ │ ├── application.yml │ │ ├── bootstrap.properties │ │ └── logback-spring.xml └── pom.xml ├── pom.xml ├── sb-examples ├── events-and-listeners │ ├── README.md │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── top │ │ │ └── ylonline │ │ │ └── sb │ │ │ └── el │ │ │ ├── EventsAndListenersApp.java │ │ │ ├── config │ │ │ ├── EventListenerConfig.java │ │ │ └── MyAsyncConfigurer.java │ │ │ ├── domain │ │ │ └── User.java │ │ │ ├── event │ │ │ └── UserEvent.java │ │ │ └── listener │ │ │ └── UserEventListener.java │ │ └── resources │ │ ├── application.yml │ │ └── logback.xml ├── pom.xml ├── redis-v1 │ ├── README.md │ ├── pom.xml │ └── src │ │ ├── main │ │ └── java │ │ │ └── top │ │ │ └── ylonline │ │ │ └── sb │ │ │ └── redis │ │ │ └── v1 │ │ │ ├── TRedisAutoConfiguration.java │ │ │ └── cache │ │ │ └── TRedisCacheManager.java │ │ └── test │ │ ├── java │ │ └── top │ │ │ └── ylonline │ │ │ └── sb │ │ │ └── redis │ │ │ └── v1 │ │ │ └── test │ │ │ ├── RedisV1App.java │ │ │ ├── RedisV1AppTest.java │ │ │ ├── domain │ │ │ └── User.java │ │ │ └── service │ │ │ └── UserService.java │ │ └── resources │ │ ├── META-INF │ │ └── spring.factories │ │ ├── application.yml │ │ └── logback.xml ├── redis-v2.0 │ ├── README.md │ ├── pom.xml │ └── src │ │ ├── main │ │ └── java │ │ │ └── top │ │ │ └── ylonline │ │ │ └── sb │ │ │ └── redis │ │ │ └── v2 │ │ │ ├── TRedisAutoConfiguration.java │ │ │ └── cache │ │ │ └── TRedisCacheManager.java │ │ └── test │ │ ├── java │ │ └── top │ │ │ └── ylonline │ │ │ └── sb │ │ │ └── redis │ │ │ └── v2 │ │ │ └── test │ │ │ ├── RedisV2App.java │ │ │ ├── RedisV2AppTest.java │ │ │ ├── domain │ │ │ └── User.java │ │ │ └── service │ │ │ └── UserService.java │ │ └── resources │ │ ├── META-INF │ │ └── spring.factories │ │ ├── application.yml │ │ └── logback.xml └── webflux │ ├── README.md │ ├── pom.xml │ └── src │ └── main │ ├── java │ └── top │ │ └── ylonline │ │ └── sb │ │ └── webflux │ │ ├── WebFluxApp.java │ │ ├── config │ │ └── JpaReactiveConfig.java │ │ ├── controller │ │ └── UserController.java │ │ ├── entity │ │ └── User.java │ │ ├── repository │ │ └── UserRepository.java │ │ └── service │ │ ├── UserService.java │ │ └── UserServiceImpl.java │ └── resources │ ├── application.yml │ ├── data-h2.sql │ └── schema-h2.sql ├── sc-examples ├── pom.xml └── sleuth │ ├── pom.xml │ └── src │ └── main │ ├── java │ └── top │ │ └── ylonline │ │ └── sc │ │ └── sleuth │ │ ├── SleuthApp.java │ │ ├── config │ │ └── JpaReactiveConfig.java │ │ ├── entity │ │ └── User.java │ │ ├── repository │ │ └── UserRepository.java │ │ └── service │ │ ├── UserService.java │ │ └── UserServiceImpl.java │ └── resources │ ├── application.yml │ ├── bootstrap.yml │ ├── data-h2.sql │ └── schema-h2.sql └── sentinel-examples ├── pom.xml ├── sentinel-cluster-example ├── README.md ├── pom.xml ├── sentinel-cluster-client │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── top │ │ │ └── ylonline │ │ │ └── sentinel │ │ │ ├── SentinelClusterClientApp.java │ │ │ └── init │ │ │ └── NacosDatasourceInitFunc.java │ │ └── resources │ │ ├── META-INF │ │ └── services │ │ │ └── com.alibaba.csp.sentinel.init.InitFunc │ │ ├── application.yml │ │ ├── bootstrap.yml │ │ └── logback-spring.xml └── sentinel-cluster-server-alone │ ├── pom.xml │ └── src │ └── main │ ├── java │ └── top │ │ └── ylonline │ │ └── sentinel │ │ ├── SentinelClusterServerApp.java │ │ └── init │ │ └── NacosDatasourceInitFunc.java │ └── resources │ ├── META-INF │ └── services │ │ └── com.alibaba.csp.sentinel.init.InitFunc │ ├── application.yml │ ├── bootstrap.yml │ └── logback-spring.xml └── sentinel-spring-cloud-example ├── README.md ├── pom.xml └── src └── main ├── java └── top │ └── ylonline │ └── sentinel │ └── spring │ └── cloud │ └── example │ └── SentinelApp.java └── resources ├── application.yml └── logback-spring.xml /.gitignore: -------------------------------------------------------------------------------- 1 | # maven ignore 2 | dependency-reduced-pom.xml 3 | .flattened-pom.xml 4 | 5 | target/ 6 | !.mvn/wrapper/* 7 | *.zip 8 | *.tar 9 | *.tar.gz 10 | 11 | # eclipse ignore 12 | .settings/ 13 | .project 14 | .classpath 15 | 16 | # idea ignore 17 | .idea/ 18 | *.ipr 19 | *.iml 20 | *.iws 21 | 22 | # temp ignore 23 | *.log 24 | *.cache 25 | *.diff 26 | *.patch 27 | *.tmp 28 | 29 | # system ignore 30 | .DS_Store 31 | Thumbs.db 32 | *.orig -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # java-best-practice 2 | 3 | Java 的一些学习例子,最佳实践 4 | 5 | ## Examples 6 | 7 | > dubbo 8 | - [dubbo-v2.6.x](dubbo-examples/dubbo-v2.6.x) Dubbo-2.6.5 + Spring Boot:zk + nacos 注册中心 9 | - [dubbo-v2.7.x](dubbo-examples/dubbo-v2.7.x) Dubbo-2.7.0 + Spring Boot 10 | - [dubbo-sca](dubbo-examples/dubbo-sca) Dubbo-2.7.6 + Spring Boot.2.0.x + Spring Cloud.F 11 | 12 | 13 | > nacos 14 | - [nacos-spring-boot-example](nacos-examples/nacos-spring-boot-example) Nacos + Spring Boot 简单入门 15 | - [nacos-spring-cloud-example](nacos-examples/nacos-spring-cloud-example) Nacos + Spring Cloud 简单入门 16 | 17 | 18 | > sentinel 19 | - [sentinel-spring-cloud-example](sentinel-examples/sentinel-spring-cloud-example) sentinel 简单入门 20 | - [sentinel-cluster-example](sentinel-examples/sentinel-cluster-example) Sentinel 配置动态规则数据源(集群模式):Nacos 配置中心(zk、apollo同理) 21 | 22 | 23 | > spring-cloud-gateway 24 | - [gateway-simple](gateway-examples/gateway-simple) gateway 简单入门 25 | - [gateway-nacos](gateway-examples/gateway-nacos) gateway 实现动态路由规则:Nacos 配置中心 26 | 27 | 28 | > feign-examples 29 | - [openfeign](feign-examples/openfeign) openfeign 简单使用 30 | 31 | 32 | > dom4j 33 | - [dom4j-example](dom4j-example) dom4j 解析任意 xml 报文 34 | 35 | 36 | > 加解密 37 | - [frontend-backend-encrypt-with-rsa](encrypt-examples/frontend-backend-encrypt-with-rsa) 前后端分离数据加密传输 38 | 39 | 40 | > Spring Boot 41 | - [events-and-listeners](sb-examples/events-and-listeners) Spring 事件发布和监听 42 | - [webflux](sb-examples/webflux) webflux 简单入门,提供堵塞、响应式对比 43 | 44 | 45 | > Cache 46 | 47 | 自定义 Expired 注解,实现缓存的过期时间配置,并支持 SpEL 表达式配置动态过期时间 48 | - redis 49 | - [redis-v1](sb-examples/redis-v1) 50 | - [redis-v2.0](sb-examples/redis-v2.0) 51 | 52 | - memcached 53 | - [xmemcached-spring-boot-starter](https://github.com/foreveryang321/xmemcached-spring-boot-starter) Spring Boot Starter for XMemcached 54 | -------------------------------------------------------------------------------- /common/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | top.ylonline 7 | java-best-practice 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | common 13 | 14 | common 15 | 16 | http://www.example.com 17 | 18 | 19 | UTF-8 20 | 1.8 21 | 1.8 22 | 23 | 24 | 25 | 26 | org.springframework 27 | spring-core 28 | 4.3.22.RELEASE 29 | provided 30 | true 31 | 32 | 33 | org.springframework 34 | spring-context-support 35 | 4.3.22.RELEASE 36 | provided 37 | true 38 | 39 | 40 | org.slf4j 41 | slf4j-api 42 | 1.7.15 43 | provided 44 | true 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /common/src/main/java/top/ylonline/common/cache/annotation/Expired.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.common.cache.annotation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Inherited; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.RetentionPolicy; 8 | import java.lang.annotation.Target; 9 | 10 | /** 11 | * 自定义缓存过期时间配置注解,过期时间单位:s(秒) 12 | *
13 |  *     1、{@link Expired#el()}优先级比{@link Expired#value()}高,优先使用{@link Expired#el()}的配置
14 |  * 
15 | * 16 | * @author YL 17 | */ 18 | @Target({ElementType.METHOD, ElementType.TYPE}) 19 | @Retention(RetentionPolicy.RUNTIME) 20 | @Inherited 21 | @Documented 22 | public @interface Expired { 23 | /** 24 | * 过期时间,单位:秒,默认:-1(使用全局默认过期时间) 25 | *
26 |      *     与 {@link #el()} 属性互斥,优先使用 {@link #el()} 配置。
27 |      * 
28 | */ 29 | long value() default -1; 30 | 31 | /** 32 | * 过期时间,单位:秒 33 | * Spring Expression Language (SpEL) expression for computing the expiration time dynamically. 34 | *
35 |      *     与 {@link #value()} 属性互斥,优先使用当前配置。
36 |      * 
37 | */ 38 | String el() default ""; 39 | } 40 | -------------------------------------------------------------------------------- /common/src/main/java/top/ylonline/common/cache/interceptor/TCacheErrorHandler.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.common.cache.interceptor; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.cache.Cache; 5 | import org.springframework.cache.interceptor.CacheErrorHandler; 6 | 7 | /** 8 | * 自定义缓存异常处理程序 9 | *
10 |  *     解决的问题:
11 |  *     Redis 容易出现缓存问题(超时、Redis 宕机等),当使用 spring cache 的注释 Cacheable、Cacheput 等处理缓存问题时,
12 |  *     我们无法使用 try catch 处理出现的异常,所以最后导致结果是整个服务报错无法正常工作。
13 |  *     通过自定义 {@link TCacheErrorHandler} 来处理异常可以解决这个问题。
14 |  * 
15 | *

16 | * 缓存仅仅是为了业务更快地查询而存在的,如果因为缓存操作失败导致正常的业务流程失败,有点得不偿失了。 17 | * 因此需要开发者自定义 CacheErrorHandler 处理缓存读写的异常。 18 | *

19 | * 20 | *

21 | * 如果缓存写发生了异常,就可能导致数据库的数据和缓存的数据不一致的问题。 22 | * 为了解决该问题,需要继续扩展 CacheErrorHandler 的 handleCachePutError 和 handleCacheEvictError 方法。 23 | * 思路就是将缓存写操作失败的 key 保存下来,通过重试任务删除这些 key 对应的缓存解决数据库数据与缓存数据不一致的问题。 24 | *

25 | * 26 | * @author YL 27 | */ 28 | @Slf4j 29 | public class TCacheErrorHandler implements CacheErrorHandler { 30 | 31 | @Override 32 | public void handleCacheGetError(RuntimeException exception, Cache cache, Object key) { 33 | log.error("key: {}, msg: {}", key, exception.getMessage(), exception); 34 | } 35 | 36 | @Override 37 | public void handleCachePutError(RuntimeException exception, Cache cache, Object key, Object value) { 38 | log.error("key: {}, value: {}, msg: {}", key, value, exception.getMessage(), exception); 39 | // 写入失败时,尝试删除缓存,如果 evict 也出现异常,则可能会直接抛给应用,这里需要 try catch 处理一下 40 | try { 41 | cache.evict(key); 42 | } catch (Exception e) { 43 | // ignore 44 | } 45 | } 46 | 47 | @Override 48 | public void handleCacheEvictError(RuntimeException exception, Cache cache, Object key) { 49 | log.error("key: {}, msg: {}", key, exception.getMessage(), exception); 50 | } 51 | 52 | @Override 53 | public void handleCacheClearError(RuntimeException exception, Cache cache) { 54 | throw exception; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /common/src/main/java/top/ylonline/common/cache/interceptor/TKeyGenerator.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.common.cache.interceptor; 2 | 3 | import org.springframework.cache.interceptor.KeyGenerator; 4 | import org.springframework.util.StringUtils; 5 | 6 | import java.lang.reflect.Method; 7 | 8 | /** 9 | * spring-cache 自定义 key 生成规则 10 | * 11 | * @author YL 12 | */ 13 | public class TKeyGenerator implements KeyGenerator { 14 | 15 | @Override 16 | public Object generate(Object o, Method method, Object... params) { 17 | StringBuilder sb = new StringBuilder(32); 18 | // 拼接规则:类名.函数名 19 | sb.append(o.getClass().getSimpleName()); 20 | sb.append("."); 21 | sb.append(method.getName()); 22 | if (params.length == 0) { 23 | return sb.toString(); 24 | } 25 | if (params.length == 1) { 26 | Object param = params[0]; 27 | if (param != null && !param.getClass().isArray()) { 28 | sb.append(compute(param)); 29 | } 30 | return sb.toString(); 31 | } 32 | // 参数拼接规则:类名#函数名#p1.p2.p3 33 | Object[] arr = new Object[params.length]; 34 | System.arraycopy(params, 0, arr, 0, params.length); 35 | String str = StringUtils.arrayToDelimitedString(arr, "."); 36 | sb.append(compute(str)); 37 | return sb.toString(); 38 | } 39 | 40 | private String compute(Object str) { 41 | return "#" + str; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /common/src/main/java/top/ylonline/common/cache/util/CacheUtils.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.common.cache.util; 2 | 3 | /** 4 | * 缓存工具 5 | * 6 | * @author YL 7 | */ 8 | public final class CacheUtils { 9 | private static final String SYMBOL = "#"; 10 | 11 | /** 12 | * 构建一个新的 cacheName,以实现动态过期时间配置 13 | * 14 | * @param cacheName 原始 cacheName 15 | * @param ttl 过期时间 16 | */ 17 | public static String buildCacheNameForTtl(String cacheName, long ttl) { 18 | return cacheName + SYMBOL + ttl; 19 | } 20 | 21 | public static String[] splitCacheNameForTtl(String cacheNameForTtl) { 22 | return cacheNameForTtl.split(SYMBOL, -1); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /common/src/main/java/top/ylonline/common/util/StrUtils.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.common.util; 2 | 3 | /** 4 | * @author YL 5 | */ 6 | public abstract class StrUtils { 7 | 8 | public static boolean isEmpty(CharSequence cs) { 9 | return cs == null || cs.length() == 0; 10 | } 11 | 12 | public static boolean isNotEmpty(CharSequence cs) { 13 | return !isEmpty(cs); 14 | } 15 | 16 | public static boolean isBlank(CharSequence cs) { 17 | int strLen; 18 | if (cs != null && (strLen = cs.length()) != 0) { 19 | for (int i = 0; i < strLen; ++i) { 20 | if (!Character.isWhitespace(cs.charAt(i))) { 21 | return false; 22 | } 23 | } 24 | 25 | return true; 26 | } else { 27 | return true; 28 | } 29 | } 30 | 31 | public static boolean isNotBlank(CharSequence cs) { 32 | return !isBlank(cs); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /dom4j-example/README.md: -------------------------------------------------------------------------------- 1 | # dom4j 2 | `org.dom4j.2.1.0` 版本以前,使用 `DocumentHelper.parseText`会存在`XXE` 漏洞,代码如下 3 | ```java 4 | public static Document parseText(String text) throws DocumentException { 5 | SAXReader reader = new SAXReader(); 6 | String encoding = getEncoding(text); 7 | 8 | InputSource source = new InputSource(new StringReader(text)); 9 | source.setEncoding(encoding); 10 | 11 | Document result = reader.read(source); 12 | 13 | // if the XML parser doesn't provide a way to retrieve the encoding, 14 | // specify it manually 15 | if (result.getXMLEncoding() == null) { 16 | result.setXMLEncoding(encoding); 17 | } 18 | 19 | return result; 20 | } 21 | ``` 22 | `org.dom4j.2.1.1` 版本以后,使用 `DocumentHelper.parseText`不会存在`XXE` 漏洞,代码如下 23 | ```java 24 | public static Document parseText(String text) throws DocumentException { 25 | SAXReader reader = new SAXReader(); 26 | try { 27 | reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); 28 | reader.setFeature("http://xml.org/sax/features/external-general-entities", false); 29 | reader.setFeature("http://xml.org/sax/features/external-parameter-entities", false); 30 | } catch (SAXException e) { 31 | //Parse with external resources downloading allowed. 32 | } 33 | 34 | String encoding = getEncoding(text); 35 | 36 | InputSource source = new InputSource(new StringReader(text)); 37 | source.setEncoding(encoding); 38 | 39 | Document result = reader.read(source); 40 | 41 | // if the XML parser doesn't provide a way to retrieve the encoding, 42 | // specify it manually 43 | if (result.getXMLEncoding() == null) { 44 | result.setXMLEncoding(encoding); 45 | } 46 | 47 | return result; 48 | } 49 | ``` -------------------------------------------------------------------------------- /dom4j-example/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | top.ylonline 6 | java-best-practice 7 | 1.0-SNAPSHOT 8 | 9 | 4.0.0 10 | 11 | dom4j-example 12 | Java 最佳实践 :: dom4j 13 | 14 | 15 | UTF-8 16 | 1.8 17 | 1.8 18 | 19 | 20 | 21 | 22 | top.ylonline 23 | common 24 | ${project.parent.version} 25 | 26 | 27 | org.dom4j 28 | dom4j 29 | 2.1.1 30 | 31 | 32 | 33 | com.alibaba 34 | fastjson 35 | 1.2.54 36 | test 37 | 38 | 39 | commons-io 40 | commons-io 41 | 2.5 42 | test 43 | 44 | 45 | org.apache.commons 46 | commons-lang3 47 | 3.8.1 48 | test 49 | 50 | 51 | junit 52 | junit 53 | 4.12 54 | test 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /dom4j-example/src/main/java/top/ylonline/dom4j/XMLParserConfiguration.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.dom4j; 2 | 3 | /** 4 | * @author YL 5 | */ 6 | public class XMLParserConfiguration { 7 | // private static final String CDATA_TAG_NAME = "text"; 8 | 9 | private boolean keepRoot; 10 | 11 | private boolean keepAttributes; 12 | 13 | /** 14 | * Default parser configuration. Does not keep strings, and the CDATA Tag Name is "text". 15 | */ 16 | public XMLParserConfiguration() { 17 | this(false, false); 18 | } 19 | 20 | public XMLParserConfiguration(final boolean keepAttributes) { 21 | this(false, keepAttributes); 22 | } 23 | 24 | public XMLParserConfiguration(final boolean keepRoot, final boolean keepAttributes) { 25 | this.keepRoot = keepRoot; 26 | this.keepAttributes = keepAttributes; 27 | } 28 | 29 | public boolean isKeepRoot() { 30 | return keepRoot; 31 | } 32 | 33 | public boolean isKeepAttributes() { 34 | return keepAttributes; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /dom4j-example/src/test/java/top/ylonline/dom4j/CrmTest.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.dom4j; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import org.junit.Test; 5 | 6 | /** 7 | * @author YL 8 | */ 9 | public class CrmTest extends TestCase { 10 | private static final boolean KEEP_ATTRRIBUTES = false; 11 | private static final String ENCODING = "UTF-8"; 12 | 13 | @Test 14 | public void crmReceive() { 15 | parse("crm.receive.txt"); 16 | } 17 | 18 | @Test 19 | public void crmReceiveCdata() { 20 | parse("crm.receive.cdata.txt"); 21 | } 22 | 23 | @Test 24 | public void crmSend() { 25 | parse("crm.send.txt"); 26 | } 27 | 28 | @Test 29 | public void crmSendCdata() { 30 | parse("crm.send.cdata.txt"); 31 | } 32 | 33 | private void parse(String fileName) { 34 | XMLParserConfiguration configuration = new XMLParserConfiguration(false, KEEP_ATTRRIBUTES); 35 | String xml = getByFile(fileName, ENCODING); 36 | 37 | // 去掉 38 | xml = xml.replaceAll("(<\\?[^<]*\\?>)?", ""); 39 | 40 | String json = JSON.toJSONString(Dom4jUtils.parse(xml, configuration)); 41 | System.out.println(fileName + " --->\n<--- " + json); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /dom4j-example/src/test/java/top/ylonline/dom4j/CspTest.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.dom4j; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import org.junit.Test; 5 | 6 | /** 7 | * @author YL 8 | */ 9 | public class CspTest extends TestCase { 10 | private static final boolean KEEP_ATTRRIBUTES = false; 11 | private static final String ENCODING = "UTF-8"; 12 | 13 | @Test 14 | public void cpsReceive() { 15 | parse("csp.receive.txt"); 16 | } 17 | 18 | @Test 19 | public void cpsReceiveCdata() { 20 | parse("csp.receive.cdata.txt"); 21 | } 22 | 23 | @Test 24 | public void cpsSend() { 25 | parse("csp.send.txt"); 26 | } 27 | 28 | @Test 29 | public void cpsSendCdata() { 30 | parse("csp.send.cdata.txt"); 31 | } 32 | 33 | private void parse(String fileName) { 34 | XMLParserConfiguration configuration = new XMLParserConfiguration(false, KEEP_ATTRRIBUTES); 35 | String xml = getByFile(fileName, ENCODING); 36 | // if ("csp.receive.txt".equals(fileName)){ 37 | // if (StringUtils.isNotBlank(xml)) { 38 | // String ir = ""; 40 | // if (xml.contains(ir)) { 41 | // xml = xml.replace(ir, ir + "", "]]>"); 43 | // } 44 | // } 45 | // } 46 | 47 | // 去掉 48 | xml = xml.replaceAll("(<\\?[^<]*\\?>)?", ""); 49 | 50 | String json = JSON.toJSONString(Dom4jUtils.parse(xml, configuration)); 51 | System.out.println(fileName + " --->\n<--- " + json); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /dom4j-example/src/test/java/top/ylonline/dom4j/TestCase.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.dom4j; 2 | 3 | import org.apache.commons.io.IOUtils; 4 | 5 | import java.io.File; 6 | import java.io.FileInputStream; 7 | import java.io.IOException; 8 | import java.net.URL; 9 | 10 | /** 11 | * @author YL 12 | */ 13 | public class TestCase { 14 | protected String getByFile(String fileName, String encoding) { 15 | ClassLoader classLoader = TestCase.class.getClassLoader(); 16 | try { 17 | URL url = classLoader.getResource(fileName); 18 | return IOUtils.toString(new FileInputStream(new File(url.getFile())), encoding); 19 | } catch (IOException e) { 20 | e.printStackTrace(); 21 | } 22 | return ""; 23 | } 24 | 25 | protected String removeXmlStringNamespaceAndPreamble(String xmlString) { 26 | return xmlString//.replaceAll("(<\\?[^<]*\\?>)?", "") //去掉 27 | .replaceAll("xmlns.*?(\"|\').*?(\"|\')", "") //去掉xmlns: 28 | .replaceAll("(<)(\\w+:)", "$1") //去掉开头标签的冒号前的前缀 29 | .replaceAll("()", "$1$3"); //去掉结尾标签的冒号前前缀 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /dom4j-example/src/test/resources/crm.receive.cdata.txt: -------------------------------------------------------------------------------- 1 | 2 | 0 3 | OK 4 | 5 | 6 | 7 | 3333333333 8 | 2222222222222222 9 | 姓名 10 | 10 11 | 2716872242 12 | 50 13 | 500101 14 | 02 15 | 16 | 17 | 18 | 0 19 | 0 20 | 0 21 | 22 | 03 23 | 5001 24 | 7777777A9F3AADBD 25 | 1 26 | 1 27 | UNDEF 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /dom4j-example/src/test/resources/crm.send.cdata.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | admin20171120100304533 4 | admin 5 | admin123 6 | 1 7 | 200 8 | 接口组件名称 9 | 1 10 | 11 | 12 | 13 | 14 | 15 | root 16 | root123 17 | 200 18 | 19 | 20 | 21 | 22 | 2 23 | 18111111111 24 | 25 | 26 | 27 | 28 | 201 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /dom4j-example/src/test/resources/csp.receive.cdata.txt: -------------------------------------------------------------------------------- 1 | 2 | 0 3 | OK 4 | 5 | 6 | 0 7 | OK 8 | 201409移动话费促销包送话费(抵扣套外)_赠金﹏8538810489﹏1 10 | 11 | 14 | 5UI﹏-891﹏20170702013614﹏1544051565/无法找到对应营业厅﹏﹏13333333333﹏8344144030﹏20170601:20170630▕▏5UI﹏-3030﹏20170901213459﹏1544051565/无法找到对应营业厅﹏﹏13333333333﹏8344144030﹏20170801:20170831▕▏5UI﹏-2132﹏20170602025720﹏1544051565/无法找到对应营业厅﹏﹏13333333333﹏8344144030﹏20170501:20170531▕▏5UD﹏30000﹏20170321101415﹏STF_YEZB/余额帐本【接口】﹏IBSS充值(一次出发票,不可退,ib赠送使用)﹏﹏﹏20170301:20170331 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /dom4j-example/src/test/resources/csp.receive.txt: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 0 10 | OK 11 | 12 | 13 | 0 14 | OK 15 | 201409移动话费促销包送话费(抵扣套外)_赠金﹏8538810489﹏1 17 | 18 | 21 | 5UI﹏-891﹏20170702013614﹏1544051565/无法找到对应营业厅﹏﹏13333333333﹏8344144030﹏20170601:20170630▕▏5UI﹏-3030﹏20170901213459﹏1544051565/无法找到对应营业厅﹏﹏13333333333﹏8344144030﹏20170801:20170831▕▏5UI﹏-2132﹏20170602025720﹏1544051565/无法找到对应营业厅﹏﹏13333333333﹏8344144030﹏20170501:20170531▕▏5UD﹏30000﹏20170321101415﹏STF_YEZB/余额帐本【接口】﹏IBSS充值(一次出发票,不可退,ib赠送使用)﹏﹏﹏20170301:20170331 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /dom4j-example/src/test/resources/csp.send.cdata.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | admin 5 | admin123 6 | 接口组件名称 7 | 8 | 9 | 10 | 757 11 | 2040817707 12 | 20160923 13 | 20170922 14 | 15 | 16 | -------------------------------------------------------------------------------- /dom4j-example/src/test/resources/csp.send.txt: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 9 | 10 | 11 | admin 12 | admin123 13 | 接口组件名称 14 | 15 | 16 | 17 | 757 18 | 2040817707 19 | 20160923 20 | 20170922 21 | 22 | 23 | 24 | ]]> 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-sca/dubbo-sca-api/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | top.ylonline.dubbo 6 | dubbo-sca 7 | 1.0-SNAPSHOT 8 | 9 | 4.0.0 10 | 11 | dubbo-sca-api 12 | Java 最佳实践 :: dubbo(${project.artifactId}) 13 | 14 | 15 | UTF-8 16 | 1.8 17 | 1.8 18 | 19 | 20 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-sca/dubbo-sca-api/src/main/java/top/ylonline/dubbo/sca/api/DubboService.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.dubbo.sca.api; 2 | 3 | /** 4 | * @author YL 5 | */ 6 | public interface DubboService { 7 | /** 8 | * echo 9 | * 10 | * @param message msg 11 | * 12 | * @return 信息 13 | */ 14 | String get(String message); 15 | } 16 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-sca/dubbo-sca-api/src/main/java/top/ylonline/dubbo/sca/api/EchoService.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.dubbo.sca.api; 2 | 3 | /** 4 | * @author YL 5 | */ 6 | public interface EchoService { 7 | /** 8 | * echo 9 | * 10 | * @param message msg 11 | * 12 | * @return 信息 13 | */ 14 | String echo(String message); 15 | } 16 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-sca/dubbo-sca-api/src/main/java/top/ylonline/dubbo/sca/api/RestService.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.dubbo.sca.api; 2 | 3 | /** 4 | * @author YL 5 | */ 6 | public interface RestService { 7 | /** 8 | * 通过 id 获取用户名 9 | * 10 | * @param id 用户id 11 | * 12 | * @return 用户名 13 | */ 14 | String getName(long id); 15 | } 16 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-sca/dubbo-sca-consumer/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | top.ylonline.dubbo 6 | dubbo-sca 7 | 1.0-SNAPSHOT 8 | 9 | 4.0.0 10 | 11 | dubbo-sca-consumer 12 | Java 最佳实践 :: dubbo(${project.artifactId}) 13 | 14 | 15 | UTF-8 16 | 1.8 17 | 1.8 18 | 19 | 20 | 21 | 22 | top.ylonline.dubbo 23 | dubbo-sca-api 24 | ${project.parent.version} 25 | 26 | 27 | com.alibaba.cloud 28 | spring-cloud-starter-dubbo 29 | 30 | 31 | 32 | 33 | org.springframework.cloud 34 | spring-cloud-starter-zookeeper-discovery 35 | 36 | 37 | org.springframework.cloud 38 | spring-cloud-starter-netflix-ribbon 39 | 40 | 41 | 42 | 43 | 47 | 48 | 49 | org.springframework.boot 50 | spring-boot-starter-test 51 | test 52 | 53 | 54 | 55 | 56 | 57 | 58 | org.springframework.boot 59 | spring-boot-maven-plugin 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-sca/dubbo-sca-consumer/src/main/resources/application-consul.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8080 3 | feign: 4 | hystrix: 5 | enabled: true 6 | dubbo: 7 | # scan: 8 | # base-packages: top.ylonline.dubbo.sca.service 9 | registry: 10 | address: spring-cloud://localhost 11 | protocols: 12 | dubbo: 13 | name: dubbo 14 | port: -1 15 | rest: 16 | name: rest 17 | port: 8081 18 | server: netty -------------------------------------------------------------------------------- /dubbo-examples/dubbo-sca/dubbo-sca-consumer/src/main/resources/application-zk.yml: -------------------------------------------------------------------------------- 1 | #server: 2 | # port: 0 3 | dubbo: 4 | application: 5 | id: dubbo-sca-consumer 6 | name: dubbo-sca-consumer 7 | qos-enable: false 8 | registry: 9 | address: spring-cloud://localhost 10 | consumer: 11 | check: false 12 | cloud: 13 | subscribed-services: dubbo-sca-provider 14 | #provider: 15 | # application: 16 | # name: dubbo-sca-provider 17 | spring: 18 | cloud: 19 | service-registry: 20 | auto-registration: 21 | # 要禁用这个,否则需要web环境才能启动 22 | enabled: false 23 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-sca/dubbo-sca-consumer/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: dubbo-sca-consumer 4 | --- 5 | spring: 6 | profiles: zk 7 | cloud: 8 | zookeeper: 9 | enabled: true 10 | connect-string: 192.168.56.101:2181 -------------------------------------------------------------------------------- /dubbo-examples/dubbo-sca/dubbo-sca-consumer/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | ${logger.pattern} 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-sca/dubbo-sca-provider/src/main/java/top/ylonline/dubbo/sca/DubboScaProviderApp.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.dubbo.sca; 2 | 3 | import org.apache.dubbo.config.spring.context.annotation.DubboComponentScan; 4 | import org.springframework.boot.WebApplicationType; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.boot.builder.SpringApplicationBuilder; 7 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient; 8 | 9 | /** 10 | * @author YL 11 | */ 12 | @SpringBootApplication 13 | @DubboComponentScan(basePackages = "top.ylonline.dubbo.sca") 14 | @EnableDiscoveryClient 15 | public class DubboScaProviderApp { 16 | 17 | public static void main(String[] args) { 18 | new SpringApplicationBuilder(DubboScaProviderApp.class) 19 | .properties("spring.profiles.active=zk") 20 | .web(WebApplicationType.NONE) 21 | .run(args); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-sca/dubbo-sca-provider/src/main/java/top/ylonline/dubbo/sca/service/DubboServiceImpl.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.dubbo.sca.service; 2 | 3 | import org.apache.dubbo.config.annotation.Service; 4 | import top.ylonline.dubbo.sca.api.DubboService; 5 | 6 | /** 7 | * @author YL 8 | */ 9 | @Service(protocol = "dubbo") 10 | public class DubboServiceImpl implements DubboService { 11 | 12 | @Override 13 | public String get(String message) { 14 | return "Hello " + message; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-sca/dubbo-sca-provider/src/main/java/top/ylonline/dubbo/sca/service/EchoServiceImpl.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.dubbo.sca.service; 2 | 3 | import org.apache.dubbo.config.annotation.Service; 4 | import top.ylonline.dubbo.sca.api.EchoService; 5 | 6 | /** 7 | * @author YL 8 | */ 9 | @Service(protocol = "dubbo") 10 | public class EchoServiceImpl implements EchoService { 11 | 12 | @Override 13 | public String echo(String message) { 14 | return "Echo, Hello " + message; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-sca/dubbo-sca-provider/src/main/java/top/ylonline/dubbo/sca/service/RestServiceImpl.java: -------------------------------------------------------------------------------- 1 | // package top.ylonline.dubbo.sca.service; 2 | // 3 | // import org.apache.dubbo.config.annotation.Service; 4 | // import top.ylonline.dubbo.sca.api.RestService; 5 | // 6 | // import javax.ws.rs.GET; 7 | // import javax.ws.rs.Path; 8 | // import javax.ws.rs.QueryParam; 9 | // 10 | // /** 11 | // * @author YL 12 | // */ 13 | // @Service(protocol = "rest") 14 | // @Path("/rest") 15 | // public class RestServiceImpl implements RestService { 16 | // 17 | // @GET 18 | // @Path("/get") 19 | // @Override 20 | // public String getName(@QueryParam("id") long id) { 21 | // return "user id: " + id; 22 | // } 23 | // } 24 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-sca/dubbo-sca-provider/src/main/resources/application-consul.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8080 3 | feign: 4 | hystrix: 5 | enabled: true 6 | dubbo: 7 | # scan: 8 | # base-packages: top.ylonline.dubbo.sca.service 9 | registry: 10 | address: spring-cloud://localhost 11 | protocols: 12 | dubbo: 13 | name: dubbo 14 | port: -1 15 | rest: 16 | name: rest 17 | port: 8081 18 | server: netty -------------------------------------------------------------------------------- /dubbo-examples/dubbo-sca/dubbo-sca-provider/src/main/resources/application-zk.yml: -------------------------------------------------------------------------------- 1 | #feign: 2 | # hystrix: 3 | # enabled: true 4 | dubbo: 5 | application: 6 | id: dubbo-sca-provider 7 | name: dubbo-sca-provider 8 | qos-enable: false 9 | # qos-port: 33333 10 | # qos: 11 | # enable: false 12 | # port: 33333 13 | # accept: 14 | # foreign: 15 | # ip: false 16 | registry: 17 | address: spring-cloud://localhost 18 | # address: zookeeper://192.168.56.101:2181 19 | protocol: 20 | name: dubbo 21 | port: -1 22 | # config: 23 | # multiple: true 24 | # protocols: 25 | # dubbo: 26 | # name: dubbo 27 | # port: -1 28 | # rest: 29 | # name: rest 30 | # port: 8081 31 | # server: netty 32 | 33 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-sca/dubbo-sca-provider/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: dubbo-sca-provider 4 | --- 5 | spring: 6 | profiles: zk 7 | cloud: 8 | zookeeper: 9 | enabled: true 10 | connect-string: 192.168.56.101:2181 -------------------------------------------------------------------------------- /dubbo-examples/dubbo-sca/dubbo-sca-provider/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | ${logger.pattern} 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-v2.6.x/dubbo-v2.6.x-api/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | top.ylonline.dubbo 6 | dubbo-v2.6.x 7 | 1.0-SNAPSHOT 8 | 9 | 4.0.0 10 | 11 | dubbo-v2.6.x-api 12 | Java 最佳实践 :: dubbo(${project.artifactId}) 13 | 14 | 15 | UTF-8 16 | 1.8 17 | 1.8 18 | 19 | 20 | 21 | 22 | 23 | org.jboss.resteasy 24 | resteasy-jaxrs 25 | provided 26 | true 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-v2.6.x/dubbo-v2.6.x-api/src/main/java/top/ylonline/dubbo/spring/boot/api/DubboService.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.dubbo.spring.boot.api; 2 | 3 | import javax.ws.rs.QueryParam; 4 | 5 | /** 6 | * @author YL 7 | */ 8 | public interface DubboService { 9 | /** 10 | * echo 11 | * 12 | * @param message msg 13 | * 14 | * @return 信息 15 | */ 16 | String echo(@QueryParam("message") String message); 17 | } 18 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-v2.6.x/dubbo-v2.6.x-api/src/main/java/top/ylonline/dubbo/spring/boot/api/MultipleService.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.dubbo.spring.boot.api; 2 | 3 | import javax.ws.rs.GET; 4 | import javax.ws.rs.Path; 5 | import javax.ws.rs.QueryParam; 6 | 7 | /** 8 | * @author YL 9 | */ 10 | @Path("/multiple") 11 | public interface MultipleService { 12 | /** 13 | * echo 14 | * 15 | * @param message msg 16 | * 17 | * @return 信息 18 | */ 19 | @GET 20 | @Path("/echo") 21 | String echo(@QueryParam("message") String message); 22 | } 23 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-v2.6.x/dubbo-v2.6.x-api/src/main/java/top/ylonline/dubbo/spring/boot/api/RestService.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.dubbo.spring.boot.api; 2 | 3 | import javax.ws.rs.GET; 4 | import javax.ws.rs.Path; 5 | import javax.ws.rs.QueryParam; 6 | 7 | /** 8 | * @author YL 9 | */ 10 | @Path("/single") 11 | public interface RestService { 12 | /** 13 | * echo 14 | * 15 | * @param message msg 16 | * 17 | * @return 信息 18 | */ 19 | @GET 20 | @Path("/echo") 21 | String echo(@QueryParam("message") String message); 22 | } 23 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-v2.6.x/dubbo-v2.6.x-consumer/src/main/java/top/ylonline/dubbo/spring/boot/DubboConsumer.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.dubbo.spring.boot; 2 | 3 | import com.alibaba.dubbo.config.spring.context.annotation.DubboComponentScan; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.boot.builder.SpringApplicationBuilder; 7 | import org.springframework.context.annotation.ImportResource; 8 | 9 | import java.util.Collections; 10 | 11 | /** 12 | * Hello world! 13 | * 14 | * @author YL 15 | */ 16 | @SpringBootApplication 17 | @ImportResource(locations = {"classpath:dubbo-consumer-${spring.profiles.active}.xml"}) 18 | @DubboComponentScan(basePackages = {"top.ylonline.dubbo.spring.boot"}) 19 | @Slf4j 20 | public class DubboConsumer { 21 | 22 | /** 23 | * Common 24 | */ 25 | private static SpringApplicationBuilder configureSpringBuilder(SpringApplicationBuilder builder) { 26 | // builder.application().addListeners(new EnvironmentPreparedEventListener()); 27 | builder.application().addPrimarySources(Collections.singletonList(DubboConsumer.class)); 28 | return builder.sources(DubboConsumer.class); 29 | } 30 | 31 | public static void main(String[] args) { 32 | configureSpringBuilder(new SpringApplicationBuilder()) 33 | .application() 34 | .run(args); 35 | } 36 | } 37 | 38 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-v2.6.x/dubbo-v2.6.x-consumer/src/main/java/top/ylonline/dubbo/spring/boot/controller/DemoController.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.dubbo.spring.boot.controller; 2 | 3 | import org.springframework.web.bind.annotation.GetMapping; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | import org.springframework.web.bind.annotation.RequestParam; 6 | import org.springframework.web.bind.annotation.RestController; 7 | import top.ylonline.dubbo.spring.boot.api.DubboService; 8 | import top.ylonline.dubbo.spring.boot.api.MultipleService; 9 | import top.ylonline.dubbo.spring.boot.api.RestService; 10 | 11 | import javax.annotation.Resource; 12 | 13 | /** 14 | * @author YL 15 | */ 16 | @RestController 17 | @RequestMapping("/demo") 18 | public class DemoController { 19 | /** 20 | * dubbo-2.6.5及以下版本的Reference还不支持protocol属性 21 | */ 22 | @Resource 23 | private MultipleService multipleService; 24 | @Resource 25 | private DubboService dubboService; 26 | @Resource 27 | private RestService restService; 28 | 29 | @GetMapping("/multiple") 30 | public String user(@RequestParam String message) { 31 | return multipleService.echo(message); 32 | } 33 | 34 | @GetMapping("/dubbo") 35 | public String dubbo(@RequestParam String message) { 36 | return dubboService.echo(message); 37 | } 38 | 39 | @GetMapping("/rest") 40 | public String rest(@RequestParam String message) { 41 | return restService.echo(message); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-v2.6.x/dubbo-v2.6.x-consumer/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8080 3 | servlet: 4 | context-path: / 5 | spring: 6 | profiles: 7 | active: zk 8 | application: 9 | name: dubbo-consumer 10 | #dubbo: 11 | # application: 12 | # name: dubbo-consumer 13 | # qos-enable: false 14 | # registry: 15 | # address: zookeeper://192.168.56.101:2181 16 | # client: curator 17 | # consumer: 18 | # check: 'false' 19 | # client: netty4 -------------------------------------------------------------------------------- /dubbo-examples/dubbo-v2.6.x/dubbo-v2.6.x-consumer/src/main/resources/dubbo-consumer-nacos.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 21 | 23 | 25 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-v2.6.x/dubbo-v2.6.x-consumer/src/main/resources/dubbo-consumer-zk.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 21 | 23 | 25 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-v2.6.x/dubbo-v2.6.x-consumer/src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | ${logger.pattern} 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-v2.6.x/dubbo-v2.6.x-provider/src/main/java/top/ylonline/dubbo/spring/boot/DubboProvider.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.dubbo.spring.boot; 2 | 3 | import com.alibaba.dubbo.config.spring.context.annotation.DubboComponentScan; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.boot.builder.SpringApplicationBuilder; 7 | 8 | import java.util.Collections; 9 | 10 | /** 11 | * Hello world! 12 | * 13 | * @author YL 14 | */ 15 | @SpringBootApplication 16 | @DubboComponentScan(basePackages = {"top.ylonline.dubbo.spring.boot"}) 17 | @Slf4j 18 | public class DubboProvider { 19 | 20 | /** 21 | * Common 22 | */ 23 | private static SpringApplicationBuilder configureSpringBuilder(SpringApplicationBuilder builder) { 24 | // builder.application().addListeners(new EnvironmentPreparedEventListener()); 25 | builder.application().addPrimarySources(Collections.singletonList(DubboProvider.class)); 26 | return builder.sources(DubboProvider.class); 27 | } 28 | 29 | public static void main(String[] args) { 30 | configureSpringBuilder(new SpringApplicationBuilder()) 31 | .application() 32 | .run(args); 33 | } 34 | } 35 | 36 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-v2.6.x/dubbo-v2.6.x-provider/src/main/java/top/ylonline/dubbo/spring/boot/service/DubboServiceImpl.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.dubbo.spring.boot.service; 2 | 3 | import com.alibaba.dubbo.config.annotation.Service; 4 | import com.alibaba.dubbo.rpc.RpcContext; 5 | import top.ylonline.dubbo.spring.boot.api.DubboService; 6 | 7 | import javax.ws.rs.QueryParam; 8 | 9 | /** 10 | * @author YL 11 | */ 12 | @Service(protocol = {"dubbo"}) 13 | public class DubboServiceImpl implements DubboService { 14 | 15 | @Override 16 | public String echo(@QueryParam("message") String message) { 17 | return "{\"message\": \"" + message + "\", \"protocol\": \"dubbo\", \"url\": \"" 18 | + RpcContext.getContext().getUrl() + "\"}"; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-v2.6.x/dubbo-v2.6.x-provider/src/main/java/top/ylonline/dubbo/spring/boot/service/MultipleServiceImpl.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.dubbo.spring.boot.service; 2 | 3 | import com.alibaba.dubbo.config.annotation.Service; 4 | import com.alibaba.dubbo.rpc.RpcContext; 5 | import top.ylonline.dubbo.spring.boot.api.MultipleService; 6 | 7 | import javax.ws.rs.QueryParam; 8 | 9 | /** 10 | * @author YL 11 | */ 12 | @Service(protocol = {"dubbo", "rest"}) 13 | // @Path("/multiple") 14 | public class MultipleServiceImpl implements MultipleService { 15 | 16 | // @GET 17 | // @Path("/echo") 18 | @Override 19 | public String echo(@QueryParam("message") String message) { 20 | return "{\"message\": \"" 21 | + message + "\", \"protocol\": \"dubbo + rest\", \"url\": \"" 22 | + RpcContext.getContext().getUrl() + "\"}"; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-v2.6.x/dubbo-v2.6.x-provider/src/main/java/top/ylonline/dubbo/spring/boot/service/RestServiceImpl.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.dubbo.spring.boot.service; 2 | 3 | import com.alibaba.dubbo.config.annotation.Service; 4 | import com.alibaba.dubbo.rpc.RpcContext; 5 | import top.ylonline.dubbo.spring.boot.api.RestService; 6 | 7 | import javax.ws.rs.QueryParam; 8 | 9 | /** 10 | * @author YL 11 | */ 12 | @Service(protocol = {"rest"}) 13 | // @Path("/single") 14 | public class RestServiceImpl implements RestService { 15 | 16 | // @GET 17 | // @Path("/echo") 18 | @Override 19 | public String echo(@QueryParam("message") String message) { 20 | return "{\"message\": \"" + message + "\", \"protocol\": \"rest\", \"url\": \"" 21 | + RpcContext.getContext().getUrl() + "\"}"; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-v2.6.x/dubbo-v2.6.x-provider/src/main/resources/application-nacos.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: dubbo-provider 4 | dubbo: 5 | application: 6 | name: dubbo-provider 7 | qos-enable: false 8 | registry: 9 | address: nacos://192.168.56.101:8848 10 | # register: false 11 | # protocol: 12 | # name: dubbo 13 | # port: 20880 14 | # server: netty4 15 | # protocol: 16 | # name: rest 17 | # port: 9090 18 | # server: netty 19 | config: 20 | multiple: true 21 | protocols: 22 | dubbo: 23 | name: dubbo 24 | port: -1 25 | server: netty4 26 | rest: 27 | name: rest 28 | port: 9090 29 | server: netty 30 | provider: 31 | delay: -1 32 | timeout: 20000 33 | retries: 0 -------------------------------------------------------------------------------- /dubbo-examples/dubbo-v2.6.x/dubbo-v2.6.x-provider/src/main/resources/application-zk.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: dubbo-provider 4 | dubbo: 5 | application: 6 | name: dubbo-provider 7 | qos-enable: false 8 | registry: 9 | address: zookeeper://192.168.56.101:2181 10 | client: curator 11 | # protocol: 12 | # name: dubbo 13 | # port: 20880 14 | # server: netty4 15 | # protocol: 16 | # name: rest 17 | # port: 9090 18 | # server: netty 19 | config: 20 | multiple: true 21 | protocols: 22 | dubbo: 23 | name: dubbo 24 | port: -1 25 | server: netty4 26 | rest: 27 | name: rest 28 | port: 9090 29 | server: netty 30 | provider: 31 | delay: -1 32 | timeout: 20000 33 | retries: 0 -------------------------------------------------------------------------------- /dubbo-examples/dubbo-v2.6.x/dubbo-v2.6.x-provider/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | profiles: 3 | active: zk -------------------------------------------------------------------------------- /dubbo-examples/dubbo-v2.6.x/dubbo-v2.6.x-provider/src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | ${logger.pattern} 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-v2.7.x/README.md: -------------------------------------------------------------------------------- 1 | # dubbo-v2.7.x 2 | > 环境: 3 | > dubbo 2.7.1 4 | > duboo-spring-boot-starter 2.7.1 5 | 6 | 7 | 8 | ## 启动 provider 9 | 10 | 访问以下地址来判断`provider`端使用多协议是否正常 11 | 12 | [http://localhost:9090/single/echo?message=rest-protocol](http://localhost:9090/single/echo?message=rest-protocol) 13 | 14 | [http://localhost:9090//multiple/echo?message=dubbo-or-rest-protocol](http://localhost:9090/multiple/echo?message=dubbo-or-rest-protocol) 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | ## 启动 consumer 23 | 24 | 分别访问以下地址来判断`consumer`端使用多协议是否正常 25 | - [http://localhost:8080/demo/dubbo?message=dubbo-protocol](http://localhost:8080/demo/dubbo?message=dubbo-protocol) 26 | - [http://localhost:8080/demo/rest?message=rest-protocol](http://localhost:8080/demo/rest?message=rest-protocol) 27 | - [http://localhost:8080/demo/multiple?message=dubbo-or-rest-protocol](http://localhost:8080/demo/multiple?message=dubbo-or-rest-protocol) 28 | 29 | 30 | 31 | ## 异常问题 32 | 33 | ### java.lang.NoClassDefFoundError: org/jboss/resteasy/client/jaxrs/engines/ApacheHttpClient4Engine 34 | 35 | > 需要添加以下依赖包,该依赖 provider 端无需依赖,consumer 端需要依赖 36 | 37 | ```xml 38 | 39 | org.jboss.resteasy 40 | resteasy-client 41 | ${resteasy-client.version} 42 | 43 | ``` 44 | 45 | 46 | 47 | ### java.lang.RuntimeException: You must use at least one, but no more than one http method annotation on: top.ylonline 48 | .dubbo.spring.boot.example.api.EchoService.echo.. 49 | 50 | > 出现这个异常,说明要在使用的接口标注:@Path、@POST、@Get等javax.ws.rs.*这个路径下相关注解,不应该在实现类标注 51 | 52 | 53 | 54 | ```java 55 | package top.ylonline.dubbo.spring.boot.api; 56 | 57 | import javax.ws.rs.GET; 58 | import javax.ws.rs.Path; 59 | import javax.ws.rs.QueryParam; 60 | 61 | /** 62 | * @author YL 63 | */ 64 | @Path("/single") 65 | public interface RestService { 66 | /** 67 | * echo 68 | * 69 | * @param message msg 70 | * 71 | * @return 信息 72 | */ 73 | @GET 74 | @Path("/echo") 75 | String echo(@QueryParam("message") String message); 76 | } 77 | ``` 78 | 79 | ### Duplicate application configs 80 | 当使用`org.apache.dubbo:dubbo-spring-boot-starter` 2.7.0,同时使用xml作为`dubbo`的配置时,会出现以下异常: 81 | ```text 82 | Caused by: java.lang.IllegalStateException: Duplicate application configs: and 83 | ``` -------------------------------------------------------------------------------- /dubbo-examples/dubbo-v2.7.x/dubbo-v2.7.x-api/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | top.ylonline.dubbo 6 | dubbo-v2.7.x 7 | 1.0-SNAPSHOT 8 | 9 | 4.0.0 10 | 11 | dubbo-v2.7.x-api 12 | Java 最佳实践 :: dubbo(${project.artifactId}) 13 | 14 | 15 | UTF-8 16 | 1.8 17 | 1.8 18 | 19 | 20 | 21 | 22 | 23 | org.jboss.resteasy 24 | resteasy-jaxrs 25 | provided 26 | true 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-v2.7.x/dubbo-v2.7.x-api/src/main/java/top/ylonline/dubbo27x/api/DubboService.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.dubbo27x.api; 2 | 3 | /** 4 | * @author YL 5 | */ 6 | public interface DubboService { 7 | /** 8 | * echo 9 | * 10 | * @param message msg 11 | * 12 | * @return 信息 13 | */ 14 | String echo(String message); 15 | } 16 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-v2.7.x/dubbo-v2.7.x-api/src/main/java/top/ylonline/dubbo27x/api/MultipleService.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.dubbo27x.api; 2 | 3 | import javax.ws.rs.GET; 4 | import javax.ws.rs.Path; 5 | import javax.ws.rs.QueryParam; 6 | 7 | /** 8 | * @author YL 9 | */ 10 | @Path("/multiple") 11 | public interface MultipleService { 12 | /** 13 | * echo 14 | * 15 | * @param message msg 16 | * 17 | * @return 信息 18 | */ 19 | @GET 20 | @Path("/echo") 21 | String echo(@QueryParam("message") String message); 22 | } 23 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-v2.7.x/dubbo-v2.7.x-api/src/main/java/top/ylonline/dubbo27x/api/RestService.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.dubbo27x.api; 2 | 3 | import javax.ws.rs.GET; 4 | import javax.ws.rs.Path; 5 | import javax.ws.rs.QueryParam; 6 | 7 | /** 8 | * @author YL 9 | */ 10 | @Path("/single") 11 | public interface RestService { 12 | /** 13 | * echo 14 | * 15 | * @param message msg 16 | * 17 | * @return 信息 18 | */ 19 | @GET 20 | @Path("/echo") 21 | String echo(@QueryParam("message") String message); 22 | } 23 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-v2.7.x/dubbo-v2.7.x-consumer/src/main/java/top/ylonline/dubbo27x/DubboConsumer270.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.dubbo27x; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; 6 | import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration; 7 | import org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration; 8 | 9 | /** 10 | * @author YL 11 | */ 12 | @SpringBootApplication( 13 | exclude = { 14 | DataSourceAutoConfiguration.class, 15 | WebSocketServletAutoConfiguration.class, 16 | JmxAutoConfiguration.class 17 | } 18 | ) 19 | // @ImportResource(locations = {"classpath:dubbo-consumer-${spring.profiles.active}.xml"}) 20 | public class DubboConsumer270 { 21 | 22 | public static void main(String[] args) { 23 | SpringApplication.run(DubboConsumer270.class, args); 24 | } 25 | } 26 | 27 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-v2.7.x/dubbo-v2.7.x-consumer/src/main/java/top/ylonline/dubbo27x/controller/DemoController.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.dubbo27x.controller; 2 | 3 | import org.apache.dubbo.config.annotation.Reference; 4 | import org.springframework.web.bind.annotation.GetMapping; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.bind.annotation.RequestParam; 7 | import org.springframework.web.bind.annotation.RestController; 8 | import top.ylonline.dubbo27x.api.DubboService; 9 | import top.ylonline.dubbo27x.api.MultipleService; 10 | import top.ylonline.dubbo27x.api.RestService; 11 | 12 | /** 13 | * @author YL 14 | */ 15 | @RestController 16 | @RequestMapping("/demo") 17 | public class DemoController { 18 | // @Resource 19 | // private MultipleService multipleService; 20 | // @Resource 21 | // private DubboService dubboService; 22 | // @Resource 23 | // private RestService restService; 24 | 25 | @Reference(protocol = "dubbo") 26 | private MultipleService multipleService; 27 | @Reference 28 | private DubboService dubboService; 29 | @Reference 30 | private RestService restService; 31 | 32 | @GetMapping("/multiple") 33 | public String user(@RequestParam String message) { 34 | return multipleService.echo(message); 35 | } 36 | 37 | @GetMapping("/dubbo") 38 | public String dubbo(@RequestParam String message) { 39 | return dubboService.echo(message); 40 | } 41 | 42 | @GetMapping("/rest") 43 | public String rest(@RequestParam String message) { 44 | return restService.echo(message); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-v2.7.x/dubbo-v2.7.x-consumer/src/main/resources/application-zk.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8080 3 | servlet: 4 | context-path: / 5 | spring: 6 | application: 7 | name: dubbo-consumer-2.7.x 8 | dubbo: 9 | scan: 10 | base-packages: top.ylonline.dubbo27x 11 | application: 12 | name: ${spring.application.name} 13 | qos-enable: false 14 | registry: 15 | address: zookeeper://192.168.56.101:2181 16 | client: curator 17 | simplified: true 18 | metadata-report: 19 | address: ${dubbo.registry.address} 20 | consumer: 21 | check: false 22 | client: netty -------------------------------------------------------------------------------- /dubbo-examples/dubbo-v2.7.x/dubbo-v2.7.x-consumer/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | profiles: 3 | active: zk 4 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-v2.7.x/dubbo-v2.7.x-consumer/src/main/resources/dubbo-consumer-zk.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 20 | 22 | 24 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-v2.7.x/dubbo-v2.7.x-consumer/src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | ${logger.pattern} 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-v2.7.x/dubbo-v2.7.x-provider/src/main/java/top/ylonline/dubbo27x/DubboProvider270.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.dubbo27x; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | /** 7 | * @author YL 8 | */ 9 | @SpringBootApplication 10 | public class DubboProvider270 { 11 | 12 | public static void main(String[] args) { 13 | SpringApplication.run(DubboProvider270.class, args); 14 | } 15 | } 16 | 17 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-v2.7.x/dubbo-v2.7.x-provider/src/main/java/top/ylonline/dubbo27x/service/DubboServiceImpl.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.dubbo27x.service; 2 | 3 | import org.apache.dubbo.config.annotation.Service; 4 | import org.apache.dubbo.rpc.RpcContext; 5 | import top.ylonline.dubbo27x.api.DubboService; 6 | 7 | /** 8 | * @author YL 9 | */ 10 | @Service(protocol = {"dubbo"}) 11 | public class DubboServiceImpl implements DubboService { 12 | 13 | @Override 14 | public String echo(String message) { 15 | return "{\"message\": \"" + message + "\", \"protocol\": \"dubbo\", \"url\": \"" 16 | + RpcContext.getContext().getUrl() + "\"}"; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-v2.7.x/dubbo-v2.7.x-provider/src/main/java/top/ylonline/dubbo27x/service/MultipleServiceImpl.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.dubbo27x.service; 2 | 3 | import org.apache.dubbo.config.annotation.Service; 4 | import org.apache.dubbo.rpc.RpcContext; 5 | import top.ylonline.dubbo27x.api.MultipleService; 6 | 7 | import javax.ws.rs.QueryParam; 8 | 9 | /** 10 | * @author YL 11 | */ 12 | @Service(protocol = {"dubbo", "rest"}) 13 | // @Path("/multiple") 14 | public class MultipleServiceImpl implements MultipleService { 15 | 16 | // @GET 17 | // @Path("/echo") 18 | @Override 19 | public String echo(@QueryParam("message") String message) { 20 | return "{\"message\": \"" 21 | + message + "\", \"protocol\": \"dubbo + rest\", \"url\": \"" 22 | + RpcContext.getContext().getUrl() + "\"}"; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-v2.7.x/dubbo-v2.7.x-provider/src/main/java/top/ylonline/dubbo27x/service/RestServiceImpl.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.dubbo27x.service; 2 | 3 | import org.apache.dubbo.config.annotation.Service; 4 | import org.apache.dubbo.rpc.RpcContext; 5 | import top.ylonline.dubbo27x.api.RestService; 6 | 7 | import javax.ws.rs.QueryParam; 8 | 9 | /** 10 | * @author YL 11 | */ 12 | @Service(protocol = {"rest"}) 13 | // @Path("/single") 14 | public class RestServiceImpl implements RestService { 15 | 16 | // @GET 17 | // @Path("/echo") 18 | @Override 19 | public String echo(@QueryParam("message") String message) { 20 | return "{\"message\": \"" + message + "\", \"protocol\": \"rest\", \"url\": \"" 21 | + RpcContext.getContext().getUrl() + "\"}"; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-v2.7.x/dubbo-v2.7.x-provider/src/main/resources/application-nacos.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: dubbo-provider-2.7.x 4 | dubbo: 5 | scan: 6 | base-packages: top.ylonline.dubbo27x 7 | application: 8 | name: dubbo-provider-2.7.x 9 | qos-enable: false 10 | registry: 11 | address: nacos://192.168.56.101:8848 12 | # register: false 13 | # protocol: 14 | # name: dubbo 15 | # port: 20880 16 | # server: netty4 17 | # protocol: 18 | # name: rest 19 | # port: 9090 20 | # server: netty 21 | config: 22 | multiple: true 23 | protocols: 24 | dubbo: 25 | name: dubbo 26 | port: -1 27 | server: netty 28 | rest: 29 | name: rest 30 | port: 9090 31 | server: netty 32 | provider: 33 | delay: -1 34 | timeout: 20000 35 | retries: 0 -------------------------------------------------------------------------------- /dubbo-examples/dubbo-v2.7.x/dubbo-v2.7.x-provider/src/main/resources/application-zk.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: dubbo-provider-2.7.x 4 | dubbo: 5 | scan: 6 | base-packages: top.ylonline.dubbo27x 7 | application: 8 | name: ${spring.application.name} 9 | qos-enable: false 10 | registry: 11 | address: zookeeper://192.168.56.101:2181 12 | client: curator 13 | simplified: true 14 | metadata-report: 15 | address: ${dubbo.registry.address} 16 | # protocol: 17 | # name: dubbo 18 | # port: -1 19 | # server: netty 20 | # protocol: 21 | # name: rest 22 | # port: 9090 23 | # server: netty 24 | config: 25 | multiple: true 26 | protocols: 27 | dubbo: 28 | name: dubbo 29 | port: -1 30 | server: netty 31 | rest: 32 | name: rest 33 | port: 9090 34 | server: netty 35 | provider: 36 | delay: -1 37 | timeout: 20000 38 | retries: 0 -------------------------------------------------------------------------------- /dubbo-examples/dubbo-v2.7.x/dubbo-v2.7.x-provider/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | profiles: 3 | active: zk -------------------------------------------------------------------------------- /dubbo-examples/dubbo-v2.7.x/dubbo-v2.7.x-provider/src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | ${logger.pattern} 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /dubbo-examples/dubbo-v2.7.x/元数据中心配置.md: -------------------------------------------------------------------------------- 1 | # 元数据中心配置 2 | > 环境: 3 | > dubbo 2.7.0 4 | > duboo-spring-boot-starter 2.7.0 5 | 6 | ## zookeeper 7 | ```yaml 8 | dubbo: 9 | scan: 10 | base-packages: top.ylonline.dubbo27x 11 | application: 12 | name: dubbo-provider-2.7.x 13 | qos-enable: false 14 | registry: 15 | address: zookeeper://192.168.56.101:2181 16 | client: curator 17 | simplified: true 18 | metadata-report: 19 | address: ${dubbo.registry.address} 20 | ``` 21 | 22 | ```xml 23 | 24 | 25 | org.apache.dubbo 26 | dubbo 27 | 28 | 29 | 30 | com.google.code.gson 31 | gson 32 | 33 | ``` 34 | 35 | ## redis 36 | ```yaml 37 | dubbo: 38 | scan: 39 | base-packages: top.ylonline.dubbo27x 40 | application: 41 | name: dubbo-provider-2.7.x 42 | qos-enable: false 43 | registry: 44 | address: zookeeper://192.168.56.101:2181 45 | client: curator 46 | simplified: true 47 | metadata-report: 48 | address: redis://192.168.56.101:6379 49 | ``` 50 | 51 | ```xml 52 | 53 | 54 | org.apache.dubbo 55 | dubbo 56 | 57 | 58 | 59 | com.google.code.gson 60 | gson 61 | 62 | 63 | redis.clients 64 | jedis 65 | 66 | ``` -------------------------------------------------------------------------------- /dubbo-examples/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | top.ylonline 6 | java-best-practice 7 | 1.0-SNAPSHOT 8 | 9 | 4.0.0 10 | 11 | top.ylonline.dubbo 12 | dubbo-examples 13 | Java 最佳实践 :: dubbo 14 | pom 15 | 16 | 17 | dubbo-v2.6.x 18 | dubbo-v2.7.x 19 | dubbo-sca 20 | 21 | 22 | 23 | UTF-8 24 | 1.8 25 | 1.8 26 | 27 | 28 | -------------------------------------------------------------------------------- /encrypt-examples/frontend-backend-encrypt-with-rsa/README.md: -------------------------------------------------------------------------------- 1 | # 前后端分离数据加密传输 2 | 3 | ## RSA 非对称加密算法 4 | 1977年,三位数学家Rivest、Shamir 和 Adleman 设计了一种算法,可以实现非对称加密。这种算法用他们三个人的名字命名,叫做RSA算法。 5 | 6 | 7 | 这种算法非常可靠,密钥越长,它就越难破解。根据已经披露的文献,目前被破解的最长RSA密钥是768个二进制位。也就是说,长度超过768位的密钥,还无法破解(至少没人公开宣布)。可以认为,1024位的RSA密钥基本安全,2048位的密钥极其安全。 8 | 9 | > 本例子使用的密钥长度为:1024 10 | > 请看 RsaUtils 类 KEY_SIZE 变量 11 | 12 | 13 | ## 原理 14 | 15 | > 后端传输到前端 16 | 17 | 后端使用`AES`加密数据,并使用`RSA私钥`加密`AES密钥`; 18 | 19 | 前端使用`RSA公钥`解密`AES密钥`,再使用解密后的`AES密钥`解密数据。 20 | 21 | > 前端传输到后端 22 | 23 | 前端使用`AES`加密数据,并使用`RSA公钥`加密`AES密钥`; 24 | 25 | 后端使用`RSA私钥`解密前端传过来的`AES密钥`,再使用`RSA`解密后的`AES 密钥`解密数据。 26 | 27 | 28 | ## 为什么使用 RSA 加密 AES 的密钥 29 | 用对称加密算法(比如:`AES`)来加密消息,然后利用`RSA 30 | `称加密算法加密密钥传递。因为在同等安全等级下,`RSA`加密算法作为一种非对称密码学系统,通常比对称加密体制要慢。对称加密算法的密钥和要传递的消息相比通常要短得多,所以相比之下使用`RSA`加密密钥然后用对称加密来加密任意长度的消息,这样要更快很多。 31 | 32 | 33 | ## AES demo 34 | [http://localhost:8087/demo/aes](http://localhost:8087/demo/aes),打开浏览器控制台查看日志输出 35 | 36 | 37 | ## RSA demo 38 | [http://localhost:8087/demo/rsa](http://localhost:8087/demo/rsa),打开浏览器控制台查看日志输出 -------------------------------------------------------------------------------- /encrypt-examples/frontend-backend-encrypt-with-rsa/src/main/java/top/ylonline/encrypt/FrontendBackendEncryptWithRsaApp.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.encrypt; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | /** 7 | * Hello world! 8 | * 9 | * @author YL 10 | */ 11 | @SpringBootApplication 12 | public class FrontendBackendEncryptWithRsaApp { 13 | 14 | public static void main(String[] args) { 15 | SpringApplication.run(FrontendBackendEncryptWithRsaApp.class, args); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /encrypt-examples/frontend-backend-encrypt-with-rsa/src/main/java/top/ylonline/encrypt/common/Const.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.encrypt.common; 2 | 3 | /** 4 | * @author YL 5 | */ 6 | public class Const { 7 | /** 8 | * 原始字符串:明文 9 | */ 10 | public static final String STR = "测试123abc"; 11 | 12 | /** 13 | * rsa 模 14 | */ 15 | public static final String MODULUS = 16 | "bdfb837d5fc8de0a6408b8720cdd557e08b4af0ebf9552311e8e89352fc7390b91ce3d84b20a36fe80c1aae279a68b04338724565b47052f19fc57c109e54bbeba5318b55ed472f6798a2828d1e8b61984b8d586e932ee2cfbc26155f3ae47df6aa1993d38d80d9c061c016e514d78f296055a44299b7c5de6cc74a376fa535f"; 17 | /** 18 | * rsa 私钥指数 19 | */ 20 | public static final String PRIVATE_EXPONENT = 21 | "7414f626e91be6f01a6769abe648673077494f9d875a49ba519d6e20dd6cb1626c58c4260c53497f00555580c42c0acd2a5eecc90744c1da21da9a140d63d97f45f92a1d05cc177edf19a2f360786d06058d5aee21ec7527b0006531497986498dd8204aa45eecebcc73c63454617d482a1144cf6f6e3fd85098d3d163aa2421"; 22 | /** 23 | * rsa 公钥指数 24 | */ 25 | public static final String PUBLIC_EXPONENT = "10001"; 26 | } 27 | -------------------------------------------------------------------------------- /encrypt-examples/frontend-backend-encrypt-with-rsa/src/main/java/top/ylonline/encrypt/controller/DemoController.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.encrypt.controller; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.ui.Model; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import top.ylonline.encrypt.common.Const; 8 | import top.ylonline.encrypt.util.AesUtils; 9 | import top.ylonline.encrypt.util.RsaUtils; 10 | 11 | /** 12 | * @author YL 13 | */ 14 | @Controller 15 | @RequestMapping("/demo") 16 | public class DemoController { 17 | 18 | @GetMapping("/aes") 19 | public String aes(Model model) { 20 | model.addAttribute("str", Const.STR); 21 | String key = AesUtils.randomKey(); 22 | model.addAttribute("key", key); 23 | // 加密后的明文 24 | model.addAttribute("encrypt", AesUtils.encrypt(key, "UTF-8", Const.STR)); 25 | return "aes"; 26 | } 27 | 28 | @GetMapping("/rsa") 29 | public String rsa(Model model) { 30 | model.addAttribute("str", Const.STR); 31 | model.addAttribute("modulus", Const.MODULUS); 32 | // todo 私钥禁止传到前端(这里是为了测试),公钥可以传到前端 33 | model.addAttribute("privateExponent", Const.PRIVATE_EXPONENT); 34 | model.addAttribute("publicExponent", Const.PUBLIC_EXPONENT); 35 | 36 | // 私钥加密后的明文 37 | model.addAttribute("encrypt", RsaUtils.encryptPrivate(Const.MODULUS, Const.PRIVATE_EXPONENT, Const.STR)); 38 | return "rsa"; 39 | } 40 | 41 | @GetMapping("/rsa-and-aes") 42 | public String rsaAndAes(Model model) { 43 | String aesKey = ""; 44 | model.addAttribute("str", Const.STR); 45 | model.addAttribute("modulus", Const.MODULUS); 46 | // todo 私钥禁止传到前端(这里是为了测试),公钥可以传到前端 47 | model.addAttribute("privateExponent", Const.PRIVATE_EXPONENT); 48 | model.addAttribute("publicExponent", Const.PUBLIC_EXPONENT); 49 | 50 | // aes 加密数据 51 | model.addAttribute("encryptData", AesUtils.encrypt(aesKey, "UTF-8", Const.STR)); 52 | 53 | // rsa 加密 aes 密钥 54 | model.addAttribute("encryptAesKey", RsaUtils.encryptPrivate(Const.MODULUS, Const.PRIVATE_EXPONENT, aesKey)); 55 | return "rsa-and-aes"; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /encrypt-examples/frontend-backend-encrypt-with-rsa/src/main/java/top/ylonline/encrypt/util/EncryptException.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.encrypt.util; 2 | 3 | /** 4 | * 统一异常封装 5 | * 6 | * @author YL 7 | */ 8 | public class EncryptException extends RuntimeException { 9 | private static final long serialVersionUID = 1L; 10 | 11 | public EncryptException(String msg) { 12 | super(msg); 13 | } 14 | 15 | public EncryptException(Exception cause) { 16 | super(cause); 17 | } 18 | 19 | public EncryptException(String msg, Exception cause) { 20 | super(msg, cause); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /encrypt-examples/frontend-backend-encrypt-with-rsa/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8087 3 | servlet: 4 | context-path: / 5 | -------------------------------------------------------------------------------- /encrypt-examples/frontend-backend-encrypt-with-rsa/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | ${logger.pattern} 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /encrypt-examples/frontend-backend-encrypt-with-rsa/src/main/resources/static/crypto-js/format-hex.js: -------------------------------------------------------------------------------- 1 | (function (undefined) { 2 | // Shortcuts 3 | var C = CryptoJS; 4 | var C_lib = C.lib; 5 | var CipherParams = C_lib.CipherParams; 6 | var C_enc = C.enc; 7 | var Hex = C_enc.Hex; 8 | var C_format = C.format; 9 | 10 | var HexFormatter = C_format.Hex = { 11 | /** 12 | * Converts the ciphertext of a cipher params object to a hexadecimally encoded string. 13 | * 14 | * @param {CipherParams} cipherParams The cipher params object. 15 | * 16 | * @return {string} The hexadecimally encoded string. 17 | * 18 | * @static 19 | * 20 | * @example 21 | * 22 | * var hexString = CryptoJS.format.Hex.stringify(cipherParams); 23 | */ 24 | stringify: function (cipherParams) { 25 | return cipherParams.ciphertext.toString(Hex); 26 | }, 27 | 28 | /** 29 | * Converts a hexadecimally encoded ciphertext string to a cipher params object. 30 | * 31 | * @param {string} input The hexadecimally encoded string. 32 | * 33 | * @return {CipherParams} The cipher params object. 34 | * 35 | * @static 36 | * 37 | * @example 38 | * 39 | * var cipherParams = CryptoJS.format.Hex.parse(hexString); 40 | */ 41 | parse: function (input) { 42 | var ciphertext = Hex.parse(input); 43 | return CipherParams.create({ ciphertext: ciphertext }); 44 | } 45 | }; 46 | }()); 47 | -------------------------------------------------------------------------------- /encrypt-examples/frontend-backend-encrypt-with-rsa/src/main/resources/static/crypto-js/lib-typedarrays.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | // Check if typed arrays are supported 3 | if (typeof ArrayBuffer != 'function') { 4 | return; 5 | } 6 | 7 | // Shortcuts 8 | var C = CryptoJS; 9 | var C_lib = C.lib; 10 | var WordArray = C_lib.WordArray; 11 | 12 | // Reference original init 13 | var superInit = WordArray.init; 14 | 15 | // Augment WordArray.init to handle typed arrays 16 | var subInit = WordArray.init = function (typedArray) { 17 | // Convert buffers to uint8 18 | if (typedArray instanceof ArrayBuffer) { 19 | typedArray = new Uint8Array(typedArray); 20 | } 21 | 22 | // Convert other array views to uint8 23 | if ( 24 | typedArray instanceof Int8Array || 25 | (typeof Uint8ClampedArray !== "undefined" && typedArray instanceof Uint8ClampedArray) || 26 | typedArray instanceof Int16Array || 27 | typedArray instanceof Uint16Array || 28 | typedArray instanceof Int32Array || 29 | typedArray instanceof Uint32Array || 30 | typedArray instanceof Float32Array || 31 | typedArray instanceof Float64Array 32 | ) { 33 | typedArray = new Uint8Array(typedArray.buffer, typedArray.byteOffset, typedArray.byteLength); 34 | } 35 | 36 | // Handle Uint8Array 37 | if (typedArray instanceof Uint8Array) { 38 | // Shortcut 39 | var typedArrayByteLength = typedArray.byteLength; 40 | 41 | // Extract bytes 42 | var words = []; 43 | for (var i = 0; i < typedArrayByteLength; i++) { 44 | words[i >>> 2] |= typedArray[i] << (24 - (i % 4) * 8); 45 | } 46 | 47 | // Initialize this word array 48 | superInit.call(this, words, typedArrayByteLength); 49 | } else { 50 | // Else call normal init 51 | superInit.apply(this, arguments); 52 | } 53 | }; 54 | 55 | subInit.prototype = WordArray; 56 | }()); 57 | -------------------------------------------------------------------------------- /encrypt-examples/frontend-backend-encrypt-with-rsa/src/main/resources/static/crypto-js/mode-cfb.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Cipher Feedback block mode. 3 | */ 4 | CryptoJS.mode.CFB = (function () { 5 | var CFB = CryptoJS.lib.BlockCipherMode.extend(); 6 | 7 | CFB.Encryptor = CFB.extend({ 8 | processBlock: function (words, offset) { 9 | // Shortcuts 10 | var cipher = this._cipher; 11 | var blockSize = cipher.blockSize; 12 | 13 | generateKeystreamAndEncrypt.call(this, words, offset, blockSize, cipher); 14 | 15 | // Remember this block to use with next block 16 | this._prevBlock = words.slice(offset, offset + blockSize); 17 | } 18 | }); 19 | 20 | CFB.Decryptor = CFB.extend({ 21 | processBlock: function (words, offset) { 22 | // Shortcuts 23 | var cipher = this._cipher; 24 | var blockSize = cipher.blockSize; 25 | 26 | // Remember this block to use with next block 27 | var thisBlock = words.slice(offset, offset + blockSize); 28 | 29 | generateKeystreamAndEncrypt.call(this, words, offset, blockSize, cipher); 30 | 31 | // This block becomes the previous block 32 | this._prevBlock = thisBlock; 33 | } 34 | }); 35 | 36 | function generateKeystreamAndEncrypt(words, offset, blockSize, cipher) { 37 | // Shortcut 38 | var iv = this._iv; 39 | 40 | // Generate keystream 41 | if (iv) { 42 | var keystream = iv.slice(0); 43 | 44 | // Remove IV for subsequent blocks 45 | this._iv = undefined; 46 | } else { 47 | var keystream = this._prevBlock; 48 | } 49 | cipher.encryptBlock(keystream, 0); 50 | 51 | // Encrypt 52 | for (var i = 0; i < blockSize; i++) { 53 | words[offset + i] ^= keystream[i]; 54 | } 55 | } 56 | 57 | return CFB; 58 | }()); 59 | -------------------------------------------------------------------------------- /encrypt-examples/frontend-backend-encrypt-with-rsa/src/main/resources/static/crypto-js/mode-ctr-gladman.js: -------------------------------------------------------------------------------- 1 | /** @preserve 2 | * Counter block mode compatible with Dr Brian Gladman fileenc.c 3 | * derived from CryptoJS.mode.CTR 4 | * Jan Hruby jhruby.web@gmail.com 5 | */ 6 | CryptoJS.mode.CTRGladman = (function () { 7 | var CTRGladman = CryptoJS.lib.BlockCipherMode.extend(); 8 | 9 | function incWord(word) 10 | { 11 | if (((word >> 24) & 0xff) === 0xff) { //overflow 12 | var b1 = (word >> 16)&0xff; 13 | var b2 = (word >> 8)&0xff; 14 | var b3 = word & 0xff; 15 | 16 | if (b1 === 0xff) // overflow b1 17 | { 18 | b1 = 0; 19 | if (b2 === 0xff) 20 | { 21 | b2 = 0; 22 | if (b3 === 0xff) 23 | { 24 | b3 = 0; 25 | } 26 | else 27 | { 28 | ++b3; 29 | } 30 | } 31 | else 32 | { 33 | ++b2; 34 | } 35 | } 36 | else 37 | { 38 | ++b1; 39 | } 40 | 41 | word = 0; 42 | word += (b1 << 16); 43 | word += (b2 << 8); 44 | word += b3; 45 | } 46 | else 47 | { 48 | word += (0x01 << 24); 49 | } 50 | return word; 51 | } 52 | 53 | function incCounter(counter) 54 | { 55 | if ((counter[0] = incWord(counter[0])) === 0) 56 | { 57 | // encr_data in fileenc.c from Dr Brian Gladman's counts only with DWORD j < 8 58 | counter[1] = incWord(counter[1]); 59 | } 60 | return counter; 61 | } 62 | 63 | var Encryptor = CTRGladman.Encryptor = CTRGladman.extend({ 64 | processBlock: function (words, offset) { 65 | // Shortcuts 66 | var cipher = this._cipher 67 | var blockSize = cipher.blockSize; 68 | var iv = this._iv; 69 | var counter = this._counter; 70 | 71 | // Generate keystream 72 | if (iv) { 73 | counter = this._counter = iv.slice(0); 74 | 75 | // Remove IV for subsequent blocks 76 | this._iv = undefined; 77 | } 78 | 79 | incCounter(counter); 80 | 81 | var keystream = counter.slice(0); 82 | cipher.encryptBlock(keystream, 0); 83 | 84 | // Encrypt 85 | for (var i = 0; i < blockSize; i++) { 86 | words[offset + i] ^= keystream[i]; 87 | } 88 | } 89 | }); 90 | 91 | CTRGladman.Decryptor = Encryptor; 92 | 93 | return CTRGladman; 94 | }()); 95 | 96 | 97 | -------------------------------------------------------------------------------- /encrypt-examples/frontend-backend-encrypt-with-rsa/src/main/resources/static/crypto-js/mode-ctr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Counter block mode. 3 | */ 4 | CryptoJS.mode.CTR = (function () { 5 | var CTR = CryptoJS.lib.BlockCipherMode.extend(); 6 | 7 | var Encryptor = CTR.Encryptor = CTR.extend({ 8 | processBlock: function (words, offset) { 9 | // Shortcuts 10 | var cipher = this._cipher 11 | var blockSize = cipher.blockSize; 12 | var iv = this._iv; 13 | var counter = this._counter; 14 | 15 | // Generate keystream 16 | if (iv) { 17 | counter = this._counter = iv.slice(0); 18 | 19 | // Remove IV for subsequent blocks 20 | this._iv = undefined; 21 | } 22 | var keystream = counter.slice(0); 23 | cipher.encryptBlock(keystream, 0); 24 | 25 | // Increment counter 26 | counter[blockSize - 1] = (counter[blockSize - 1] + 1) | 0 27 | 28 | // Encrypt 29 | for (var i = 0; i < blockSize; i++) { 30 | words[offset + i] ^= keystream[i]; 31 | } 32 | } 33 | }); 34 | 35 | CTR.Decryptor = Encryptor; 36 | 37 | return CTR; 38 | }()); 39 | -------------------------------------------------------------------------------- /encrypt-examples/frontend-backend-encrypt-with-rsa/src/main/resources/static/crypto-js/mode-ecb.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Electronic Codebook block mode. 3 | */ 4 | CryptoJS.mode.ECB = (function () { 5 | var ECB = CryptoJS.lib.BlockCipherMode.extend(); 6 | 7 | ECB.Encryptor = ECB.extend({ 8 | processBlock: function (words, offset) { 9 | this._cipher.encryptBlock(words, offset); 10 | } 11 | }); 12 | 13 | ECB.Decryptor = ECB.extend({ 14 | processBlock: function (words, offset) { 15 | this._cipher.decryptBlock(words, offset); 16 | } 17 | }); 18 | 19 | return ECB; 20 | }()); 21 | -------------------------------------------------------------------------------- /encrypt-examples/frontend-backend-encrypt-with-rsa/src/main/resources/static/crypto-js/mode-ofb.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Output Feedback block mode. 3 | */ 4 | CryptoJS.mode.OFB = (function () { 5 | var OFB = CryptoJS.lib.BlockCipherMode.extend(); 6 | 7 | var Encryptor = OFB.Encryptor = OFB.extend({ 8 | processBlock: function (words, offset) { 9 | // Shortcuts 10 | var cipher = this._cipher 11 | var blockSize = cipher.blockSize; 12 | var iv = this._iv; 13 | var keystream = this._keystream; 14 | 15 | // Generate keystream 16 | if (iv) { 17 | keystream = this._keystream = iv.slice(0); 18 | 19 | // Remove IV for subsequent blocks 20 | this._iv = undefined; 21 | } 22 | cipher.encryptBlock(keystream, 0); 23 | 24 | // Encrypt 25 | for (var i = 0; i < blockSize; i++) { 26 | words[offset + i] ^= keystream[i]; 27 | } 28 | } 29 | }); 30 | 31 | OFB.Decryptor = Encryptor; 32 | 33 | return OFB; 34 | }()); 35 | -------------------------------------------------------------------------------- /encrypt-examples/frontend-backend-encrypt-with-rsa/src/main/resources/static/crypto-js/pad-ansix923.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ANSI X.923 padding strategy. 3 | */ 4 | CryptoJS.pad.AnsiX923 = { 5 | pad: function (data, blockSize) { 6 | // Shortcuts 7 | var dataSigBytes = data.sigBytes; 8 | var blockSizeBytes = blockSize * 4; 9 | 10 | // Count padding bytes 11 | var nPaddingBytes = blockSizeBytes - dataSigBytes % blockSizeBytes; 12 | 13 | // Compute last byte position 14 | var lastBytePos = dataSigBytes + nPaddingBytes - 1; 15 | 16 | // Pad 17 | data.clamp(); 18 | data.words[lastBytePos >>> 2] |= nPaddingBytes << (24 - (lastBytePos % 4) * 8); 19 | data.sigBytes += nPaddingBytes; 20 | }, 21 | 22 | unpad: function (data) { 23 | // Get number of padding bytes from last byte 24 | var nPaddingBytes = data.words[(data.sigBytes - 1) >>> 2] & 0xff; 25 | 26 | // Remove padding 27 | data.sigBytes -= nPaddingBytes; 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /encrypt-examples/frontend-backend-encrypt-with-rsa/src/main/resources/static/crypto-js/pad-iso10126.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ISO 10126 padding strategy. 3 | */ 4 | CryptoJS.pad.Iso10126 = { 5 | pad: function (data, blockSize) { 6 | // Shortcut 7 | var blockSizeBytes = blockSize * 4; 8 | 9 | // Count padding bytes 10 | var nPaddingBytes = blockSizeBytes - data.sigBytes % blockSizeBytes; 11 | 12 | // Pad 13 | data.concat(CryptoJS.lib.WordArray.random(nPaddingBytes - 1)). 14 | concat(CryptoJS.lib.WordArray.create([nPaddingBytes << 24], 1)); 15 | }, 16 | 17 | unpad: function (data) { 18 | // Get number of padding bytes from last byte 19 | var nPaddingBytes = data.words[(data.sigBytes - 1) >>> 2] & 0xff; 20 | 21 | // Remove padding 22 | data.sigBytes -= nPaddingBytes; 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /encrypt-examples/frontend-backend-encrypt-with-rsa/src/main/resources/static/crypto-js/pad-iso97971.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ISO/IEC 9797-1 Padding Method 2. 3 | */ 4 | CryptoJS.pad.Iso97971 = { 5 | pad: function (data, blockSize) { 6 | // Add 0x80 byte 7 | data.concat(CryptoJS.lib.WordArray.create([0x80000000], 1)); 8 | 9 | // Zero pad the rest 10 | CryptoJS.pad.ZeroPadding.pad(data, blockSize); 11 | }, 12 | 13 | unpad: function (data) { 14 | // Remove zero padding 15 | CryptoJS.pad.ZeroPadding.unpad(data); 16 | 17 | // Remove one more byte -- the 0x80 byte 18 | data.sigBytes--; 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /encrypt-examples/frontend-backend-encrypt-with-rsa/src/main/resources/static/crypto-js/pad-nopadding.js: -------------------------------------------------------------------------------- 1 | /** 2 | * A noop padding strategy. 3 | */ 4 | CryptoJS.pad.NoPadding = { 5 | pad: function () { 6 | }, 7 | 8 | unpad: function () { 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /encrypt-examples/frontend-backend-encrypt-with-rsa/src/main/resources/static/crypto-js/pad-zeropadding.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Zero padding strategy. 3 | */ 4 | CryptoJS.pad.ZeroPadding = { 5 | pad: function (data, blockSize) { 6 | // Shortcut 7 | var blockSizeBytes = blockSize * 4; 8 | 9 | // Pad 10 | data.clamp(); 11 | data.sigBytes += blockSizeBytes - ((data.sigBytes % blockSizeBytes) || blockSizeBytes); 12 | }, 13 | 14 | unpad: function (data) { 15 | // Shortcut 16 | var dataWords = data.words; 17 | 18 | // Unpad 19 | var i = data.sigBytes - 1; 20 | while (!((dataWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff)) { 21 | i--; 22 | } 23 | data.sigBytes = i + 1; 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /encrypt-examples/frontend-backend-encrypt-with-rsa/src/main/resources/static/crypto-js/sha224.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | // Shortcuts 3 | var C = CryptoJS; 4 | var C_lib = C.lib; 5 | var WordArray = C_lib.WordArray; 6 | var C_algo = C.algo; 7 | var SHA256 = C_algo.SHA256; 8 | 9 | /** 10 | * SHA-224 hash algorithm. 11 | */ 12 | var SHA224 = C_algo.SHA224 = SHA256.extend({ 13 | _doReset: function () { 14 | this._hash = new WordArray.init([ 15 | 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 16 | 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4 17 | ]); 18 | }, 19 | 20 | _doFinalize: function () { 21 | var hash = SHA256._doFinalize.call(this); 22 | 23 | hash.sigBytes -= 4; 24 | 25 | return hash; 26 | } 27 | }); 28 | 29 | /** 30 | * Shortcut function to the hasher's object interface. 31 | * 32 | * @param {WordArray|string} message The message to hash. 33 | * 34 | * @return {WordArray} The hash. 35 | * 36 | * @static 37 | * 38 | * @example 39 | * 40 | * var hash = CryptoJS.SHA224('message'); 41 | * var hash = CryptoJS.SHA224(wordArray); 42 | */ 43 | C.SHA224 = SHA256._createHelper(SHA224); 44 | 45 | /** 46 | * Shortcut function to the HMAC's object interface. 47 | * 48 | * @param {WordArray|string} message The message to hash. 49 | * @param {WordArray|string} key The secret key. 50 | * 51 | * @return {WordArray} The HMAC. 52 | * 53 | * @static 54 | * 55 | * @example 56 | * 57 | * var hmac = CryptoJS.HmacSHA224(message, key); 58 | */ 59 | C.HmacSHA224 = SHA256._createHmacHelper(SHA224); 60 | }()); 61 | -------------------------------------------------------------------------------- /encrypt-examples/frontend-backend-encrypt-with-rsa/src/main/resources/static/crypto-js/sha384.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | // Shortcuts 3 | var C = CryptoJS; 4 | var C_x64 = C.x64; 5 | var X64Word = C_x64.Word; 6 | var X64WordArray = C_x64.WordArray; 7 | var C_algo = C.algo; 8 | var SHA512 = C_algo.SHA512; 9 | 10 | /** 11 | * SHA-384 hash algorithm. 12 | */ 13 | var SHA384 = C_algo.SHA384 = SHA512.extend({ 14 | _doReset: function () { 15 | this._hash = new X64WordArray.init([ 16 | new X64Word.init(0xcbbb9d5d, 0xc1059ed8), new X64Word.init(0x629a292a, 0x367cd507), 17 | new X64Word.init(0x9159015a, 0x3070dd17), new X64Word.init(0x152fecd8, 0xf70e5939), 18 | new X64Word.init(0x67332667, 0xffc00b31), new X64Word.init(0x8eb44a87, 0x68581511), 19 | new X64Word.init(0xdb0c2e0d, 0x64f98fa7), new X64Word.init(0x47b5481d, 0xbefa4fa4) 20 | ]); 21 | }, 22 | 23 | _doFinalize: function () { 24 | var hash = SHA512._doFinalize.call(this); 25 | 26 | hash.sigBytes -= 16; 27 | 28 | return hash; 29 | } 30 | }); 31 | 32 | /** 33 | * Shortcut function to the hasher's object interface. 34 | * 35 | * @param {WordArray|string} message The message to hash. 36 | * 37 | * @return {WordArray} The hash. 38 | * 39 | * @static 40 | * 41 | * @example 42 | * 43 | * var hash = CryptoJS.SHA384('message'); 44 | * var hash = CryptoJS.SHA384(wordArray); 45 | */ 46 | C.SHA384 = SHA512._createHelper(SHA384); 47 | 48 | /** 49 | * Shortcut function to the HMAC's object interface. 50 | * 51 | * @param {WordArray|string} message The message to hash. 52 | * @param {WordArray|string} key The secret key. 53 | * 54 | * @return {WordArray} The HMAC. 55 | * 56 | * @static 57 | * 58 | * @example 59 | * 60 | * var hmac = CryptoJS.HmacSHA384(message, key); 61 | */ 62 | C.HmacSHA384 = SHA512._createHmacHelper(SHA384); 63 | }()); 64 | -------------------------------------------------------------------------------- /encrypt-examples/frontend-backend-encrypt-with-rsa/src/main/resources/templates/error/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 404 5 | 6 | 7 | 8 | 9 |

404

10 | 11 | 12 | -------------------------------------------------------------------------------- /encrypt-examples/frontend-backend-encrypt-with-rsa/src/main/resources/templates/error/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 500 5 | 6 | 7 | 8 | 9 |

500

10 | 11 | 12 | -------------------------------------------------------------------------------- /encrypt-examples/frontend-backend-encrypt-with-rsa/src/test/java/top/ylonline/encrypt/AppTest.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.encrypt; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.assertTrue; 6 | 7 | /** 8 | * Unit test for simple App. 9 | */ 10 | public class AppTest { 11 | /** 12 | * Rigorous Test :-) 13 | */ 14 | @Test 15 | public void shouldAnswerWithTrue() { 16 | assertTrue(true); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /encrypt-examples/frontend-backend-encrypt-with-rsa/src/test/java/top/ylonline/encrypt/util/AesUtilsTest.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.encrypt.util; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | import top.ylonline.encrypt.common.Const; 6 | 7 | /** 8 | * @author YL 9 | */ 10 | public class AesUtilsTest { 11 | 12 | @Test 13 | public void backend() { 14 | String str = Const.STR; 15 | 16 | String key = AesUtils.randomKey(); 17 | System.out.println("key: " + key); 18 | String encrypt = AesUtils.encrypt(key, "UTF-8", str); 19 | System.out.println("encrypt: " + encrypt); 20 | String decrypt = AesUtils.decrypt(key, "UTF-8", encrypt); 21 | System.out.println("decrypt: " + decrypt); 22 | Assert.assertEquals(str, decrypt); 23 | } 24 | 25 | /** 26 | * 前端解密,后端解密 27 | */ 28 | @Test 29 | public void frontend() { 30 | String key = "NHXGgRvVrvLv4GaB"; 31 | String encrypt = "Eq8kNQVlgaz+JbpR3R/Z0Q=="; 32 | String decrypt = AesUtils.decrypt(key, "UTF-8", encrypt); 33 | System.out.println("decrypt: " + decrypt); 34 | Assert.assertEquals(Const.STR, decrypt); 35 | } 36 | } -------------------------------------------------------------------------------- /encrypt-examples/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | top.ylonline 6 | java-best-practice 7 | 1.0-SNAPSHOT 8 | 9 | 4.0.0 10 | 11 | top.ylonline.encrypt 12 | encrypt-examples 13 | Java 最佳实践 :: encrypt 14 | pom 15 | 16 | 17 | frontend-backend-encrypt-with-rsa 18 | 19 | 20 | 21 | UTF-8 22 | 1.8 23 | 1.8 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /feign-examples/openfeign/src/main/java/top/ylonline/feign/OpenFeignApp.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.feign; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.openfeign.EnableFeignClients; 6 | 7 | /** 8 | * @author YL 9 | */ 10 | @SpringBootApplication 11 | @EnableFeignClients 12 | public class OpenFeignApp { 13 | 14 | public static void main(String[] args) { 15 | SpringApplication.run(OpenFeignApp.class, args); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /feign-examples/openfeign/src/main/java/top/ylonline/feign/client/CspClient.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.feign.client; 2 | 3 | import org.springframework.cloud.openfeign.FeignClient; 4 | import org.springframework.web.bind.annotation.PostMapping; 5 | import org.springframework.web.bind.annotation.RequestBody; 6 | 7 | /** 8 | * @author YL 9 | */ 10 | @FeignClient( 11 | name = "ic", 12 | url = "http://127.0.0.1:8888/ic/services/ws" 13 | ) 14 | public interface CspClient { 15 | 16 | /** 17 | * 调用 ic 平台接口 18 | * 19 | * @param xml 入参 20 | * 21 | * @return 接口出参 22 | */ 23 | @PostMapping(headers = {"SOAPAction=\"\"", "Content-Type=text/xml; charset=gbk"}) 24 | String call(@RequestBody String xml); 25 | } 26 | -------------------------------------------------------------------------------- /feign-examples/openfeign/src/main/java/top/ylonline/feign/client/Github.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.feign.client; 2 | 3 | import feign.Param; 4 | import feign.RequestLine; 5 | 6 | import java.util.List; 7 | import java.util.Map; 8 | 9 | /** 10 | * @author YL 11 | */ 12 | public interface Github { 13 | /** 14 | * 获取 github 仓库的贡献者 15 | * 16 | * @param owner github 拥有者 17 | * @param repo github repository name 18 | * 19 | * @return 贡献者列表 20 | */ 21 | @RequestLine("GET /repos/{owner}/{repo}/contributors") 22 | List> contributors(@Param("owner") String owner, @Param("repo") String repo); 23 | } 24 | -------------------------------------------------------------------------------- /feign-examples/openfeign/src/main/java/top/ylonline/feign/client/GithubClient.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.feign.client; 2 | 3 | import org.springframework.cloud.openfeign.FeignClient; 4 | import org.springframework.web.bind.annotation.GetMapping; 5 | import org.springframework.web.bind.annotation.PathVariable; 6 | 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | /** 11 | * @author YL 12 | */ 13 | @FeignClient(name = "githut-api", url = "https://api.github.com") 14 | public interface GithubClient { 15 | /** 16 | * 获取 github 仓库的贡献者 17 | * 18 | * @param owner github 拥有者 19 | * @param repo github repository name 20 | * 21 | * @return 贡献者列表 22 | */ 23 | @GetMapping(value = "/repos/{owner}/{repo}/contributors") 24 | List> contributors(@PathVariable("owner") String owner, @PathVariable("repo") String repo); 25 | } 26 | -------------------------------------------------------------------------------- /feign-examples/openfeign/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: openfeign -------------------------------------------------------------------------------- /feign-examples/openfeign/src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | ${logger.pattern} 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /feign-examples/openfeign/src/test/java/top/ylonline/feign/client/CspClientTest.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.feign.client; 2 | 3 | import org.apache.commons.lang.StringEscapeUtils; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 8 | import org.springframework.cloud.openfeign.EnableFeignClients; 9 | import org.springframework.context.annotation.Configuration; 10 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 11 | 12 | /** 13 | * @author YL 14 | */ 15 | @RunWith(SpringJUnit4ClassRunner.class) 16 | @Configuration 17 | @EnableAutoConfiguration 18 | @EnableFeignClients(clients = CspClient.class) 19 | public class CspClientTest { 20 | 21 | @Autowired 22 | private CspClient cspClient; 23 | 24 | @Test 25 | public void contributors() { 26 | String xml = "10000MH123456AllServInfo7691115362069290201]]>"; 37 | 38 | String str = cspClient.call(xml); 39 | System.out.println(StringEscapeUtils.unescapeXml(str)); 40 | 41 | } 42 | } -------------------------------------------------------------------------------- /feign-examples/openfeign/src/test/java/top/ylonline/feign/client/GithubClientTest.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.feign.client; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 8 | import org.springframework.cloud.openfeign.EnableFeignClients; 9 | import org.springframework.context.annotation.Configuration; 10 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 11 | 12 | import java.util.List; 13 | import java.util.Map; 14 | 15 | /** 16 | * @author YL 17 | */ 18 | @RunWith(SpringJUnit4ClassRunner.class) 19 | @Configuration 20 | @EnableAutoConfiguration 21 | @EnableFeignClients(clients = GithubClient.class) 22 | public class GithubClientTest { 23 | 24 | @Autowired 25 | private GithubClient githubClient; 26 | 27 | @Test 28 | public void contributors() { 29 | List> contributors = githubClient.contributors("foreveryang321", "java-best-practice"); 30 | for (Map contributor : contributors) { 31 | System.out.println(JSON.toJSONString(contributor)); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /feign-examples/openfeign/src/test/java/top/ylonline/feign/client/GithubTest.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.feign.client; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import feign.Feign; 5 | import feign.gson.GsonDecoder; 6 | import org.junit.Test; 7 | 8 | import java.util.List; 9 | import java.util.Map; 10 | 11 | /** 12 | * @author YL 13 | */ 14 | public class GithubTest { 15 | 16 | @Test 17 | public void contributors() { 18 | Github github = Feign.builder() 19 | .decoder(new GsonDecoder()) 20 | .target(Github.class, "https://api.github.com"); 21 | 22 | List> contributors = github.contributors("foreveryang321", "java-best-practice"); 23 | for (Map contributor : contributors) { 24 | System.out.println(JSON.toJSONString(contributor)); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /feign-examples/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | top.ylonline 6 | java-best-practice 7 | 1.0-SNAPSHOT 8 | 9 | 4.0.0 10 | 11 | top.ylonline.feign 12 | feign-examples 13 | Java 最佳实践 :: feigh 14 | pom 15 | 16 | 17 | openfeign 18 | 19 | 20 | 21 | UTF-8 22 | 1.8 23 | 1.8 24 | 25 | 26 | -------------------------------------------------------------------------------- /flow-examples/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | java-best-practice 7 | top.ylonline 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | flow-examples 13 | Java 最佳实践 :: flow 14 | 15 | 16 | UTF-8 17 | 1.8 18 | 1.8 19 | 20 | 21 | -------------------------------------------------------------------------------- /flow-examples/src/main/java/top/ylonline/App.java: -------------------------------------------------------------------------------- 1 | package top.ylonline; 2 | 3 | /** 4 | * Hello world! 5 | * 6 | */ 7 | public class App 8 | { 9 | public static void main( String[] args ) 10 | { 11 | System.out.println( "Hello World!" ); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /gateway-examples/gateway-nacos/src/main/java/top/ylonline/nacos/spring/cloud/gateway/example/NacosGatewayApp.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.nacos.spring.cloud.gateway.example; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class NacosGatewayApp { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(NacosGatewayApp.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /gateway-examples/gateway-nacos/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8080 3 | management: 4 | endpoint: 5 | gateway: 6 | enabled: true 7 | endpoints: 8 | web: 9 | exposure: 10 | include: '*' -------------------------------------------------------------------------------- /gateway-examples/gateway-nacos/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: nacos-spring-cloud-gateway-example 4 | cloud: 5 | nacos: 6 | config: 7 | server-addr: 192.168.56.101:8848 8 | ext-config: 9 | - data-id: gateway.yaml 10 | refresh: true -------------------------------------------------------------------------------- /gateway-examples/gateway-nacos/src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | ${logger.pattern} 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /gateway-examples/gateway-simple/README.md: -------------------------------------------------------------------------------- 1 | # gateway-simple 2 | 3 | - 初始化配置 4 | ```yaml 5 | spring: 6 | application: 7 | name: spring-cloud-gateway-example 8 | cloud: 9 | gateway: 10 | routes: 11 | - id: demo 12 | uri: https://www.baidu.com 13 | predicates: 14 | - Path=/s 15 | ``` 16 | 启动后,浏览器访问 [http://localhost:8080/s](http://localhost:8080/s),请求会转发到 [https://www.baidu.com/s](https://www.baidu.com/s),说明路由成功了 17 | 18 | - 开启 gateway 端点 19 | > 如果不配置,默认只开启 `health`、`info` 端点,配置成 `*` 表示开启所有端点 20 | ```yaml 21 | management: 22 | endpoint: 23 | gateway: 24 | enabled: true 25 | endpoints: 26 | web: 27 | exposure: 28 | include: '*' 29 | ``` 30 | 31 | - 动态调整路由规则 32 | - 刷新路由规则 33 | ```sh 34 | curl -XPOST http://localhost:8080/actuator/gateway/refresh 35 | ``` 36 | 37 | - 新增路由 38 | ```sh 39 | curl -H 'Content-Type: application/json; charset=UTF-8' -XPOST http://localhost:8080/actuator/gateway/routes/taobao -d '{ 40 | "id": "taobao", 41 | "predicates": [ 42 | { 43 | "name": "Path", 44 | "args": 45 | { 46 | "_genkey_0": "/search" 47 | } 48 | }], 49 | "filters": [], 50 | "uri": "https://s.taobao.com/", 51 | "order": 0 52 | }' 53 | ``` 54 | > 要调用一下`刷新路由规则`接口才会生效 55 | 56 | > 注意:args 的 `_genkey_0` key 命名,filters 也是一样的命名方式,后缀数字按照参数配置顺序递增 57 | 58 | - 删除路由 59 | ```sh 60 | curl -XDELETE http://localhost:8080/actuator/gateway/routes/taobao 61 | ``` 62 | > 要调用一下`刷新路由规则`接口才会生效 63 | 64 | -------------------------------------------------------------------------------- /gateway-examples/gateway-simple/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | top.ylonline.gateway 6 | gateway-examples 7 | 1.0-SNAPSHOT 8 | 9 | 4.0.0 10 | 11 | gateway-simple 12 | Java 最佳实践 :: gateway(${project.artifactId}) 13 | 14 | 15 | UTF-8 16 | 1.8 17 | 1.8 18 | 19 | 2.0.6.RELEASE 20 | Finchley.SR2 21 | 22 | 23 | 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-dependencies 28 | ${spring-boot.version} 29 | pom 30 | import 31 | 32 | 33 | org.springframework.cloud 34 | spring-cloud-dependencies 35 | ${spring-cloud.version} 36 | pom 37 | import 38 | 39 | 40 | 41 | 42 | 43 | 44 | org.springframework.cloud 45 | spring-cloud-starter-gateway 46 | 47 | 48 | org.springframework.boot 49 | spring-boot-starter-actuator 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /gateway-examples/gateway-simple/src/main/java/top/ylonline/spring/cloud/gateway/example/GatewayApp.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.spring.cloud.gateway.example; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class GatewayApp { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(GatewayApp.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /gateway-examples/gateway-simple/src/main/resources/application-dev.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/foreveryang321/java-best-practice/64eaa1114acbfd168a46feb6d6ab5ea014a5c8ba/gateway-examples/gateway-simple/src/main/resources/application-dev.yml -------------------------------------------------------------------------------- /gateway-examples/gateway-simple/src/main/resources/application-local.yml: -------------------------------------------------------------------------------- 1 | debug: false 2 | server: 3 | port: 8080 4 | spring: 5 | application: 6 | name: spring-cloud-gateway-example 7 | cloud: 8 | gateway: 9 | routes: 10 | - id: baidu 11 | uri: https://www.baidu.com 12 | predicates: 13 | # 支持:After、Before、Between、Cookie、Header、Host、Method、Path、Query、RemoteAddr 14 | - Path=/s 15 | # - Between=2018-01-01T00:00:00+08:00[Asia/Shanghai], 2019-01-01T00:00:00+08:00[Asia/Shanghai] 16 | # - Host=**.yl-online.top 17 | # - Method=POST 18 | # - Header=X-Request-Id, \d+ 19 | # - Query=foo, ba. 20 | # - Query=wx 21 | # - Cookie=x-wx-auth, \d+ 22 | # - After=2018-01-01T00:00:00+08:00[Asia/Shanghai] 23 | # - Before=2019-01-01T00:00:00+08:00[Asia/Shanghai] 24 | # - RemoteAddr=127.0.0.1/24 25 | # filters: 26 | # - AddRequestHeader=X-Request-Foo, Bar 27 | # - AddRequestParameter=foo, bar 28 | # - AddResponseHeader=X-Response-Foo, Bar 29 | # - Hystrix=myCommandName 30 | # - RewritePath=/consuming-service-endpoint, /backing-service-endpoint 31 | # - PrefixPath=/my-path 32 | # - name: RequestRateLimiter 33 | # args: 34 | # redis-rate-limiter.replenishRate: 10 35 | # redis-rate-limiter.burstCapacity: 20 36 | # - RedirectTo=302, http://acme.org 37 | # - RemoveRequestHeader=X-Request-Foo 38 | # - RemoveResponseHeader=X-Response-Foo 39 | management: 40 | endpoint: 41 | gateway: 42 | enabled: true 43 | endpoints: 44 | web: 45 | exposure: 46 | include: '*' -------------------------------------------------------------------------------- /gateway-examples/gateway-simple/src/main/resources/application-pro.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/foreveryang321/java-best-practice/64eaa1114acbfd168a46feb6d6ab5ea014a5c8ba/gateway-examples/gateway-simple/src/main/resources/application-pro.yml -------------------------------------------------------------------------------- /gateway-examples/gateway-simple/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | profiles: 3 | active: local 4 | -------------------------------------------------------------------------------- /gateway-examples/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | top.ylonline 6 | java-best-practice 7 | 1.0-SNAPSHOT 8 | 9 | 4.0.0 10 | 11 | top.ylonline.gateway 12 | gateway-examples 13 | Java 最佳实践 :: gateway 14 | pom 15 | 16 | 17 | gateway-simple 18 | gateway-nacos 19 | 20 | 21 | 22 | UTF-8 23 | 1.8 24 | 1.8 25 | 26 | 2.0.6.RELEASE 27 | Finchley.SR2 28 | 29 | 30 | 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-dependencies 35 | ${spring-boot.version} 36 | pom 37 | import 38 | 39 | 40 | org.springframework.cloud 41 | spring-cloud-dependencies 42 | ${spring-cloud.version} 43 | pom 44 | import 45 | 46 | 47 | 48 | 49 | com.alibaba.nacos 50 | nacos-client 51 | 0.6.2 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /nacos-examples/nacos-spring-boot-example/README.md: -------------------------------------------------------------------------------- 1 | # nacos-spring-boot-example 2 | > 目前 Nacos 已经更新到 0.7.0 版本 3 | 4 | > 项目使用了 spring profile 多环境配置(dev、local、pro),所以需要在`nacos`控制台配置新建3个命名空间(假设新建的3个命名空间也分别是dev、local、pro)分别对应 spring profile 多环境 5 | 6 | - 配置 spring profile 7 | ```yaml 8 | spring: 9 | profiles: 10 | active: local 11 | ``` 12 | 13 | - 在 [Nacos](https://nacos.io/zh-cn/) 控制台 local 命名空间下新建配置 14 | ```properties 15 | # DATA ID:nacos-spring-boot-example.properties 16 | example.id=123 17 | example.name=nacos-spring-boot-example.properties 18 | 19 | # DATA ID:nacos-spring-boot-example-nacos.properties 20 | example.profile=nacos 21 | ``` 22 | 23 | - 请求 [http://localhost:8080/nacos/demo](http://localhost:8080/nacos/demo) 24 | ```bash 25 | $ curl http://localhost:8080/nacos/demo 26 | { 27 | "id": 123, 28 | "name": "nacos-spring-boot-example.properties", 29 | "profile": "读取不到" 30 | } 31 | ``` 32 | 33 | - 修改配置,验证是否可以实时更新 34 | - 修改 `example.id`、`example.name` 的值 35 | ```properties 36 | # DATA ID:nacos-spring-boot-example.properties 37 | example.id=123456 38 | example.name=nacos-spring-boot-example.properties.new 39 | ``` 40 | - 请求 [http://localhost:8080/nacos/demo](http://localhost:8080/nacos/demo) 41 | ```bash 42 | $ curl http://localhost:8080/nacos/demo 43 | { 44 | "id": 123456, 45 | "name": "nacos-spring-boot-example.properties.new", 46 | "profile": "读取不到" 47 | } 48 | ``` 49 | 50 | - 结论 51 | 1. `@NacosValue`配置 autoRefreshed = true 是可以实时更新配置的,而`Spring`的`@Value`不能实时更新 52 | 2. 不支持 spring profile 粒度的配置(当前测试的`nacos-spring-boot-starter`版本) -------------------------------------------------------------------------------- /nacos-examples/nacos-spring-boot-example/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | top.ylonline.nacos 6 | nacos-examples 7 | 1.0-SNAPSHOT 8 | 9 | 4.0.0 10 | 11 | nacos-spring-boot-example 12 | Java 最佳实践 :: nacos(${project.artifactId}) 13 | 14 | 15 | UTF-8 16 | 1.8 17 | 1.8 18 | 19 | 2.0.6.RELEASE 20 | 21 | 22 | 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-dependencies 27 | ${spring-boot.version} 28 | pom 29 | import 30 | 31 | 32 | 33 | com.alibaba.nacos 34 | nacos-client 35 | 0.6.2 36 | 37 | 38 | 39 | 40 | 41 | 42 | org.springframework.boot 43 | spring-boot-starter-web 44 | 45 | 46 | 47 | com.alibaba.boot 48 | nacos-config-spring-boot-starter 49 | 0.2.1 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /nacos-examples/nacos-spring-boot-example/src/main/java/top/ylonline/nacos/spring/boot/example/NacosBootApp.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.nacos.spring.boot.example; 2 | 3 | import com.alibaba.nacos.api.config.annotation.NacosConfigListener; 4 | import com.alibaba.nacos.api.config.annotation.NacosValue; 5 | import com.alibaba.nacos.spring.context.annotation.config.EnableNacosConfig; 6 | import com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource; 7 | import com.alibaba.nacos.spring.context.annotation.config.NacosPropertySources; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.springframework.beans.factory.annotation.Value; 10 | import org.springframework.boot.SpringApplication; 11 | import org.springframework.boot.autoconfigure.SpringBootApplication; 12 | import org.springframework.web.bind.annotation.GetMapping; 13 | import org.springframework.web.bind.annotation.RestController; 14 | 15 | @SpringBootApplication 16 | @EnableNacosConfig 17 | @NacosPropertySources({ 18 | @NacosPropertySource(dataId = NacosBootApp.DATAID) 19 | }) 20 | @RestController 21 | @Slf4j 22 | public class NacosBootApp { 23 | static final String DATAID = "nacos-spring-boot-example.properties"; 24 | 25 | public static void main(String[] args) { 26 | SpringApplication.run(NacosBootApp.class, args); 27 | } 28 | 29 | @NacosConfigListener( 30 | dataId = NacosBootApp.DATAID, 31 | timeout = 500 32 | ) 33 | public void onChangeListener(String newContent) throws Exception { 34 | log.info("------------------------------------------------------------------"); 35 | log.info("{}", newContent); 36 | log.info("------------------------------------------------------------------"); 37 | } 38 | 39 | @NacosValue(value = "${example.id}", autoRefreshed = true) 40 | private int id; 41 | @Value("${example.name}") 42 | private String name; 43 | @NacosValue(value = "${example.profile:读取不到}", autoRefreshed = true) 44 | private String profile; 45 | 46 | @GetMapping("/demo") 47 | public String demo() { 48 | return String.format("{\"id\": %s, \"name\": \"%s\", \"profile\": \"%s\"}", id, name, profile); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /nacos-examples/nacos-spring-boot-example/src/main/resources/application-dev.yml: -------------------------------------------------------------------------------- 1 | debug: false 2 | server: 3 | port: 8080 4 | servlet: 5 | context-path: /nacos 6 | spring: 7 | application: 8 | name: nacos-spring-boot-example 9 | nacos: 10 | config: 11 | server-addr: 192.168.56.101:8848 12 | namespace: e88cbbea-6f38-4c8d-92c7-168cbbd5e3a9 -------------------------------------------------------------------------------- /nacos-examples/nacos-spring-boot-example/src/main/resources/application-local.yml: -------------------------------------------------------------------------------- 1 | debug: false 2 | server: 3 | port: 8080 4 | servlet: 5 | context-path: /nacos 6 | spring: 7 | application: 8 | name: nacos-spring-boot-example 9 | nacos: 10 | config: 11 | server-addr: 192.168.56.101:8848 12 | namespace: 595669e1-765c-4005-9224-8e277f970da3 -------------------------------------------------------------------------------- /nacos-examples/nacos-spring-boot-example/src/main/resources/application-pro.yml: -------------------------------------------------------------------------------- 1 | debug: false 2 | server: 3 | port: 8080 4 | servlet: 5 | context-path: /nacos 6 | spring: 7 | application: 8 | name: nacos-spring-boot-example 9 | nacos: 10 | config: 11 | server-addr: 192.168.56.101:8848 12 | namespace: d33cc729-4947-4c06-8c66-883507e1e509 -------------------------------------------------------------------------------- /nacos-examples/nacos-spring-boot-example/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | profiles: 3 | active: local 4 | -------------------------------------------------------------------------------- /nacos-examples/nacos-spring-cloud-example/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | top.ylonline.nacos 6 | nacos-examples 7 | 1.0-SNAPSHOT 8 | 9 | 4.0.0 10 | 11 | nacos-spring-cloud-example 12 | Java 最佳实践 :: nacos(${project.artifactId}) 13 | 14 | 15 | UTF-8 16 | 1.8 17 | 1.8 18 | 19 | 2.0.6.RELEASE 20 | Finchley.SR2 21 | 22 | 23 | 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-dependencies 28 | ${spring-boot.version} 29 | pom 30 | import 31 | 32 | 33 | org.springframework.cloud 34 | spring-cloud-dependencies 35 | ${spring-cloud.version} 36 | pom 37 | import 38 | 39 | 40 | 41 | com.alibaba.nacos 42 | nacos-client 43 | 0.6.2 44 | 45 | 46 | 47 | 48 | 49 | 50 | org.springframework.boot 51 | spring-boot-starter-web 52 | 53 | 54 | 55 | 56 | org.springframework.cloud 57 | spring-cloud-starter-alibaba-nacos-config 58 | 0.2.1.RELEASE 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /nacos-examples/nacos-spring-cloud-example/src/main/java/top/ylonline/nacos/spring/cloud/example/NacosCloudApp.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.nacos.spring.cloud.example; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class NacosCloudApp { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(NacosCloudApp.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /nacos-examples/nacos-spring-cloud-example/src/main/java/top/ylonline/nacos/spring/cloud/example/controller/DemoController.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.nacos.spring.cloud.example.controller; 2 | 3 | import com.alibaba.nacos.api.config.annotation.NacosValue; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.cloud.context.config.annotation.RefreshScope; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.RestController; 9 | 10 | /** 11 | * @author YL 12 | */ 13 | @RestController 14 | @RefreshScope 15 | @Slf4j 16 | public class DemoController { 17 | @NacosValue(value = "${example.id}", autoRefreshed = true) 18 | private int id; 19 | @Value("${example.name}") 20 | private String name; 21 | @Value("${example.age}") 22 | private int age; 23 | @Value("${example.weight}") 24 | private String weight; 25 | @Value("${example.profile}") 26 | private String profile; 27 | 28 | @GetMapping("/demo") 29 | public String demo() { 30 | return String.format("{\"id\": %s, \"name\": \"%s\", \"age\": \"%s\", \"weight\": \"%s\", \"profile\": " + 31 | "\"%s\"}", id, name, age, weight, profile); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /nacos-examples/nacos-spring-cloud-example/src/main/resources/application-nacos.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8080 3 | servlet: 4 | context-path: /nacos -------------------------------------------------------------------------------- /nacos-examples/nacos-spring-cloud-example/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | profiles: 3 | active: nacos -------------------------------------------------------------------------------- /nacos-examples/nacos-spring-cloud-example/src/main/resources/bootstrap.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=nacos-spring-cloud-example 2 | spring.cloud.nacos.config.server-addr=192.168.56.101:8848 3 | 4 | spring.cloud.nacos.config.ext-config[0].data-id=ext-config-default.properties 5 | spring.cloud.nacos.config.ext-config[0].refresh=true 6 | 7 | spring.cloud.nacos.config.ext-config[1].data-id=ext-config.yaml 8 | spring.cloud.nacos.config.ext-config[1].group=REFRESH_GROUP 9 | spring.cloud.nacos.config.ext-config[1].refresh=true -------------------------------------------------------------------------------- /nacos-examples/nacos-spring-cloud-example/src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | ${logger.pattern} 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /nacos-examples/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | top.ylonline 6 | java-best-practice 7 | 1.0-SNAPSHOT 8 | 9 | 4.0.0 10 | 11 | top.ylonline.nacos 12 | nacos-examples 13 | Java 最佳实践 :: nacos 14 | pom 15 | 16 | 17 | nacos-spring-boot-example 18 | nacos-spring-cloud-example 19 | 20 | 21 | 22 | UTF-8 23 | 1.8 24 | 1.8 25 | 26 | 27 | -------------------------------------------------------------------------------- /sb-examples/events-and-listeners/README.md: -------------------------------------------------------------------------------- 1 | # spring 事件发布和监听 2 | > 使用事件发布和监听,最大的作用应该是为了***业务解耦***。类似的有:消息队列的发布订阅模式 3 | 4 | [spring-boot 官方文档](https://docs.spring.io/spring-boot/docs/2.0.8.RELEASE/reference/htmlsingle/#boot-features-application-events-and-listeners) 5 | 6 | 比如:用户注册成功后,发送注册成功邮件、短信通知用户。 7 | 8 | ## 同步方式 9 | 如果使用同步的方式发送注册成功事件,会导致线程堵塞,增加用户注册的等待时间。 10 | 11 | ## 异步方式 12 | 使用异步的方式发送邮件、短信通知,可以减少用户等待注册成功的时间。 13 | 14 | - @EnableAsync 15 | - 连接池配置(实现AsyncConfigurer,或者自定义Bean) 16 | - @Async、@EventListener 17 | -------------------------------------------------------------------------------- /sb-examples/events-and-listeners/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | top.ylonline.sb 6 | sb-examples 7 | 1.0-SNAPSHOT 8 | 9 | 4.0.0 10 | 11 | events-and-listeners 12 | Java 最佳实践 :: spring-boot(${project.artifactId}) 13 | 14 | 15 | UTF-8 16 | 1.8 17 | 1.8 18 | 2.0.6.RELEASE 19 | 20 | 21 | 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-dependencies 26 | ${spring-boot.version} 27 | pom 28 | import 29 | 30 | 31 | 32 | 33 | 34 | 35 | org.springframework.boot 36 | spring-boot-starter-web 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /sb-examples/events-and-listeners/src/main/java/top/ylonline/sb/el/EventsAndListenersApp.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.sb.el; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.boot.builder.SpringApplicationBuilder; 6 | import org.springframework.context.ApplicationEventPublisher; 7 | import org.springframework.scheduling.annotation.EnableAsync; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.RestController; 10 | import top.ylonline.sb.el.domain.User; 11 | import top.ylonline.sb.el.event.UserEvent; 12 | 13 | import javax.annotation.Resource; 14 | 15 | /** 16 | * Hello world! 17 | * 18 | * @author YL 19 | */ 20 | @SpringBootApplication 21 | @EnableAsync 22 | @RestController 23 | @Slf4j 24 | public class EventsAndListenersApp { 25 | /** 26 | * Common 27 | */ 28 | private static SpringApplicationBuilder configureSpringBuilder(SpringApplicationBuilder builder) { 29 | // builder.listeners(new UserEventListener()); 30 | return builder.sources(EventsAndListenersApp.class); 31 | } 32 | 33 | /** 34 | * for JAR deploy 35 | */ 36 | public static void main(String[] args) { 37 | configureSpringBuilder(new SpringApplicationBuilder()) 38 | .run(args); 39 | } 40 | 41 | @Resource 42 | private ApplicationEventPublisher publisher; 43 | 44 | @GetMapping("/publishObject") 45 | public String publishObject() { 46 | publisher.publishEvent(User.builder().id(123L).name("foreveryang123").age(11).build()); 47 | log.info("发布 object 对象成功"); 48 | return "publishObject 发布成功"; 49 | } 50 | 51 | @GetMapping("/publishEvent") 52 | public String publishEvent() { 53 | publisher.publishEvent(new UserEvent(this, User.builder().id(456L).name("foreveryang456").age(22).build())); 54 | log.info("发布 event 成功"); 55 | return "publishEvent 发布成功"; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /sb-examples/events-and-listeners/src/main/java/top/ylonline/sb/el/config/EventListenerConfig.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.sb.el.config; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.context.event.EventListener; 6 | import org.springframework.scheduling.annotation.Async; 7 | import top.ylonline.sb.el.domain.User; 8 | import top.ylonline.sb.el.event.UserEvent; 9 | 10 | import java.util.concurrent.TimeUnit; 11 | 12 | /** 13 | * @author YL 14 | */ 15 | @Configuration 16 | @Slf4j 17 | public class EventListenerConfig { 18 | 19 | // @Async("eventThreadPoolTaskExecutor") 20 | // @EventListener 21 | // public void handleEvent(Object event) { 22 | // log.info("监听所有事件 ---> event: {}", event); 23 | // try { 24 | // TimeUnit.SECONDS.sleep(5); 25 | // } catch (InterruptedException e) { 26 | // e.printStackTrace(); 27 | // } 28 | // log.info("监听所有事件 ---> event: {}", event); 29 | // } 30 | 31 | @Async("eventThreadPoolTaskExecutor") 32 | @EventListener 33 | public void handleUserEvent(UserEvent event) { 34 | log.info("开始:监听到 userEvent 事件 ---> event: {}, user event: {}, time: {}", event, event.getUser(), 35 | event.getTimestamp()); 36 | try { 37 | TimeUnit.SECONDS.sleep(5); 38 | } catch (InterruptedException e) { 39 | e.printStackTrace(); 40 | } 41 | log.info("结束:监听到 userEvent 事件 ---> event: {}, user event: {}, time: {}", event, event.getUser(), 42 | event.getTimestamp()); 43 | } 44 | 45 | @Async("eventThreadPoolTaskExecutor") 46 | @EventListener 47 | public void handleUser(User user) { 48 | log.info("开始:监听到 user 对象 ---> user: {}", user); 49 | try { 50 | TimeUnit.SECONDS.sleep(5); 51 | } catch (InterruptedException e) { 52 | e.printStackTrace(); 53 | } 54 | log.info("结束:监听到 user 对象 ---> user: {}", user); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /sb-examples/events-and-listeners/src/main/java/top/ylonline/sb/el/config/MyAsyncConfigurer.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.sb.el.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.scheduling.annotation.AsyncConfigurer; 6 | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; 7 | 8 | import java.util.concurrent.Executor; 9 | 10 | /** 11 | * 异步执行线程池配置 12 | * 13 | * @author YL 14 | */ 15 | @Configuration 16 | public class MyAsyncConfigurer implements AsyncConfigurer { 17 | 18 | @Bean("eventThreadPoolTaskExecutor") 19 | public Executor eventThreadPoolTaskExecutor() { 20 | return executor(5, 10, 20, 30); 21 | } 22 | 23 | @Override 24 | public Executor getAsyncExecutor() { 25 | return executor(10, 128, 256, 60); 26 | } 27 | 28 | private Executor executor(int coreSize, int maxSize, int queueSize, int keepAlive) { 29 | ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); 30 | executor.setCorePoolSize(coreSize); 31 | executor.setMaxPoolSize(maxSize); 32 | executor.setQueueCapacity(queueSize); 33 | executor.setKeepAliveSeconds(keepAlive); 34 | executor.setThreadNamePrefix("async-executor-"); 35 | executor.initialize(); 36 | return executor; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /sb-examples/events-and-listeners/src/main/java/top/ylonline/sb/el/domain/User.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.sb.el.domain; 2 | 3 | import lombok.Builder; 4 | import lombok.Data; 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | * @author YL 10 | */ 11 | @Data 12 | @Builder 13 | // @NoArgsConstructor 14 | public class User implements Serializable { 15 | private static final long serialVersionUID = 1L; 16 | 17 | private Long id; 18 | 19 | private String name; 20 | 21 | private int age; 22 | } 23 | -------------------------------------------------------------------------------- /sb-examples/events-and-listeners/src/main/java/top/ylonline/sb/el/event/UserEvent.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.sb.el.event; 2 | 3 | import org.springframework.context.ApplicationEvent; 4 | import top.ylonline.sb.el.domain.User; 5 | 6 | /** 7 | * @author YL 8 | */ 9 | public class UserEvent extends ApplicationEvent { 10 | private static final long serialVersionUID = 1L; 11 | 12 | private User user; 13 | 14 | public UserEvent(Object source, User user) { 15 | super(source); 16 | this.user = user; 17 | } 18 | 19 | public User getUser() { 20 | return user; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /sb-examples/events-and-listeners/src/main/java/top/ylonline/sb/el/listener/UserEventListener.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.sb.el.listener;// package top.ylonline.springboot.event.listener; 2 | // 3 | // import lombok.extern.slf4j.Slf4j; 4 | // import org.springframework.context.ApplicationListener; 5 | // import org.springframework.scheduling.annotation.Async; 6 | // import org.springframework.stereotype.Component; 7 | // import top.ylonline.springboot.event.event.UserEvent; 8 | // 9 | // import java.util.concurrent.TimeUnit; 10 | // 11 | // /** 12 | // * @author YL 13 | // */ 14 | // @Component 15 | // @Slf4j 16 | // public class UserEventListener implements ApplicationListener { 17 | // 18 | // @Async("eventThreadPoolTaskExecutor") 19 | // @Override 20 | // public void onApplicationEvent(UserEvent event) { 21 | // log.info("开始:监听到 userEvent ---> user event: {}", event); 22 | // try { 23 | // TimeUnit.SECONDS.sleep(5); 24 | // } catch (InterruptedException e) { 25 | // e.printStackTrace(); 26 | // } 27 | // log.info("结束:监听到 userEvent ---> user event: {}", event); 28 | // } 29 | // } 30 | -------------------------------------------------------------------------------- /sb-examples/events-and-listeners/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8085 3 | servlet: 4 | path: / -------------------------------------------------------------------------------- /sb-examples/events-and-listeners/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | ${logger.pattern} 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /sb-examples/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | top.ylonline 6 | java-best-practice 7 | 1.0-SNAPSHOT 8 | 9 | 4.0.0 10 | 11 | top.ylonline.sb 12 | sb-examples 13 | Java 最佳实践 :: spring-boot 14 | pom 15 | 16 | 17 | events-and-listeners 18 | redis-v2.0 19 | redis-v1 20 | webflux 21 | 22 | 23 | 24 | UTF-8 25 | 1.8 26 | 1.8 27 | 28 | 29 | -------------------------------------------------------------------------------- /sb-examples/redis-v1/README.md: -------------------------------------------------------------------------------- 1 | # 自定义 Expired 注解 2 | 3 | - 自定义 Expired 注解,实现 redis 缓存的过期时间配置 4 | - 支持 Spring Expression Language (SpEL) ,实现动态配置过期时间。注意:使用 SpEL 配置过期时间时,配合`@Cacheput`、`CacheEvict`等使用时会有问题 5 | 6 | ## 环境 7 | - spring-boot 1.x 8 | - jedis 9 | - redis server 10 | 11 | 12 | ## 使用方式 13 | 14 | ```java 15 | import org.springframework.cache.annotation.Cacheable; 16 | import org.springframework.stereotype.Service; 17 | 18 | /** 19 | * @author YL 20 | */ 21 | @Service 22 | public class UserService { 23 | /** 24 | * 指定具体过期时间 25 | */ 26 | @Cacheable( 27 | value = "redis.v1.test", 28 | unless = "#result == null") 29 | @Expired(300) 30 | public User getUser(Long id, String firstName, String lastName) { 31 | return new User(id, firstName, lastName); 32 | } 33 | 34 | /** 35 | * SpEL 动态配置过期时间 36 | */ 37 | @Cacheable( 38 | value = "redis.v1.test.ttl", 39 | unless = "#result == null") 40 | @Expired(spEl = "#ttl") 41 | public User getUser(Long id, String firstName, String lastName, long ttl) { 42 | return new User(id, firstName, lastName); 43 | } 44 | } 45 | ``` -------------------------------------------------------------------------------- /sb-examples/redis-v1/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | top.ylonline.sb 6 | sb-examples 7 | 1.0-SNAPSHOT 8 | 9 | 4.0.0 10 | 11 | redis-v1 12 | Java 最佳实践 :: spring-boot(${project.artifactId}) 13 | 14 | 15 | UTF-8 16 | 1.8 17 | 1.8 18 | 19 | 1.5.19.RELEASE 20 | 21 | 22 | 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-dependencies 27 | ${spring-boot.version} 28 | pom 29 | import 30 | 31 | 32 | 33 | 34 | 35 | 36 | top.ylonline 37 | common 38 | ${project.version} 39 | 40 | 41 | org.springframework.boot 42 | spring-boot-starter-data-redis 43 | 44 | 45 | com.alibaba 46 | fastjson 47 | 1.2.54 48 | 49 | 50 | 51 | org.springframework.boot 52 | spring-boot-starter-test 53 | test 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /sb-examples/redis-v1/src/test/java/top/ylonline/sb/redis/v1/test/RedisV1App.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.sb.redis.v1.test; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | /** 7 | * Hello world! 8 | * 9 | * @author YL 10 | */ 11 | @SpringBootApplication 12 | public class RedisV1App { 13 | public static void main(String[] args) { 14 | SpringApplication.run(RedisV1App.class, args); 15 | synchronized (RedisV1App.class) { 16 | while (true) { 17 | try { 18 | RedisV1App.class.wait(); 19 | } catch (Exception e) { 20 | // ignore 21 | break; 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /sb-examples/redis-v1/src/test/java/top/ylonline/sb/redis/v1/test/RedisV1AppTest.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.sb.redis.v1.test; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.springframework.boot.test.context.SpringBootTest; 7 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 8 | import top.ylonline.sb.redis.v1.test.domain.User; 9 | import top.ylonline.sb.redis.v1.test.service.UserService; 10 | 11 | import javax.annotation.Resource; 12 | 13 | /** 14 | * Unit test for simple App. 15 | */ 16 | @RunWith(SpringJUnit4ClassRunner.class) 17 | @SpringBootTest(classes = RedisV1App.class) 18 | public class RedisV1AppTest { 19 | @Resource 20 | private UserService userService; 21 | 22 | @Test 23 | public void none() { 24 | User user = userService.none(1L, "cache", "normal"); 25 | System.out.println(user.toString()); 26 | Assert.assertEquals(1, user.getId().longValue()); 27 | } 28 | 29 | @Test 30 | public void normal() { 31 | User user = userService.getUser(1L, "cache", "normal"); 32 | System.out.println(user.toString()); 33 | Assert.assertEquals(1, user.getId().longValue()); 34 | } 35 | 36 | /** 37 | * 动态配置过期时间 38 | */ 39 | @Test 40 | public void dynamicTTL() { 41 | User user = userService.getUser(2L, "cache", "dynamicTTL", 900L); 42 | System.out.println(user.toString()); 43 | Assert.assertEquals(2, user.getId().longValue()); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /sb-examples/redis-v1/src/test/java/top/ylonline/sb/redis/v1/test/domain/User.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.sb.redis.v1.test.domain; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.io.Serializable; 8 | 9 | /** 10 | * @author YL 11 | */ 12 | @Data 13 | @NoArgsConstructor 14 | @AllArgsConstructor 15 | public class User implements Serializable { 16 | private static final long serialVersionUID = 3776888683392400078L; 17 | 18 | private Long id; 19 | private String firstName; 20 | private String lastName; 21 | } 22 | -------------------------------------------------------------------------------- /sb-examples/redis-v1/src/test/java/top/ylonline/sb/redis/v1/test/service/UserService.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.sb.redis.v1.test.service; 2 | 3 | import org.springframework.cache.annotation.Cacheable; 4 | import org.springframework.stereotype.Service; 5 | import top.ylonline.common.cache.annotation.Expired; 6 | import top.ylonline.sb.redis.v1.test.domain.User; 7 | 8 | /** 9 | * @author YL 10 | */ 11 | @Service 12 | public class UserService { 13 | /** 14 | * 使用默认 15 | */ 16 | @Cacheable( 17 | value = "redis.v1.none", 18 | unless = "#result == null") 19 | public User none(Long id, String firstName, String lastName) { 20 | return new User(id, firstName, lastName); 21 | } 22 | 23 | /** 24 | * 指定具体过期时间 25 | */ 26 | @Cacheable( 27 | value = "redis.v1.test", 28 | unless = "#result == null") 29 | @Expired(300) 30 | public User getUser(Long id, String firstName, String lastName) { 31 | return new User(id, firstName, lastName); 32 | } 33 | 34 | /** 35 | * SpEL 动态配置过期时间 36 | */ 37 | @Cacheable( 38 | value = "redis.v1.test.ttl", 39 | unless = "#result == null") 40 | @Expired(el = "#ttl") 41 | public User getUser(Long id, String firstName, String lastName, long ttl) { 42 | return new User(id, firstName, lastName); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /sb-examples/redis-v1/src/test/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | # Auto Configure 2 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 3 | top.ylonline.sb.redis.v1.TRedisAutoConfiguration 4 | -------------------------------------------------------------------------------- /sb-examples/redis-v1/src/test/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | redis: 3 | host: localhsot 4 | port: 6379 5 | timeout: 1000 6 | -------------------------------------------------------------------------------- /sb-examples/redis-v1/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | ${logger.pattern} 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /sb-examples/redis-v2.0/README.md: -------------------------------------------------------------------------------- 1 | # 自定义 Expired 注解 2 | 3 | - 自定义 Expired 注解,实现 redis 缓存的过期时间配置 4 | - 支持 Spring Expression Language (SpEL) ,实现动态配置过期时间。注意:使用 SpEL 配置过期时间时,配合`@Cacheput`、`CacheEvict`等使用时会有问题 5 | 6 | 7 | 8 | ## 环境 9 | - spring-boot 2.0.x 10 | - lettuce 11 | - redis server 12 | 13 | 14 | ## 使用方式 15 | 16 | ```java 17 | import org.springframework.cache.annotation.Cacheable; 18 | import org.springframework.stereotype.Service; 19 | 20 | /** 21 | * @author YL 22 | */ 23 | @Service 24 | public class UserService { 25 | /** 26 | * 指定具体过期时间 27 | */ 28 | @Cacheable( 29 | value = "redis.v2.test", 30 | unless = "#result == null") 31 | @Expired(300) 32 | public User getUser(Long id, String firstName, String lastName) { 33 | return new User(id, firstName, lastName); 34 | } 35 | 36 | /** 37 | * SpEL 动态配置过期时间 38 | */ 39 | @Cacheable( 40 | value = "redis.v2.test.ttl", 41 | unless = "#result == null") 42 | @Expired(spEl = "#ttl") 43 | public User getUser(Long id, String firstName, String lastName, long ttl) { 44 | return new User(id, firstName, lastName); 45 | } 46 | } 47 | ``` -------------------------------------------------------------------------------- /sb-examples/redis-v2.0/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | top.ylonline.sb 6 | sb-examples 7 | 1.0-SNAPSHOT 8 | 9 | 4.0.0 10 | 11 | redis-v2.0 12 | Java 最佳实践 :: spring-boot(${project.artifactId}) 13 | 14 | 15 | UTF-8 16 | 1.8 17 | 1.8 18 | 19 | 2.0.6.RELEASE 20 | 21 | 22 | 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-dependencies 27 | ${spring-boot.version} 28 | pom 29 | import 30 | 31 | 32 | 33 | 34 | 35 | 36 | top.ylonline 37 | common 38 | ${project.version} 39 | 40 | 41 | org.springframework.boot 42 | spring-boot-starter-data-redis 43 | 44 | 45 | com.alibaba 46 | fastjson 47 | 1.2.54 48 | 49 | 50 | 51 | org.springframework.boot 52 | spring-boot-starter-test 53 | test 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /sb-examples/redis-v2.0/src/test/java/top/ylonline/sb/redis/v2/test/RedisV2App.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.sb.redis.v2.test; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | /** 7 | * @author YL 8 | */ 9 | @SpringBootApplication 10 | public class RedisV2App { 11 | public static void main(String[] args) { 12 | SpringApplication.run(RedisV2App.class, args); 13 | synchronized (RedisV2App.class) { 14 | while (true) { 15 | try { 16 | RedisV2App.class.wait(); 17 | } catch (Exception e) { 18 | // ignore 19 | break; 20 | } 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /sb-examples/redis-v2.0/src/test/java/top/ylonline/sb/redis/v2/test/RedisV2AppTest.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.sb.redis.v2.test; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.springframework.boot.test.context.SpringBootTest; 7 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 8 | import top.ylonline.sb.redis.v2.test.domain.User; 9 | import top.ylonline.sb.redis.v2.test.service.UserService; 10 | 11 | import javax.annotation.Resource; 12 | 13 | /** 14 | * Unit test for simple App. 15 | */ 16 | @RunWith(SpringJUnit4ClassRunner.class) 17 | @SpringBootTest(classes = RedisV2App.class) 18 | public class RedisV2AppTest { 19 | 20 | @Resource 21 | private UserService userService; 22 | 23 | @Test 24 | public void none() { 25 | User user = userService.none(1L, "cache", "normal"); 26 | System.out.println(user.toString()); 27 | Assert.assertEquals(1, user.getId().longValue()); 28 | } 29 | 30 | @Test 31 | public void normal() { 32 | User user = userService.getUser(1L, "cache", "normal"); 33 | System.out.println(user.toString()); 34 | Assert.assertEquals(1, user.getId().longValue()); 35 | } 36 | 37 | /** 38 | * 动态配置过期时间 39 | */ 40 | @Test 41 | public void dynamicTTL() { 42 | User user = userService.getUser(2L, "cache", "dynamicTTL", 900L); 43 | System.out.println(user.toString()); 44 | Assert.assertEquals(2, user.getId().longValue()); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /sb-examples/redis-v2.0/src/test/java/top/ylonline/sb/redis/v2/test/domain/User.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.sb.redis.v2.test.domain; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.io.Serializable; 8 | 9 | /** 10 | * @author YL 11 | */ 12 | @Data 13 | @NoArgsConstructor 14 | @AllArgsConstructor 15 | public class User implements Serializable { 16 | private static final long serialVersionUID = 858347007112924676L; 17 | 18 | private Long id; 19 | private String firstName; 20 | private String lastName; 21 | } 22 | -------------------------------------------------------------------------------- /sb-examples/redis-v2.0/src/test/java/top/ylonline/sb/redis/v2/test/service/UserService.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.sb.redis.v2.test.service; 2 | 3 | import org.springframework.cache.annotation.Cacheable; 4 | import org.springframework.stereotype.Service; 5 | import top.ylonline.common.cache.annotation.Expired; 6 | import top.ylonline.sb.redis.v2.test.domain.User; 7 | 8 | /** 9 | * @author YL 10 | */ 11 | @Service 12 | public class UserService { 13 | /** 14 | * 使用默认 15 | */ 16 | @Cacheable( 17 | value = "redis.v2.none", 18 | unless = "#result == null") 19 | public User none(Long id, String firstName, String lastName) { 20 | return new User(id, firstName, lastName); 21 | } 22 | 23 | /** 24 | * 指定具体过期时间 25 | */ 26 | @Cacheable( 27 | value = "redis.v2.test", 28 | unless = "#result == null") 29 | @Expired(300) 30 | public User getUser(Long id, String firstName, String lastName) { 31 | return new User(id, firstName, lastName); 32 | } 33 | 34 | /** 35 | * SpEL 动态配置过期时间 36 | */ 37 | @Cacheable( 38 | value = "redis.v2.test.ttl", 39 | unless = "#result == null") 40 | @Expired(el = "#ttl") 41 | public User getUser(Long id, String firstName, String lastName, long ttl) { 42 | return new User(id, firstName, lastName); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /sb-examples/redis-v2.0/src/test/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | # Auto Configure 2 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 3 | top.ylonline.sb.redis.v2.TRedisAutoConfiguration 4 | -------------------------------------------------------------------------------- /sb-examples/redis-v2.0/src/test/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | redis: 3 | host: localhsot 4 | port: 6379 5 | timeout: 1s 6 | -------------------------------------------------------------------------------- /sb-examples/redis-v2.0/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | ${logger.pattern} 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /sb-examples/webflux/README.md: -------------------------------------------------------------------------------- 1 | # spring-webflux-example 2 | 3 | spring-webflux 响应式编程。本项目提供一个堵塞的例子([http://localhost:8080/user/block](http://localhost:8080/user/block) 4 | )、一个响应式的([http://localhost:8080/user/rx](http://localhost:8080/user/rx))例子 5 | 6 | > 由于这里使用的是`spring-data-jpa`,而`Reactive`对`Spring 7 | Data`的支持还不够完整,只支持了`MongoDB`、`Redis`、`Cassandra`和`Couchbase`,还不支持`JPA`、`JDBC`、`LDAP`、`Elasticsearch`、`Neo4j`、`Solr`。 8 | 9 | ## 堵塞 10 | - 请求 11 | 12 | 使用浏览器或者postman请求:[http://localhost:8080/user/block](http://localhost:8080/user/block) 13 | 14 | 抓包可以看到以下响应头部(Response Headers)内容 15 | ```text 16 | Content-Length: 253 17 | Content-Type: application/json;charset=UTF-8;q=0.8 18 | ``` 19 | 20 | - 响应内容 21 | ```json 22 | [ 23 | {"id":1,"name":"test_1"}, 24 | {"id":2,"name":"test_2"}, 25 | {"id":3,"name":"test_3"}, 26 | {"id":4,"name":"test_4"}, 27 | {"id":5,"name":"test_5"}, 28 | {"id":6,"name":"test_6"}, 29 | {"id":7,"name":"test_7"}, 30 | {"id":8,"name":"test_8"}, 31 | {"id":9,"name":"test_9"}, 32 | {"id":10,"name":"test_10"} 33 | ] 34 | ``` 35 | 36 | ## 响应式 37 | ```java 38 | @GetMapping(value = "/rx", produces = "application/stream+json") 39 | @ResponseBody 40 | public Flux rx() { 41 | return this.userService.findAll(); 42 | } 43 | ``` 44 | > 让用户在第一时间看到数据而不是等待数据采集完毕。application/stream+json 可以让调用方识别出,这些数据是分批响应式传递,而不用等待传输完才开始处理 45 | 46 | 47 | - 请求 48 | 49 | 使用浏览器或者postman请求:[http://localhost:8080/user/rx](http://localhost:8080/user/rx) 50 | 51 | 抓包可以看到以下响应头部(Response Headers)内容 52 | ```text 53 | Content-Type: application/stream+json;q=0.8;charset=UTF-8 54 | transfer-encoding: chunked 55 | ``` 56 | 57 | - 响应内容 58 | ```json 59 | {"id":1,"name":"test_1"} 60 | {"id":2,"name":"test_2"} 61 | {"id":3,"name":"test_3"} 62 | {"id":4,"name":"test_4"} 63 | {"id":5,"name":"test_5"} 64 | {"id":6,"name":"test_6"} 65 | {"id":7,"name":"test_7"} 66 | {"id":8,"name":"test_8"} 67 | {"id":9,"name":"test_9"} 68 | {"id":10,"name":"test_10"} 69 | ``` 70 | > 可以发现,响应式返回的不是标准的json格式数据,而是单行返回每个实体 71 | -------------------------------------------------------------------------------- /sb-examples/webflux/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | top.ylonline.sb 6 | sb-examples 7 | 1.0-SNAPSHOT 8 | 9 | 4.0.0 10 | 11 | webflux 12 | Java 最佳实践 :: spring-boot(${project.artifactId}) 13 | 14 | 15 | UTF-8 16 | 1.8 17 | 1.8 18 | 19 | 2.0.6.RELEASE 20 | 21 | 22 | 23 | 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-dependencies 28 | ${spring-boot.version} 29 | pom 30 | import 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | org.springframework.boot 45 | spring-boot-starter-webflux 46 | 47 | 48 | 49 | org.springframework.boot 50 | spring-boot-starter-data-jpa 51 | 52 | 53 | 54 | com.h2database 55 | h2 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /sb-examples/webflux/src/main/java/top/ylonline/sb/webflux/WebFluxApp.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.sb.webflux; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.web.bind.annotation.RestController; 6 | 7 | @SpringBootApplication 8 | @RestController 9 | public class WebFluxApp { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(WebFluxApp.class, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /sb-examples/webflux/src/main/java/top/ylonline/sb/webflux/config/JpaReactiveConfig.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.sb.webflux.config; 2 | 3 | import org.springframework.beans.factory.annotation.Qualifier; 4 | import org.springframework.beans.factory.annotation.Value; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.transaction.PlatformTransactionManager; 8 | import org.springframework.transaction.support.TransactionTemplate; 9 | import reactor.core.scheduler.Scheduler; 10 | import reactor.core.scheduler.Schedulers; 11 | 12 | import java.util.concurrent.Executors; 13 | 14 | /** 15 | * @author YL 16 | */ 17 | @Configuration 18 | public class JpaReactiveConfig { 19 | @Value("${spring.datasource.maximum-pool-size:99}") 20 | private int connectionPoolSize; 21 | 22 | @Bean 23 | @Qualifier("jdbcScheduler") 24 | public Scheduler jdbcScheduler() { 25 | return Schedulers.fromExecutor(Executors.newFixedThreadPool(connectionPoolSize)); 26 | } 27 | 28 | // @Bean 29 | // public TransactionTemplate transactionTemplate(PlatformTransactionManager transactionManager) { 30 | // return new TransactionTemplate(transactionManager); 31 | // } 32 | } 33 | -------------------------------------------------------------------------------- /sb-examples/webflux/src/main/java/top/ylonline/sb/webflux/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.sb.webflux.controller; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import org.springframework.web.bind.annotation.ResponseBody; 8 | import org.springframework.web.bind.annotation.RestController; 9 | import reactor.core.publisher.Flux; 10 | import reactor.core.publisher.Mono; 11 | import top.ylonline.sb.webflux.entity.User; 12 | import top.ylonline.sb.webflux.repository.UserRepository; 13 | import top.ylonline.sb.webflux.service.UserService; 14 | 15 | import java.util.List; 16 | 17 | /** 18 | * @author YL 19 | */ 20 | @RestController 21 | @RequestMapping("/user") 22 | @Slf4j 23 | public class UserController { 24 | private final UserRepository userRepository; 25 | private final UserService userService; 26 | 27 | @Autowired 28 | public UserController(UserRepository userRepository, UserService userService) { 29 | this.userRepository = userRepository; 30 | this.userService = userService; 31 | } 32 | 33 | @GetMapping(value = "/block") 34 | @ResponseBody 35 | public List blocking() { 36 | log.info("block"); 37 | return userRepository.findAll(); 38 | } 39 | 40 | @GetMapping(value = "/rx", produces = "application/stream+json") 41 | @ResponseBody 42 | public Flux rx() { 43 | log.info("rx"); 44 | return this.userService.findAll(); 45 | } 46 | 47 | @GetMapping(value = "/rx2") 48 | @ResponseBody 49 | public Mono> rx2() { 50 | log.info("rx2"); 51 | return this.userService.findAll2(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /sb-examples/webflux/src/main/java/top/ylonline/sb/webflux/entity/User.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.sb.webflux.entity; 2 | 3 | import lombok.Data; 4 | 5 | import javax.persistence.Entity; 6 | import javax.persistence.GeneratedValue; 7 | import javax.persistence.GenerationType; 8 | import javax.persistence.Id; 9 | import javax.persistence.Table; 10 | 11 | /** 12 | * @author YL 13 | */ 14 | @Entity 15 | @Table(name = "t_user") 16 | @Data 17 | public class User { 18 | @Id 19 | @GeneratedValue(strategy = GenerationType.IDENTITY) 20 | private Long id; 21 | 22 | private String name; 23 | } 24 | -------------------------------------------------------------------------------- /sb-examples/webflux/src/main/java/top/ylonline/sb/webflux/repository/UserRepository.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.sb.webflux.repository; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | import top.ylonline.sb.webflux.entity.User; 5 | 6 | /** 7 | * @author YL 8 | */ 9 | public interface UserRepository extends JpaRepository { 10 | } 11 | -------------------------------------------------------------------------------- /sb-examples/webflux/src/main/java/top/ylonline/sb/webflux/service/UserService.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.sb.webflux.service; 2 | 3 | import reactor.core.publisher.Flux; 4 | import reactor.core.publisher.Mono; 5 | import top.ylonline.sb.webflux.entity.User; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * @author YL 11 | */ 12 | public interface UserService { 13 | Flux findAll(); 14 | 15 | Mono> findAll2(); 16 | } 17 | -------------------------------------------------------------------------------- /sb-examples/webflux/src/main/java/top/ylonline/sb/webflux/service/UserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.sb.webflux.service; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.beans.factory.annotation.Qualifier; 6 | import org.springframework.stereotype.Service; 7 | import reactor.core.publisher.Flux; 8 | import reactor.core.publisher.Mono; 9 | import reactor.core.scheduler.Scheduler; 10 | import top.ylonline.sb.webflux.entity.User; 11 | import top.ylonline.sb.webflux.repository.UserRepository; 12 | 13 | import java.util.List; 14 | import java.util.concurrent.Callable; 15 | 16 | /** 17 | * @author YL 18 | */ 19 | @Service 20 | @Slf4j 21 | public class UserServiceImpl implements UserService { 22 | private final UserRepository userRepository; 23 | private final Scheduler jdbcScheduler; 24 | 25 | @Autowired 26 | public UserServiceImpl(UserRepository userRepository, 27 | @Qualifier("jdbcScheduler") Scheduler jdbcScheduler) { 28 | this.userRepository = userRepository; 29 | this.jdbcScheduler = jdbcScheduler; 30 | } 31 | 32 | @Override 33 | public Flux findAll() { 34 | log.info("findAll"); 35 | return asyncIterable(this.userRepository.findAll()); 36 | } 37 | 38 | private Flux asyncIterable(Iterable it) { 39 | return Flux.fromIterable(it).publishOn(this.jdbcScheduler); 40 | } 41 | 42 | @Override 43 | public Mono> findAll2() { 44 | log.info("findAll"); 45 | return asyncCallable(this.userRepository::findAll); 46 | } 47 | 48 | private Mono asyncCallable(Callable cb) { 49 | return Mono.fromCallable(cb).publishOn(this.jdbcScheduler); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /sb-examples/webflux/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8080 3 | spring: 4 | datasource: 5 | platform: h2 6 | driverClassName: org.h2.Driver 7 | url: jdbc:h2:mem:h2test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE 8 | username: root 9 | password: root123 10 | jpa: 11 | database: h2 12 | hibernate: 13 | ddl-auto: update 14 | show-sql: true 15 | properties: 16 | hibernate: 17 | format_sql: true 18 | dialect: org.hibernate.dialect.H2Dialect 19 | # h2: 20 | # console: 21 | # enabled: true 22 | # path: /console 23 | # settings: 24 | # trace: false 25 | # web-allow-others: false -------------------------------------------------------------------------------- /sb-examples/webflux/src/main/resources/data-h2.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO t_user (id, name) VALUES (1, 'test_1'); 2 | INSERT INTO t_user (id, name) VALUES (2, 'test_2'); 3 | INSERT INTO t_user (id, name) VALUES (3, 'test_3'); 4 | INSERT INTO t_user (id, name) VALUES (4, 'test_4'); 5 | INSERT INTO t_user (id, name) VALUES (5, 'test_5'); 6 | INSERT INTO t_user (id, name) VALUES (6, 'test_6'); 7 | INSERT INTO t_user (id, name) VALUES (7, 'test_7'); 8 | INSERT INTO t_user (id, name) VALUES (8, 'test_8'); 9 | INSERT INTO t_user (id, name) VALUES (9, 'test_9'); 10 | INSERT INTO t_user (id, name) VALUES (10, 'test_10'); -------------------------------------------------------------------------------- /sb-examples/webflux/src/main/resources/schema-h2.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `t_user` 2 | ( 3 | `id` int(11) unsigned NOT NULL primary key AUTO_INCREMENT, 4 | `name` varchar(20) DEFAULT NULL 5 | ); -------------------------------------------------------------------------------- /sc-examples/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | top.ylonline 6 | java-best-practice 7 | 1.0-SNAPSHOT 8 | 9 | 4.0.0 10 | 11 | top.ylonline.sc 12 | sc-examples 13 | Java 最佳实践 :: spring-cloud 14 | pom 15 | 16 | 17 | sleuth 18 | 19 | 20 | 21 | UTF-8 22 | 1.8 23 | 1.8 24 | 25 | 26 | -------------------------------------------------------------------------------- /sc-examples/sleuth/src/main/java/top/ylonline/sc/sleuth/SleuthApp.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.sc.sleuth; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.cloud.client.loadbalancer.LoadBalanced; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.web.bind.annotation.RestController; 10 | import org.springframework.web.client.RestTemplate; 11 | import reactor.core.publisher.Flux; 12 | import top.ylonline.sc.sleuth.entity.User; 13 | import top.ylonline.sc.sleuth.repository.UserRepository; 14 | import top.ylonline.sc.sleuth.service.UserService; 15 | 16 | import javax.annotation.Resource; 17 | import java.util.List; 18 | 19 | /** 20 | * Hello world! 21 | * 22 | * @author YL 23 | */ 24 | @SpringBootApplication 25 | @RestController 26 | @Slf4j 27 | public class SleuthApp { 28 | public static void main(String[] args) { 29 | SpringApplication.run(SleuthApp.class, args); 30 | } 31 | 32 | @Bean 33 | @LoadBalanced 34 | public RestTemplate restTemplate() { 35 | return new RestTemplate(); 36 | } 37 | 38 | @Resource 39 | private UserRepository userRepository; 40 | @Resource 41 | private UserService userService; 42 | @Resource 43 | private RestTemplate restTemplate; 44 | 45 | @RequestMapping("/user/list") 46 | public List list() { 47 | log.info("user/list"); 48 | return userRepository.findAll(); 49 | } 50 | 51 | @RequestMapping("/user/list2") 52 | public Flux list2() { 53 | log.info("user/list2"); 54 | List list = (List) restTemplate.getForObject("http://localhost:8080/user/list", List.class); 55 | log.info("list: {}", list); 56 | return userService.findAll(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /sc-examples/sleuth/src/main/java/top/ylonline/sc/sleuth/config/JpaReactiveConfig.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.sc.sleuth.config; 2 | 3 | import org.springframework.beans.factory.annotation.Qualifier; 4 | import org.springframework.beans.factory.annotation.Value; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import reactor.core.scheduler.Scheduler; 8 | import reactor.core.scheduler.Schedulers; 9 | 10 | import java.util.concurrent.Executors; 11 | 12 | /** 13 | * @author YL 14 | */ 15 | @Configuration 16 | public class JpaReactiveConfig { 17 | @Value("${spring.datasource.maximum-pool-size:99}") 18 | private int connectionPoolSize; 19 | 20 | @Bean 21 | @Qualifier("jdbcScheduler") 22 | public Scheduler jdbcScheduler() { 23 | return Schedulers.fromExecutor(Executors.newFixedThreadPool(connectionPoolSize)); 24 | } 25 | 26 | // @Bean 27 | // public TransactionTemplate transactionTemplate(PlatformTransactionManager transactionManager) { 28 | // return new TransactionTemplate(transactionManager); 29 | // } 30 | } 31 | -------------------------------------------------------------------------------- /sc-examples/sleuth/src/main/java/top/ylonline/sc/sleuth/entity/User.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.sc.sleuth.entity; 2 | 3 | import lombok.Data; 4 | 5 | import javax.persistence.Entity; 6 | import javax.persistence.GeneratedValue; 7 | import javax.persistence.GenerationType; 8 | import javax.persistence.Id; 9 | import javax.persistence.Table; 10 | import java.io.Serializable; 11 | 12 | /** 13 | * @author YL 14 | */ 15 | @Entity 16 | @Table(name = "t_user") 17 | @Data 18 | public class User implements Serializable { 19 | private static final long serialVersionUID = 1L; 20 | 21 | @Id 22 | @GeneratedValue(strategy = GenerationType.IDENTITY) 23 | private Long id; 24 | 25 | private String name; 26 | } 27 | -------------------------------------------------------------------------------- /sc-examples/sleuth/src/main/java/top/ylonline/sc/sleuth/repository/UserRepository.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.sc.sleuth.repository; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | import top.ylonline.sc.sleuth.entity.User; 5 | 6 | /** 7 | * @author YL 8 | */ 9 | public interface UserRepository extends JpaRepository { 10 | } 11 | -------------------------------------------------------------------------------- /sc-examples/sleuth/src/main/java/top/ylonline/sc/sleuth/service/UserService.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.sc.sleuth.service; 2 | 3 | import reactor.core.publisher.Flux; 4 | import reactor.core.publisher.Mono; 5 | import top.ylonline.sc.sleuth.entity.User; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * @author YL 11 | */ 12 | public interface UserService { 13 | Flux findAll(); 14 | 15 | Mono> findAll2(); 16 | } 17 | -------------------------------------------------------------------------------- /sc-examples/sleuth/src/main/java/top/ylonline/sc/sleuth/service/UserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.sc.sleuth.service; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.beans.factory.annotation.Qualifier; 5 | import org.springframework.stereotype.Service; 6 | import org.springframework.web.client.RestTemplate; 7 | import reactor.core.publisher.Flux; 8 | import reactor.core.publisher.Mono; 9 | import reactor.core.scheduler.Scheduler; 10 | import top.ylonline.sc.sleuth.entity.User; 11 | import top.ylonline.sc.sleuth.repository.UserRepository; 12 | 13 | import java.util.List; 14 | import java.util.concurrent.Callable; 15 | 16 | /** 17 | * @author YL 18 | */ 19 | @Service 20 | @Slf4j 21 | public class UserServiceImpl implements UserService { 22 | private final UserRepository userRepository; 23 | private final Scheduler jdbcScheduler; 24 | private final RestTemplate restTemplate; 25 | 26 | public UserServiceImpl(UserRepository userRepository, 27 | @Qualifier("jdbcScheduler") Scheduler jdbcScheduler, 28 | RestTemplate restTemplate) { 29 | this.userRepository = userRepository; 30 | this.jdbcScheduler = jdbcScheduler; 31 | this.restTemplate = restTemplate; 32 | } 33 | 34 | @Override 35 | public Flux findAll() { 36 | List list = (List) restTemplate.getForObject("http://localhost:8080/user/list", List.class); 37 | log.info("list: {}", list); 38 | return asyncIterable(this.userRepository.findAll()); 39 | } 40 | 41 | private Flux asyncIterable(Iterable it) { 42 | return Flux.fromIterable(it).publishOn(this.jdbcScheduler); 43 | } 44 | 45 | @Override 46 | public Mono> findAll2() { 47 | log.info("findAll2"); 48 | return asyncCallable(this.userRepository::findAll); 49 | } 50 | 51 | private Mono asyncCallable(Callable cb) { 52 | return Mono.fromCallable(cb).publishOn(this.jdbcScheduler); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /sc-examples/sleuth/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8080 3 | spring: 4 | datasource: 5 | platform: h2 6 | driverClassName: org.h2.Driver 7 | url: jdbc:h2:mem:h2test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE 8 | username: root 9 | password: root123 10 | jpa: 11 | database: h2 12 | hibernate: 13 | ddl-auto: update 14 | show-sql: false 15 | properties: 16 | hibernate: 17 | format_sql: false 18 | dialect: org.hibernate.dialect.H2Dialect 19 | # h2: 20 | # console: 21 | # enabled: true 22 | # path: /console 23 | # settings: 24 | # trace: false 25 | # web-allow-others: false -------------------------------------------------------------------------------- /sc-examples/sleuth/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: sleuth -------------------------------------------------------------------------------- /sc-examples/sleuth/src/main/resources/data-h2.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO t_user (id, name) VALUES (1, 'test_1'); 2 | INSERT INTO t_user (id, name) VALUES (2, 'test_2'); 3 | INSERT INTO t_user (id, name) VALUES (3, 'test_3'); 4 | INSERT INTO t_user (id, name) VALUES (4, 'test_4'); 5 | INSERT INTO t_user (id, name) VALUES (5, 'test_5'); 6 | INSERT INTO t_user (id, name) VALUES (6, 'test_6'); 7 | INSERT INTO t_user (id, name) VALUES (7, 'test_7'); 8 | INSERT INTO t_user (id, name) VALUES (8, 'test_8'); 9 | INSERT INTO t_user (id, name) VALUES (9, 'test_9'); 10 | INSERT INTO t_user (id, name) VALUES (10, 'test_10'); -------------------------------------------------------------------------------- /sc-examples/sleuth/src/main/resources/schema-h2.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `t_user` 2 | ( 3 | `id` int(11) unsigned NOT NULL primary key AUTO_INCREMENT, 4 | `name` varchar(20) DEFAULT NULL 5 | ); -------------------------------------------------------------------------------- /sentinel-examples/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | top.ylonline 6 | java-best-practice 7 | 1.0-SNAPSHOT 8 | 9 | 4.0.0 10 | 11 | top.ylonline.sentinel 12 | sentinel-examples 13 | Java 最佳实践 :: sentinel 14 | pom 15 | 16 | 17 | sentinel-cluster-example 18 | sentinel-spring-cloud-example 19 | 20 | 21 | 22 | UTF-8 23 | 1.8 24 | 1.8 25 | 26 | 27 | -------------------------------------------------------------------------------- /sentinel-examples/sentinel-cluster-example/README.md: -------------------------------------------------------------------------------- 1 | # sentinel-cluster-example(未完成) 2 | 3 | 使用 Nacos 作为 Sentinel 的规则数据源(zk、apollo配置同理),集群模式配置例子。 4 | 5 | ## sentinel dashboard 改造 6 | 7 | 8 | ## sentinel 服务端 9 | 10 | 11 | ## sentinel 客服端 12 | -------------------------------------------------------------------------------- /sentinel-examples/sentinel-cluster-example/sentinel-cluster-client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | top.ylonline.sentinel 6 | sentinel-cluster-example 7 | 1.0-SNAPSHOT 8 | 9 | 4.0.0 10 | 11 | sentinel-cluster-client 12 | Java 最佳实践 :: sentinel(${project.artifactId}) 13 | 14 | 15 | UTF-8 16 | 1.8 17 | 1.8 18 | 19 | 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-web 24 | 25 | 26 | 27 | 28 | org.springframework.cloud 29 | spring-cloud-starter-alibaba-nacos-config 30 | 0.2.1.RELEASE 31 | 32 | 33 | 34 | 35 | org.springframework.cloud 36 | spring-cloud-starter-alibaba-sentinel 37 | 0.2.1.RELEASE 38 | 39 | 40 | com.alibaba.csp 41 | sentinel-dubbo-adapter 42 | 43 | 44 | com.alibaba.csp 45 | sentinel-cluster-server-default 46 | 47 | 48 | 49 | 50 | 51 | com.alibaba.csp 52 | sentinel-datasource-nacos 53 | 1.4.0 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /sentinel-examples/sentinel-cluster-example/sentinel-cluster-client/src/main/java/top/ylonline/sentinel/SentinelClusterClientApp.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.sentinel; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | /** 7 | * @author YL 8 | */ 9 | @SpringBootApplication 10 | public class SentinelClusterClientApp { 11 | 12 | public static void main(String[] args) { 13 | SpringApplication.run(SentinelClusterClientApp.class, args); 14 | synchronized (SentinelClusterClientApp.class) { 15 | while (true) { 16 | try { 17 | SentinelClusterClientApp.class.wait(); 18 | } catch (Exception e) { 19 | e.printStackTrace(); 20 | break; 21 | } 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /sentinel-examples/sentinel-cluster-example/sentinel-cluster-client/src/main/resources/META-INF/services/com.alibaba.csp.sentinel.init.InitFunc: -------------------------------------------------------------------------------- 1 | top.ylonline.sentinel.server.init.NacosDatasourceInitFunc -------------------------------------------------------------------------------- /sentinel-examples/sentinel-cluster-example/sentinel-cluster-client/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8080 3 | spring: 4 | cloud: 5 | sentinel: 6 | transport: 7 | dashboard: 192.168.56.101:8847 8 | port: 8718 9 | filter: 10 | url-patterns: 11 | - '/*' 12 | datasource: 13 | ds1: 14 | nacos: 15 | server-addr: 192.168.56.101:8848 16 | dataId: sentinel 17 | groupId: SENTINET-GROUP -------------------------------------------------------------------------------- /sentinel-examples/sentinel-cluster-example/sentinel-cluster-client/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: sentinel-cluster-client 4 | cloud: 5 | nacos: 6 | config: 7 | server-addr: 192.168.56.101:8848 -------------------------------------------------------------------------------- /sentinel-examples/sentinel-cluster-example/sentinel-cluster-client/src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | ${logger.pattern} 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /sentinel-examples/sentinel-cluster-example/sentinel-cluster-server-alone/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | top.ylonline.sentinel 6 | sentinel-cluster-example 7 | 1.0-SNAPSHOT 8 | 9 | 4.0.0 10 | 11 | sentinel-cluster-server-alone 12 | Java 最佳实践 :: sentinel(${project.artifactId}) 13 | 14 | 15 | UTF-8 16 | 1.8 17 | 1.8 18 | 19 | 20 | 21 | 22 | 23 | org.springframework.cloud 24 | spring-cloud-starter-alibaba-nacos-config 25 | 0.2.1.RELEASE 26 | 27 | 28 | 29 | 30 | org.springframework.cloud 31 | spring-cloud-starter-alibaba-sentinel 32 | 0.2.1.RELEASE 33 | 34 | 35 | com.alibaba.csp 36 | sentinel-dubbo-adapter 37 | 38 | 39 | com.alibaba.csp 40 | sentinel-web-servlet 41 | 42 | 43 | com.alibaba.csp 44 | sentinel-cluster-client-default 45 | 46 | 47 | 48 | 49 | com.alibaba.csp 50 | sentinel-datasource-nacos 51 | 1.4.0 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /sentinel-examples/sentinel-cluster-example/sentinel-cluster-server-alone/src/main/java/top/ylonline/sentinel/SentinelClusterServerApp.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.sentinel; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | /** 7 | * @author YL 8 | */ 9 | @SpringBootApplication 10 | public class SentinelClusterServerApp { 11 | 12 | public static void main(String[] args) { 13 | SpringApplication.run(SentinelClusterServerApp.class, args); 14 | synchronized (SentinelClusterServerApp.class) { 15 | while (true) { 16 | try { 17 | SentinelClusterServerApp.class.wait(); 18 | } catch (Exception e) { 19 | e.printStackTrace(); 20 | break; 21 | } 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /sentinel-examples/sentinel-cluster-example/sentinel-cluster-server-alone/src/main/resources/META-INF/services/com.alibaba.csp.sentinel.init.InitFunc: -------------------------------------------------------------------------------- 1 | top.ylonline.sentinel.init.NacosDatasourceInitFunc -------------------------------------------------------------------------------- /sentinel-examples/sentinel-cluster-example/sentinel-cluster-server-alone/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | cloud: 3 | sentinel: 4 | transport: 5 | dashboard: 192.168.56.101:8847 6 | port: 8719 7 | filter: 8 | url-patterns: 9 | - '/*' -------------------------------------------------------------------------------- /sentinel-examples/sentinel-cluster-example/sentinel-cluster-server-alone/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: sentinel-cluster-server-alone 4 | cloud: 5 | nacos: 6 | config: 7 | server-addr: 192.168.56.101:8848 -------------------------------------------------------------------------------- /sentinel-examples/sentinel-cluster-example/sentinel-cluster-server-alone/src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | ${logger.pattern} 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /sentinel-examples/sentinel-spring-cloud-example/README.md: -------------------------------------------------------------------------------- 1 | # sentinel-spring-cloud-example 2 | 3 | - 正常返回 4 | 5 | - 请求 [http://localhost:8080/sentinel/demo](http://localhost:8080/sentinel/demo) 可以看到正常返回`Hello world!`。 6 | 7 | - 同时可以在[Sentinel](https://github.com/alibaba/Sentinel) Dashboard 看到 8 | `sentinel-spring-cloud-example` 项 9 | 10 | 11 | - 添加流控规则 12 | 13 | - 在`簇点链路`菜单选择对 `/demo` 添加流控规则,阈值类型=QPS,单机阈值=0 14 | 15 | - 再次请求 [http://localhost:8080/sentinel/demo](http://localhost:8080/sentinel/demo) 可以看到返回`Blocked by Sentinel (flow 16 | limiting)`,表明配置的流控规则已经生效了。 -------------------------------------------------------------------------------- /sentinel-examples/sentinel-spring-cloud-example/src/main/java/top/ylonline/sentinel/spring/cloud/example/SentinelApp.java: -------------------------------------------------------------------------------- 1 | package top.ylonline.sentinel.spring.cloud.example; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.springframework.web.bind.annotation.RestController; 7 | 8 | @SpringBootApplication 9 | @RestController 10 | public class SentinelApp { 11 | public static void main(String[] args) { 12 | SpringApplication.run(SentinelApp.class, args); 13 | } 14 | 15 | @GetMapping("/demo") 16 | public String demo() { 17 | return "Hello world!"; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /sentinel-examples/sentinel-spring-cloud-example/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8080 3 | servlet: 4 | context-path: /sentinel 5 | spring: 6 | application: 7 | name: sentinel-spring-cloud-example 8 | cloud: 9 | sentinel: 10 | transport: 11 | dashboard: 192.168.56.101:8847 12 | port: 8719 13 | filter: 14 | url-patterns: 15 | - '/*' -------------------------------------------------------------------------------- /sentinel-examples/sentinel-spring-cloud-example/src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | ${logger.pattern} 10 | 11 | 12 | 13 | 14 | 15 | --------------------------------------------------------------------------------