spring-cloud-kubernetes学习(一) 编写第一个spring-cloud-kubernetes例子并在kubernetes中测试
在springcloud生态中,服务治理与注册中心等都有相应的组件。如eureka、hystrix,ribbon等。但是kubernetes组件也有服务发现、负载均衡的组件,我们可以借助于sping-cloud-kubernetes组件为我们提供的服务发现、负载均衡等来摈弃像eureka这样的注册中心。本文主要通过构建两个spring cloud 服务来演示spring-cloud-kubernetes组件如何做服务的发现,负载均衡等。
项目地址:https://gitee.com/quanwenz/micro-service-frame/repository/archive/first
一、首先搭建服务:
构建使用gradle,使用maven类似,只是引入方式稍微不同
1、使用gradle创建一个java工程
2、添加gradle.properties文件
这里从其他项目中拉过来的,可能有些冗余
nexusUrl=http://172.16.10.190:8081/repository/maven-public/
#nexusUrl=http://maven.aliyun.com/nexus/content/groups/public
aliyunUrl=http://maven.aliyun.com/nexus/content/groups/public
springUrl=https://repo.spring.io/libs-milestone/#java-version
javaVersion=1.8## dependency versions.
#springBootVersion=2.2.6.RELEASE
springBootVersion=2.3.5.RELEASE
#platformVersion=Cairo-SR7
platformVersion=Cairo-SR8
junitVersion=4.12
springCloudConfigVersion=2.0.0.RELEASE
lombokVersion=1.18.4#micro service versions
#openFeginVersion=2.2.5.RELEASE
#springCloudKubernetesVersion=1.1.7.RELEASE
springCloudVersion=Hoxton.SR9
#springCloudCommonsVersion=2.2.6.RELEASE
#springCloudNetflixRibbonVersion=2.2.6.RELEASE#common-redis-tools dependency versions
#jedisVersion=2.9.0
jedisVersion=3.3.0
jedis.version=${jedisVersion}
fastJsonVersion=1.2.59
lettuceCoreVersion=6.0.1.RELEASE#common-web-tools dependency versions
servletApiVersion=4.0.1
servletApi.version=${servletApiVersion}
jsoncodeVersion=1.2.4
yuicompressorVersion=2.4.8
jsonlibVersion=2.4:jdk15
orgJsonVersion=20190722
xomVersion=1.2.5
UserAgentUtilsVersion=1.20
jacksonVersion=2.9.8#common-tools dependency versions
htmlsuckerVersion=0.0.2
ostermillerVersion=1.07.00
commonLang3Version=3.8.1
dom4jVersion=1.6.1
poiVersion=3.17
poiOoxmlVersion=3.17
emojiJavaVersion=4.0.0
okioVersion=2.2.2
freemarkerVersion=2.3.28
bopomofo4jVersion=1.0.0
junrarVersion=4.0.0#common-rpc-tools
sofaVersion=5.7.6
grpcVersion=1.33.1
protocVersion=3.2.0
protocGenGrpcJavaVersion=1.4.0
libthriftVersion=0.13.0#org.apache.xmlbeans.version=2.3.0
commonsIoVersion=2.6
codecVersion=1.14
staxVersion=1.0.1
commonsBeanutilsVersion=1.9.3
itextAsianVersion=5.2.0
itextVersion=2.1.7
zxingCoreVersion=3.2.1
apacheAntVersion=1.7.1
ip2regionVersion=1.7
htoolVersion=4.1.15
cglibVersion=3.2.8
guavaVersion=20.0
pingyin4jVersion=2.5.1
itextpdfVersion=5.2.0
lowagieVersion=2.1.7
zxingVersion=3.2.1
antVersion=1.7.1#biz-base biz-mp dependency versions
#mybatisStaterVersion=1.3.2
#mysqlVersion=5.1.47
mysqlVersion=8.0.15
pagehelperVersion=1.2.5
druidVersion=1.1.16
okhttp.version=3.10.0
freemarker.version=2.3.28
caffeine.version=2.6.2
gson.version=2.8.5
jwtVersion=3.3.0
swaggerVersion=3.0.0
nettyVersion=4.1.26.Final
asciidoctorVersion=1.5.3
asciidoctorPDFVersion=1.5.0-alpha.10.1
swagger2markupDocVersion=1.3.3
userAgentUtilVersion=1.2.4
mybatis_plus_boot_starter_version=3.3.1.tmp
velocity_engine_core_version=2.0
jsoupVersion=1.11.3
logExpansionVersion=0.0.2.RELEASE
rsaEncryVersion=1.0.1.RELEASE
knife4jVersion=2.0.1
kaptchaVersion=2.3.2
screwCoreVersion=1.0.5#biz-jpa
javaxValidationVersion=2.0.1.Final#log-expansion
shadowVersion=5.0.0#javassist
javassistVersion=3.25.0-GAhostMachineIp=192.168.100.88
gradle_docker_version=1.2#common-k8s-tools
kubernetesClientVersion=4.6.1#springboot-admin
bootAdminVersion=2.2.2#rule-engine
aviatorVersion=4.2.9
3、创建三个模块
service-api、product-test-prop-service、consumer-test-prop-service
其中service-api定义Fegin的API
product-test-prop-service模拟一个提供者服务
consumer-test-prop-service模拟一个消费者服务
4、service-api中build.xml
apply plugin: 'java'dependencies {compile "org.springframework.cloud:spring-cloud-starter-openfeign"
// compile group: 'javax.servlet', name: 'javax.servlet-api', version: "${servletApiVersion}"}
5、service-api中编写接口和降级处理
接口:
/*** 测试接口** @author zhuquanwen* @vesion 1.0* @date 2020/12/6 9:59* @since jdk1.8*/
@Component
@FeignClient(name="${feign.product-prop.name:product-test-service}",fallback = PropertyClientFallback.class)
public interface PropertyClient {@GetMapping(value="properties")List<String> getProperties();
}
上面的FeignClient注解中的name使用和后面kubernetes中对应service一样的名字
降级处理:
/***** @author zhuquanwen* @vesion 1.0* @date 2020/12/6 10:05* @since jdk1.8*/
@Component
public class PropertyClientFallback implements PropertyClient {@Overridepublic List<String> getProperties() {return new ArrayList<String>();}
}
6、product-test-prop-service中build.xml
注意引入了service-api模块
apply plugin: 'java'dependencies {compile project(":service-api")compile "org.springframework.boot:spring-boot-starter-web"compile "org.springframework.boot:spring-boot-starter-actuator"compile group: 'org.springframework.boot', name: 'spring-boot-starter-undertow'}
7、product-test-prop-service的接口实现
/***** @author zhuquanwen* @vesion 1.0* @date 2020/12/6 10:43* @since jdk1.8*/
@RestController
@RequestMapping
public class PropertyController implements PropertyClient {@GetMapping("properties")public List<String> getProperties(){ArrayList<String> properties = new ArrayList<>();properties.add("properties1");properties.add("properties2");return properties;}}
8、product-test-prop-service的application.properties配置文件
server.port=8080
9、product-test-prop-service的启动类
/**** @author zhuquanwen* @vesion 1.0* @date 2020/12/6 11:12* @since jdk1.8*/
@SpringBootApplication
//@EnableFeignClients
public class Start {public static void main(String[] args) {SpringApplication.run(Start.class, args);}}
10、consumer-test-prop-service中build.xml
apply plugin: 'java'dependencies {compile project(":service-api")compile "org.springframework.cloud:spring-cloud-kubernetes-core"compile "org.springframework.cloud:spring-cloud-kubernetes-discovery"compile "org.springframework.cloud:spring-cloud-starter-kubernetes-ribbon"compile "org.springframework.cloud:spring-cloud-commons"compile "org.springframework.cloud:spring-cloud-starter-netflix-ribbon"compile "org.springframework.cloud:spring-cloud-starter-netflix-hystrix"compile "org.springframework.boot:spring-boot-starter-web"compile group: 'org.springframework.boot', name: 'spring-boot-starter-undertow'}
11、consumer-test-prop-service中调用类
/***** @author zhuquanwen* @vesion 1.0* @date 2020/12/6 11:00* @since jdk1.8*/
@RestController
@RequestMapping
public class ConsumerPropController {@Resourceprivate PropertyClient propertyClient;@GetMapping("properties")public List<String> getProductProperties(){return propertyClient.getProperties();}
}
12、consumer-test-prop-service中application.yml配置文件
其中KubernetesNamespace配置为后面使用的kubernetes的命名空间
server:port: 8080spring:application:name: consumer-test-prop-serviceproduct-test-prop-service:ribbon:KubernetesNamespace: defaultbackend:ribbon:eureka:enabled: falseclient:enabled: trueServerListRefreshInterval: 5000hystrix:command:BackendCall:execution:isolation:thread:timeoutInMilliseconds: 5000threadpool:BackendCallThread:coreSize: 5
feign:hystrix:enabled: true
13、consumer-test-prop-service中启动类
/**** @author zhuquanwen* @vesion 1.0* @date 2020/12/6 11:12* @since jdk1.8*/
@SpringBootApplication
@Configuration
@ServletComponentScan //自动扫描serletBean
@ComponentScan(basePackages = {"com.iscas"})
@EnableDiscoveryClient
@EnableFeignClients(basePackages = {"com.iscas"})
//@EnableFeignClients(basePackageClasses = {PropertyClient.class, PropertyClientFallback.class})public class Start {public static void main(String[] args) {SpringApplication springApplication = new SpringApplication(Start.class);springApplication.run(args);}}
OK,现在我们把项目搭建完了,启动两个启动类(注意端口一样的,可以把生产者的端口换一下)
访问http://localhost:8080/properties在浏览器返回了“[]”,没有返回“[“properties1”,“properties2”]”,这是因为没有运行在k8s中,没有服务发现,降级处理了。
控制台的报错也能证明
2020-12-06 16:08:09.876 WARN 5356 --- [-test-service-1] s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'ribbonLoadBalancingHttpClient' defined in org.springframework.cloud.netflix.ribbon.apache.HttpClientRibbonConfiguration: Unsatisfied dependency expressed through method 'ribbonLoadBalancingHttpClient' parameter 2; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'ribbonLoadBalancer' defined in org.springframework.cloud.netflix.ribbon.RibbonClientConfiguration: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.netflix.loadbalancer.ILoadBalancer]: Factory method 'ribbonLoadBalancer' threw exception; nested exception is io.fabric8.kubernetes.client.KubernetesClientException: Operation: [get] for kind: [Endpoints] with name: [product-test-service] in namespace: [null] failed.
2020-12-06 16:08:10.825 WARN 5356 --- [erListUpdater-0] c.n.l.PollingServerListUpdater : Failed one update cycleio.fabric8.kubernetes.client.KubernetesClientException: Operation: [get] for kind: [Endpoints] with name: [product-test-service] in namespace: [null] failed.at io.fabric8.kubernetes.client.KubernetesClientException.launderThrowable(KubernetesClientException.java:64) ~[kubernetes-client-4.10.3.jar:na]at io.fabric8.kubernetes.client.KubernetesClientException.launderThrowable(KubernetesClientException.java:72) ~[kubernetes-client-4.10.3.jar:na]at io.fabric8.kubernetes.client.dsl.base.BaseOperation.getMandatory(BaseOperation.java:244) ~[kubernetes-client-4.10.3.jar:na]at io.fabric8.kubernetes.client.dsl.base.BaseOperation.get(BaseOperation.java:187) ~[kubernetes-client-4.10.3.jar:na]at io.fabric8.kubernetes.client.dsl.base.BaseOperation.get(BaseOperation.java:79) ~[kubernetes-client-4.10.3.jar:na]at org.springframework.cloud.kubernetes.ribbon.KubernetesEndpointsServerList.getUpdatedListOfServers(KubernetesEndpointsServerList.java:58) ~[spring-cloud-kubernetes-ribbon-1.1.7.RELEASE.jar:1.1.7.RELEASE]at com.netflix.loadbalancer.DynamicServerListLoadBalancer.updateListOfServers(DynamicServerListLoadBalancer.java:240) ~[ribbon-loadbalancer-2.3.0.jar:2.3.0]at com.netflix.loadbalancer.DynamicServerListLoadBalancer$1.doUpdate(DynamicServerListLoadBalancer.java:62) ~[ribbon-loadbalancer-2.3.0.jar:2.3.0]at com.netflix.loadbalancer.PollingServerListUpdater$1.run(PollingServerListUpdater.java:116) ~[ribbon-loadbalancer-2.3.0.jar:2.3.0]at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_144]at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) [na:1.8.0_144]at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180) [na:1.8.0_144]at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) [na:1.8.0_144]at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_144]at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_144]at java.lang.Thread.run(Thread.java:748) [na:1.8.0_144]
Caused by: java.net.UnknownHostException: kubernetes.default.svcat java.net.InetAddress.getAllByName0(InetAddress.java:1280) ~[na:1.8.0_144]at java.net.InetAddress.getAllByName(InetAddress.java:1192) ~[na:1.8.0_144]at java.net.InetAddress.getAllByName(InetAddress.java:1126) ~[na:1.8.0_144]at okhttp3.Dns$1.lookup(Dns.java:40) ~[okhttp-3.10.0.jar:na]at okhttp3.internal.connection.RouteSelector.resetNextInetSocketAddress(RouteSelector.java:185) ~[okhttp-3.10.0.jar:na]at okhttp3.internal.connection.RouteSelector.nextProxy(RouteSelector.java:149) ~[okhttp-3.10.0.jar:na]at okhttp3.internal.connection.RouteSelector.next(RouteSelector.java:84) ~[okhttp-3.10.0.jar:na]at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:214) ~[okhttp-3.10.0.jar:na]at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:135) ~[okhttp-3.10.0.jar:na]at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:114) ~[okhttp-3.10.0.jar:na]at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42) ~[okhttp-3.10.0.jar:na]at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147) ~[okhttp-3.10.0.jar:na]at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121) ~[okhttp-3.10.0.jar:na]at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93) ~[okhttp-3.10.0.jar:na]at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147) ~[okhttp-3.10.0.jar:na]at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121) ~[okhttp-3.10.0.jar:na]at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93) ~[okhttp-3.10.0.jar:na]at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147) ~[okhttp-3.10.0.jar:na]at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:126) ~[okhttp-3.10.0.jar:na]at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147) ~[okhttp-3.10.0.jar:na]at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121) ~[okhttp-3.10.0.jar:na]at io.fabric8.kubernetes.client.utils.BackwardsCompatibilityInterceptor.intercept(BackwardsCompatibilityInterceptor.java:134) ~[kubernetes-client-4.10.3.jar:na]at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147) ~[okhttp-3.10.0.jar:na]at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121) ~[okhttp-3.10.0.jar:na]at io.fabric8.kubernetes.client.utils.ImpersonatorInterceptor.intercept(ImpersonatorInterceptor.java:68) ~[kubernetes-client-4.10.3.jar:na]at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147) ~[okhttp-3.10.0.jar:na]at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121) ~[okhttp-3.10.0.jar:na]at io.fabric8.kubernetes.client.utils.HttpClientUtils.lambda$createHttpClient$3(HttpClientUtils.java:149) ~[kubernetes-client-4.10.3.jar:na]at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147) ~[okhttp-3.10.0.jar:na]at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121) ~[okhttp-3.10.0.jar:na]at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:200) ~[okhttp-3.10.0.jar:na]at okhttp3.RealCall.execute(RealCall.java:77) ~[okhttp-3.10.0.jar:na]at io.fabric8.kubernetes.client.dsl.base.OperationSupport.handleResponse(OperationSupport.java:490) ~[kubernetes-client-4.10.3.jar:na]at io.fabric8.kubernetes.client.dsl.base.OperationSupport.handleResponse(OperationSupport.java:451) ~[kubernetes-client-4.10.3.jar:na]at io.fabric8.kubernetes.client.dsl.base.OperationSupport.handleGet(OperationSupport.java:416) ~[kubernetes-client-4.10.3.jar:na]at io.fabric8.kubernetes.client.dsl.base.OperationSupport.handleGet(OperationSupport.java:397) ~[kubernetes-client-4.10.3.jar:na]at io.fabric8.kubernetes.client.dsl.base.BaseOperation.handleGet(BaseOperation.java:890) ~[kubernetes-client-4.10.3.jar:na]at io.fabric8.kubernetes.client.dsl.base.BaseOperation.getMandatory(BaseOperation.java:233) ~[kubernetes-client-4.10.3.jar:na]... 13 common frames omitted
二、将两个服务运行在kubernetes中
现在我们将两个服务打包并在kubernetes集群中运行,kubernetes的搭建过程可参考前面的文章
1、gradle将两个服务打包,上传至安装了docker服务上
2、将两个jar包打成镜像
一个jar打完再打另一个
把jar包名改为app.jar
在jar包所在目录编写Dockerfile
FROM java:8-alpine
ADD app.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar", "/app.jar"]
java:8-alpine 镜像可以从网上下载,多的很
运行两个命令将jar包
docker build -t 192.168.100.91:80/product-test:0.0.1 .
192.168.100.91:80是我本地镜像服务的地址
推送到docker镜像服务
docker push 192.168.100.91:80/product-test:0.0.1
接着再把消费者的jar也打好,名字我用的192.168.100.91:80/consumer-test:0.0.1
3、在kubernetes的default空间中创建一个用户,给以最高权限
master节点创建account.yaml
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:name: test #ClusterRoleBinding的名字
subjects:- kind: ServiceAccountname: test #serviceaccount资源对象的namenamespace: default #serviceaccount的namespace
roleRef:kind: ClusterRole name: cluster-admin #k8s集群中最高权限的角色apiGroup: rbac.authorization.k8s.io
---
apiVersion: v1
kind: ServiceAccount
metadata:name: test # ServiceAccount的名字namespace: default # serviceaccount的namespacelabels:app: test #ServiceAccount的标签
运行apply -f account.yaml
4、创建product-deployment.yaml
注意serviceAccountName要使用上面创建的test
---apiVersion: extensions/v1beta1kind: Deploymentmetadata:name: product-testspec:replicas: 2template:metadata:labels:app: webspec:containers:- name: product-test-instanceimage: 192.168.100.91:80/product-test:0.0.1ports:- containerPort: 8080serviceAccountName: test
kubectl apply -f product-deployment.yaml
5、创建product-service.yaml
注意这个serivice不使用Nodeport的方式向外发布
---
apiVersion: v1
kind: Service
metadata:name: product-test-servicelabels:name: product-test-service
spec:#type: NodePort #这里代表是NodePort类型的ports:- port: 8080 #这里的端口和clusterIP对应,即ip:8080,供内部访问。targetPort: 8080 #端口一定要和container暴露出来的端口对应protocol: TCP# nodePort: 32143 # 所有的节点都会开放此端口,此端口供外部调用。selector:app: web #这里选择器一定要选择容器的标签,之前写name:kube-node是错的。
kubectl apply -f product-service.yaml
6、创建consumer-deployments.yaml
注意serviceAccountName要使用上面创建的test
---apiVersion: extensions/v1beta1kind: Deploymentmetadata:name: consumer-testspec:replicas: 2template:metadata:labels:app: web-consumerspec:containers:- name: consumer-test-instanceimage: 192.168.100.91:80/consumer-test:0.0.1ports:- containerPort: 8080serviceAccountName: test
kubectl apply -f consumer-deployment.yaml
7、创建consumer-service.yaml
注意这个serivice使用Nodeport的方式向外发布,测试访问
---
apiVersion: v1
kind: Service
metadata:name: consumer-test-servicelabels:name: consumer-test-service
spec:type: NodePort #这里代表是NodePort类型的ports:- port: 8080 #这里的端口和clusterIP对应,即ip:8080,供内部访问。targetPort: 8080 #端口一定要和container暴露出来的端口对应protocol: TCPnodePort: 32144 # 所有的节点都会开放此端口,此端口供外部调用。selector:app: web-consumer #这里选择器一定要选择容器的标签,之前写name:kube-node是错的。
kubectl apply -f consumer-service.yaml
8、从浏览器访问http://[k8s一个Node的IP]:32144/properties
返回了“[“properties1”,“properties2”]”,证明调用成功了
三、spring cloud kubernetes调用过程
从网上找到调用过程图:
从上图可以看出product-infra-consumer在调用product-infra-service时,通过FeignClient组件拿到service name信息,最底层通过ok-http3,根据service name 调用 api server 获取该service下对应的Pod信息,拿到Pod信息后通过,轮询的方式向这些pod发送请求。spring-cloud-starter-kubernetes-ribbon组件中的KubernetesServerList 继承了 ribbon-loaderbanlancer组件中的AbstractServerList以及实现了 ServerList类中的方法,并通过 KubernetesClient提供的能力向k8s api server 发送请求信息。
spring-cloud-kubernetes学习(一) 编写第一个spring-cloud-kubernetes例子并在kubernetes中测试相关推荐
- Spring学习笔记:第一个Spring Boot程序HelloWorld
Spring学习笔记:第一个Spring Boot程序HelloWorld 一.跟着 Spring 了解技术趋势 1.看看 Spring 5.x 的改变暗示了什么 2.Spring Boot 和 Sp ...
- 搭建Spring开发环境并编写第一个Spring小程序
一.前面,我写了一篇Spring框架的基础知识文章,里面没讲到如何配置Spring开发环境,今天就来讲一下,如果大家不知道怎么下载Spring软件包的话,可以看我那篇文章: http://blog.c ...
- 编写第一个Spring程序——IOC实现
第一个Spring程序 IOC范例 1.新建maven工程 2.在pom.xml文件中导入相关jar包 <!-- https://mvnrepository.com/artifact/org.s ...
- Spring Boot-Spring Tool Suit + Gradle 构建第一个Spring Boot 项目02
概述 将工程托管到Github Gradle构建 为什么一个main函数就能启动web并提供这么多功能 幕后的 Spring Boot 分发器和 multipart 配置 视图解析器.静态资源以及区域 ...
- 【Spring 工厂】工厂设计模式、第一个Spring程序细节分析、整合日志框架
Spring 引言 什么是 Spring? 工厂设计模式 简单工厂的设计 通用工厂的设计 通用工厂的使用方式 第一个 Spring 程序 环境搭建 Spring 的核心API 程序开发 细节分析 Sp ...
- Spring基础专题——第一章(第一个Spring程序)
前言:去年到现在一直没有很好的时间完成这个spring基础+源码的博客目标,去年一年比较懒吧,所以今年我希望我的知识可以分享给正在奋斗中的互联网开发人员,以及未来想往架构师上走的道友们我们一起进步,从 ...
- Spring Boot-Spring Tool Suit + Gradle 构建第一个Spring Boot 项目01
文章目录 概述 使用Spring Tool Suite构建Spring Boot项目 下载STS 插件安装 搭建第一个Spring Boot项目 启动项目 概述 通常,构建一个Spring Boot项 ...
- spring 3.x 学习笔记_spring mvc、spring jdbc 实现网站的登录注册功能
使用spring mvc.spring jdbc 实现网站的登录注册功能 1. 据业务模型 创建model 一般实现序列化 2. 用spring 注解(@Repositor ...
- Spring 源码学习一: 使用Gradle 构建Spring 源码环境
Gradle安装 下载Gradle: https://gradle.org/releases/ 选择安装的版本: 6.x 以上 选择版本后,点击下载. 配置环境变量: unzip gradle-6.8 ...
最新文章
- 基金委最新改革:9大科学部整合为4个板块资助布局
- PHP项目部署在tomcat,在Tomcat中部署Web项目的操作方法(必看篇)
- sublime text使用正则表达式批量给KV加
- Python爬虫开发:requests库的使用--ip代理参数的设置
- 特别策划:视频会议协作平台的机会与技术挑战
- html h1转换为行内,css中转换为行内样式的解决方案(css-inline)
- 一款C++ 可视化调试工具增强插件
- pythonsubprocess执行多条shell命令_Python获取shell管道数据/输入的2种方法: subprocess子进程 ......
- 关于坑爹的编解码问题
- HTML+JS调用摄像头
- 2017微软校园招聘笔试题
- MySQL:复合查询和内外连接
- 基于Canvas+React的高性能Table表格
- Android查看手机sqlite数据库(可视化)
- 我该如何在csdn上免费下载资料?
- 店盈通:拼多多如何看到关键词进店?
- 注册表编辑器无法在当前所选的项及其部分子项上设置安全性
- 近年来作品整理——软件和网站设计小结
- mac连接远程Linux(Ubuntu)
- Arduino循迹小车教程四----代码篇