SpringMvc 项目转 SringBoot
来源:互联网 发布:php过滤所有html标签 编辑:程序博客网 时间:2024/05/19 08:03
个人实践 和 备忘
项目结构 :
分布式项目, 利用maven构建了多模块, 开发还是 ssm , 项目中 有mq 和 redis , memcached。都是通过 配置文件加载,开头是web.xml 引入spring-x.xml , spring-x.xml 再去引入 其他配置文件,znf4-common-config 用来配置 *.properties 文件,mq ,jdbc , redis 系统等相关配置。
现引入Boot 先关jar包 :
我是一次性引入了很多个相关jar , 有些也没用上,你们自行去除就行。
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <spring-boot.version>1.3.1.RELEASE</spring-boot.version> <tomcat.version>8.0.28</tomcat.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> </dependency> <!-- spring-boot start --> <dependency> <!-- Import dependency management from Spring Boot --> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version>${spring-boot.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>${spring-boot.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> <version>${spring-boot.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-remote-shell</artifactId> <version>${spring-boot.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <version>${spring-boot.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> <version>${spring-boot.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <version>${spring-boot.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> <version>${tomcat.version}</version> <scope>provided</scope> </dependency> <!--spring boot end-->
加入启动模块 :
ApplicationStarter .java
package com.znf4.app;import org.springframework.boot.Banner;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.context.annotation.ImportResource;/** * Created by agui on 15/10/26. */@SpringBootApplication@ImportResource("classpath:spring/spring-context.xml")public class ApplicationStarter { public static void main(String[] args) { SpringApplication app = new SpringApplication(ApplicationStarter.class); app.setAdditionalProfiles(); app.setBannerMode(Banner.Mode.LOG); app.run(args); }}
上面类中 注解 :@ImportResource(“classpath:spring/spring-context.xml”) ,用来引入:
说明 :spring-contet-service.xml 这个配置文件在我其他模块,该模块通过它又引入了一些其他 xml 配置。
JvmConfiger.java
package com.znf4.app;import java.net.*;import java.util.ArrayList;import java.util.Enumeration;import java.util.ResourceBundle;/** * Created by agui on 15/11/2. */public class JvmConfiger { public final static ResourceBundle RESOURCE = ResourceBundle.getBundle("application"); public static String getJvmConfig() { StringBuilder buffer = new StringBuilder(); append(buffer, RESOURCE, "jvm.mem"); append(buffer, RESOURCE, "jvm.log"); append(buffer, RESOURCE, "jvm.gc"); append(buffer, RESOURCE, "jvm.others"); append(buffer, RESOURCE, "jvm.args"); return buffer.toString(); } public static String getRun() { StringBuilder buffer = new StringBuilder(); buffer.append("nohup java "); buffer.append(String.format("`java -jar %s -jvm`",getPackageName())); buffer.append(" -jar "); buffer.append(getPackageName()); buffer.append(" > "); buffer.append("./console.log"); buffer.append(" 2>&1 &"); return buffer.toString(); } private static String getPackageName(){ return getAppConfig("project.name") + "." + getAppConfig("project.package"); } private static StringBuilder append(StringBuilder buffer, ResourceBundle resource, String key) { if (resource.containsKey(key)) { String value = resource.getString(key); if (value.contains("hostname=%s")) { value = String.format(value, getLocalAddress()); } return buffer.append(" " + value); } return buffer; } public static String getAppConfig(String key) { if (RESOURCE.containsKey(key)) { return RESOURCE.getString(key); } return null; } public static String getLocalAddress() { try { // Traversal Network interface to get the first non-loopback and non-private address Enumeration<NetworkInterface> enumeration = NetworkInterface.getNetworkInterfaces(); ArrayList<String> ipv4Result = new ArrayList<String>(); ArrayList<String> ipv6Result = new ArrayList<String>(); while (enumeration.hasMoreElements()) { final NetworkInterface networkInterface = enumeration.nextElement(); final Enumeration<InetAddress> en = networkInterface.getInetAddresses(); while (en.hasMoreElements()) { final InetAddress address = en.nextElement(); if (!address.isLoopbackAddress()) { if (address instanceof Inet6Address) { ipv6Result.add(normalizeHostAddress(address)); } else { ipv4Result.add(normalizeHostAddress(address)); } } } } // prefer ipv4 if (!ipv4Result.isEmpty()) { for (String ip : ipv4Result) { if (ip.startsWith("127.0") || ip.startsWith("192.168")) { continue; } return ip; } return ipv4Result.get(ipv4Result.size() - 1); } else if (!ipv6Result.isEmpty()) { return ipv6Result.get(0); } //If failed to find,fall back to localhost final InetAddress localHost = InetAddress.getLocalHost(); return normalizeHostAddress(localHost); } catch (SocketException e) { e.printStackTrace(); } catch (UnknownHostException e) { e.printStackTrace(); } return null; } public static String normalizeHostAddress(final InetAddress localHost) { if (localHost instanceof Inet6Address) { return "[" + localHost.getHostAddress() + "]"; } else { return localHost.getHostAddress(); } }}
继续引入Boot相关配置:
值得说的是 : 我把 znf4-common-config 中的jdbc.properties 中的 相关数据库配置远方不动的粘贴到了 boot 约定下的 application.properties
# sys configisDebug = trueapplication.message=znf4# 容器端口server.port=9999server.sessionTimeout= 3600server.contextPath=# tomcat config#url = http://localhost:9999/merchant/trade/free?id=11111111111111&type=free server.tomcat.compression=2048 # is compression enabled (off, on, or an integer content length limit)server.tomcat.compressable-mime-types=text/html,text/xml,text/plain,text/javascript,application/json,application/xmltomcat.accessLogEnabled= falsetomcat.protocolHeader=x-forwarded-prototomcat.remoteIpHeader=x-forwarded-fortomcat.basedir=tomcat.backgroundProcessorDelay=30 # secsserver.tomcat.max-threads = 500server.tomcat.uri-encoding = UTF-8###############################JDBC Setting###############################commonjdbc.validationQuery=select current_timestamp()jdbc.maxWait=60000##webweb.jdbc.driver=com.mysql.jdbc.Driverweb.jdbc.url=jdbc:mysql://123.26.6.2:3306/znf4?useUnicode=true&characterEncoding=UTF-8web.jdbc.username=rootweb.jdbc.password=T5U+tbyGJ6mm6UVSZfo9qEDcmZdAx3Pk81KsYtpdhiN08WuPLwrVilyEK0yezprsCz25ghR2L11QJKQP/2+41w==web.jdbc.initialSize=2web.jdbc.minIdle=2web.jdbc.maxActive=10spring.http.encoding.charset=UTF-8spring.http.encoding.enabled=truespring.http.encoding.force=true#classpath中存在velocity 忽略spring-boot的VelocityAutoConfigurationspring.velocity.enabled=falsespring.velocity.checkTemplateLocation=true
最好以上我们就完成了 原生Springmvc SM 下的项目加进boot 相关组件,尝试启动一下 :
没有任何 问题 , 解释一下我为什么要引入boot :
之前设计这个项目就是根据需求直接设计成分布式的项目,各种中间件都是通过spring -xml 文件配置的,因为一些三方接口不是很给力,之前上网上找了一个 通过redis 对接口限流的方法,感觉还是有很大局限性,维护那不容易。之前在学Springcloud 中全家桶组件时,也是基于boot , 这把要用hystrix组件, 就想到项目通过boot 启动 , 用boot 去 引入 sringcloud 中的其他组件(现有的东西不动),后续也可以上 微服务(虽然对dubbo 情有独钟,还是选择了cloud)。 下面会展示 boot 引入 hystrix ,并且进行测试的相关代码和图片说明。
jar准备:
我是在partent 中下载jar, core 模块去继承, server 模块去引入core , merchant模块作为入口,去引用 core , server 。
直白说:引入下面这个jar 就行了,上面说的那些都跟我设计的maven多模块有关,跟jar没直接关系。
<!-- 限流,熔断,降级 --><dependency> <groupId>com.netflix.hystrix</groupId> <artifactId>hystrix-core</artifactId> <version>1.5.13</version> </dependency>
启动一个测试服务,模拟三方服务 :
我们在我们的项目中加入测试代码 :
我们通过jemter 工具模拟并发,访问merchant 模块,merchant逻辑中有通过http 访问上面 9001 服务的代码,我们的目的就是通过 boot 去配置 hystrix 实现, 限流,降级,熔断。
我们先压测一下我们测试服务器 9001 ,直接 50 个线程 10次循环,共500次请求 :
结果 :
蹦了, 那么基本上可以肯定,我们通过merchant 去访问测试服务器,500次去访问也是扛不住的,我们不可能因为一个三方服务性能不好,出先了异常,导致我们的系统也用不了,那么我对他进行处理 :
SmsSendCommand.java 类
package com.znf4.test;import java.io.InputStream;import java.net.URL;import org.apache.tomcat.util.http.fileupload.IOUtils;import com.netflix.hystrix.HystrixCommand;import com.netflix.hystrix.HystrixCommandGroupKey;public class SmsSendCommand extends HystrixCommand<String>{ protected SmsSendCommand() { super(HystrixCommandGroupKey.Factory.asKey("smsGroup")); } @Override protected String run() throws Exception { URL url = new URL("http://localhost:9001/send/agui"); byte[] result = new byte[3]; InputStream input = url.openStream(); IOUtils.readFully(input, result); // 远程服务不稳定或网络抖动时暂时关闭 return new String(result); } @Override protected String getFallback() { // 降级 策略 再次查询, 查询备用接口 缓存 mock值 // 根据业务自定义 return "降级"; }}
测试 :
@RequestMapping("test_hystrix")public String test_hystrix() throws IOException{ return new SmsSendCommand().execute();}
config.properties 文件 跟 apllication.properties 文件放在同一个目录下。 配置如下
注意 : hystrix.threadpool.smsGroup.coreSize=20 中的 smsGroup 为 上述 代码中的key : HystrixCommandGroupKey.Factory.asKey(“smsGroup”) 。
# Hystrix 默认加载的配置文件 - 限流、 熔断示例# 超时时间hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=1000000# 信号量 netflix分布式配置中心 archaius# 线程池大小hystrix.threadpool.default.coreSize=10hystrix.threadpool.default.maxQueueSize=-1hystrix.threadpool.default.queueSizeRejectionThreshold=5# 限流策略hystrix.threadpool.smsGroup.coreSize=20hystrix.threadpool.smsGroup.maxQueueSize=1000# 超过就报错hystrix.threadpool.smsGroup.queueSizeRejectionThreshold=800
结果 :
解释 : 我们 通过jmeter 直接 80 * 10 次访问我们限流后的 接口, 可以发现服务器 并没有被压垮。 证明我门的配置好用。 继续我们补充一下降级,熔断。
降级 :
降级我们要么通过 SmsSendCommand 类中的 :
进行降级逻辑,可以 在此查询,查询别用接口,缓存mock 值等。
说明一下: 我们的限流 或者熔断 报错之后都会进行降级 。
@Override protected String getFallback() { // 降级 策略 再次查询, 查询备用接口 缓存 mock值 // 根据业务自定义 return "降级"; }
熔断 :
继续追加到config.properties 文件 , 都有注释,就不解释了。
# 熔断策略# 启用/禁用熔断机制hystrix.command.default.circuitBreaker.enabled=true# 强制开启 禁止访问相关接口hystrix.command.default.circuitBreaker.forceOpen=false# 强制关闭 hystrix.command.default.circuitBreaker.forceClosed=false# 在一定前提条件下,暂停接口访问# 10秒统计一次hystrix.command.default.metrics.rollingStats.timeInMilliseconds=10000# 令牌桶数量# hystrix.command.default.metrics.rollingStats.numBuckets=10# 前提条件,时间内发起一定数量的请求。 也就是10秒钟内至少请求5次,熔断器才发挥起作用hystrix.command.default.circuitBreaker.requestVolumeThreshold=5# 错误百分比。达到或超过这个百分比,启用熔断 不会访问接口hystrix.command.default.circuitBreaker.errorThresholdPercentage=50# 10秒后,半打开状态hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds=10000
测试 :
完善测试服务器代码,加入随机数,对2取余,满足就响应一个错误,来触发熔断 ,。
重启测试服务9001 , 继续访问 80 * 10 。看结果 :
上面可以看到,我们 800次请求,:
错误百分比。达到或超过这个百分比,启用熔断 不会访问接口
hystrix.command.default.circuitBreaker.errorThresholdPercentage=50 时候我们这个接口就不会在继续接收请求,以进行了熔断。
以上,我们我们完成了 boot 的引入,顺便 我用boot 引入了hystrix 进行了 限流,熔断,降级的演示。
实例代码 : 链接: https://pan.baidu.com/s/1o8n6pw2 密码: dnsf
- SpringMvc 项目转 SringBoot
- sringboot项目在tomcat上的部署
- springmvc项目:springmvc配置文件
- springMVC项目
- Eclipse maven构建springmvc项目(转)
- springMVC项目 springMVC jar包
- SpringBoot项目转传统SpringMVC war项目的部署问题
- springmvc项目注意事项
- Maven构建SpringMVC项目
- Rest应用于SpringMVC项目
- Maven新建SpringMVC项目
- Springmvc配置(maven项目)
- springmvc web项目搭建
- SpringMVC项目接入Springfox
- SpringMVC简单项目配置
- maven创建springmvc项目
- 搭建SpringMVC项目
- springMvc框架系统项目
- mysql基础语句
- C# 创建以及安装服务
- 欢迎关注个人微信公众账号~
- hdu 2795
- 15算法课程 202. Happy Number
- SpringMvc 项目转 SringBoot
- Python股市数据分析教程——学会它,或可以实现半“智能”炒股 (Part 1)
- KMP算法的详解
- Global average Pooling
- 一图掌握bash shell编程
- MQTT协议_主题
- QPushButton 的样式表代码总结
- python模拟登录csdn并获取首页文章写入MySQL中(二)
- Hadoop运维记录 | Zeppelin启用https和Hack内核的过程