前后端分离:
Vue+Spring boot
前端 -> 前端控制层、视图层 伪造后端数据,json就不需要后端项目依旧能够跑起来 后端 -> 后端控制层、服务层、数据访问层前后端通过API进行交互前后端分离模式相对独立、且松耦合产生的问题:
前后端集成,前端或者后端无法做到“及时协商,尽早解决”,最终导致问题集中爆发解决方案:
首先定义schema(计划的提纲 ),并实时跟踪最新的API,降低集成风险早些年用word计划文档前后端分离: 前段测试后端接口:postman后端提供接口,需要实时更新最新的消息和改动Swagger:
Swagger是一个规范和完整的框架,是一个可以根据你的代码,自动生成接口文档的一个工具,并且可以用作接口测试工具。
号称世界上最流行的API框架Restful Api 文档在线自动生成器 => API 文档 与API 定义同步更新直接运行,在线测试API支持多种语言 (如:Java,PHP等)官网:https://swagger.io/1.2SpringBoot集成
1.搭建项目,并测试,确保能运行
@Controller
public class HelloController {
@RequestMapping("/hello")
@ResponseBody
public String hello(){
return "hello";
}
}
2.项目中使用Swagger需要导入启动器:
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-boot-starterartifactId>
<version>3.0.0version>
dependency>
也可以导入两个jar包依赖:
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger2artifactId>
<version>3.0.0version>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger-uiartifactId>
<version>3.0.0version>
dependency>
3.编写配置类,运行访问:http://localhost:8080/swagger-ui/index.html
@Configuration
@EnableSwagger2//开启swagger
public class SwaggerConfig {
}
注意:
这里会报错解决方法----启动类添加注解@EnableWebMvc:
当使用@EnableWebMvc时,加载的是WebMvcConfigurationSupport中的配置项
当不使用@EnableWebMvc时,使用的是WebMvcAutoConfiguration引入的配置项
测试结果:
Swagger的实例Bean是Docket,所以通过配置Docket实例来配置Swaggger:
@Configuration
@EnableSwagger2//开启swagger
public class SwaggerConfig {
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo());
}
//配置swagger的信息
public ApiInfo apiInfo(){
//作者信息
Contact DEFAULT_CONTACT = new Contact("容辞", "https://mp.csdn.net/mp_blog/manage/article?spm=1010.2135.3001.5416", "3521945255@qq.com");
return new ApiInfo(
"容辞API",
"即使再小的帆也能远航",
"v1.0",
"https://mp.csdn.net/mp_blog/manage/article?spm=1010.2135.3001.5416",
DEFAULT_CONTACT,
"Apache 2.0",
"http://www.apache.org/licenses/LICENSE-2.0",
new ArrayList<>());
}
}
1.4配置扫描接口
构建Docket时通过select()方法配置怎么扫描接口
RequestHandlerSelectors配置要扫描接口的方式
basePackage():要扫描的包any():扫描所有,项目中的所有接口都会被扫描到none():不扫描接口withMethodAnnotation(GetMapping.class):通过方法上的注解扫描,只扫描get请求withMethodAnnotation(Controller.class):通过类上的注解扫描,只扫描有controller注解的类中的接口
测试结果:
apis:
paths:
通过 enable() 方法配置是否启用swagger,如果是false,swagger将不能在浏览器中访问了
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2)
.enable(false);
}
动态配置当项目处于test、dev(生产)环境时显示swagger,处于prod(发布)时不显示。
多配置文件:
spring.profiles.active=dev
@Bean
public Docket docket(Environment environment){
//设置要显示的swagger环境
Profiles profiles = Profiles.of("dev");
//通过环境监听变量,判断是否处于自己设置的环境之中
boolean flag = environment.acceptsProfiles(profiles);
return new Docket(DocumentationType.SWAGGER_2)
.enable(flag);
}
测试:
1.6API文档分组
如果没有配置分组,默认是default;通过groupName()方法即可配置分组:
@Bean
public Docket docket1(){
return new Docket(DocumentationType.SWAGGER_2).groupName("A");
}
@Bean
public Docket docket2(){
return new Docket(DocumentationType.SWAGGER_2).groupName("B");
}
@Bean
public Docket docket3(){
return new Docket(DocumentationType.SWAGGER_2).groupName("C");
}
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2).groupName("容辞");
}
1.7扫描实体类
只要这个实体类在请求接口的返回值上,都能被扫描到swagger中:
@ApiModel("实体类")
public class User {
@ApiModelProperty("用户名")
public String userName;
@ApiModelProperty("密码")
public String userPwd;
}
@PostMapping("/u")
@ResponseBody
public User u(){
return new User();
}
为实体添加注释:
@ApiModel为类添加注释
@ApiModelProperty为类属性添加注释
测试结果:
扩展注解:
Swagger注解 | 简单说明 |
---|---|
@Api(tags = “模块说明”) | 作用在模块类上 |
@ApiOperation(“接口说明”) | 作用在接口方法上 |
@ApiModel(“POJO说明”) | 作用在模型类上:如VO、BO |
@ApiModelProperty(value = “属性说明”,hidden = true) | 作用在类方法和属性上,hidden设置为true可以隐藏该属性 |
@ApiParam(“参数说明”) | 作用在参数、方法和字段上,类似@ApiModelProperty |
@ApiOperation("hello控制类")
@GetMapping("/hello1")
@ResponseBody
public String hello1(@ApiParam("姓名") String name){
return "hello"+name;
}
测试结果:
扩展皮肤:
我们可以导入不同的包实现不同的皮肤定义
bootstrap-ui----访问 http://localhost:8080/doc.html
<dependency>
<groupId>com.github.xiaoymingroupId>
<artifactId>swagger-bootstrap-uiartifactId>
<version>1.9.6version>
dependency>
Layui-ui----访问 http://localhost:8080/docs.html
<dependency>
<groupId>com.github.caspar-chengroupId>
<artifactId>swagger-ui-layerartifactId>
<version>1.1.3version>
dependency>
knife4j----访问http://localhost:8080/doc.html
<dependency>
<groupId>com.github.xiaoymingroupId>
<artifactId>knife4j-spring-boot-starterartifactId>
<version>3.0.3version>
dependency>
总结:
我们可以通过swagger给一些比较难理解的属性或者接口增加注释信息接口文档实时更新可以在线测试正是大部的时候一定要关闭swagger,出于安全考虑也是节省运行内存
我们在网站上发送邮件,后台会去发送邮件,此时前台会造成响应不动,直到邮件发送完毕,响应才会成功,所以我们一般会采用多线程的方式去处理这些任务。
1.AsyncService类
@Service
public class AsyncService {
public void hello(){
try {
Thread.sleep(3000);//等3秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("业务进行中");
}
}
2.AsyncController类
@RestController
public class AsyncController {
@Autowired
AsyncService asyncService;
@RequestMapping("/hello")
public String hello(){
asyncService.hello();
return "success";
}
}
我们如果想让用户直接得到消息,就在后台使用多线程的方式进行处理即可,但是每次都需要自己手动去编写多线程的实现的话,太麻烦了,我们只需要用一个简单的办法,在我们的方法上加一个简单的注解即可:
@EnableAsync—启动类上@Async-------------方法上
项目开发中经常需要执行一些定时任务,比如需要在每天凌晨的时候,分析一次前一天的日志信息,Spring为我们提供了异步执行任务调度的方式,提供了两个接口:
TaskScheduler接口 任务调度者TaskExecutor接口 任务执行者两个注解:
@EnableScheduling–用在启动类上@Scheduled–用在方法上,定时任务在什么时候执行@Service
public class ScheduledService {
//在一个特定的时间去执行这个方法
//每天的晚上18:14:30都会执行
@Scheduled(cron = "30 14 20 * * *")
public void hello(){
System.out.println("hello你被执行了");
}
}
2.2.2cron
cron计划任务,是任务在约定的时间执行已经计划好的工作,这是表面的意思。在Linux中,我们经常用到 cron 服务器来完成这项工作。
cron的格式:S M H D m d
S:秒(0-59)
M: 分钟(0-59)
H:小时(0-23)
D:日(1-31)
m: 月(1-12)
d: 星期(1~7,1为星期天)
每个符号的意义:
* 表示所有值
? 表示未说明的值,即不关心它为何值
- 表示一个指定的范围
, 表示附加一个可能值
/ 符号前表示开始时间,符号后表示每次递增的值;
L last
# 用来指定这个月的第几个周几
一些cron表达式案例:
*/5 * * * * ? 每隔5秒执行一次
0 */1 * * * ? 每隔1分钟执行一次
0 0 5-15 * * ? 每天5-15点整点触发
0 0-5 14 * * ? 在每天下午2点到下午2:05期间的每1分钟触发
0 0/5 14 * * ? 在每天下午2点到下午2:55期间的每5分钟触发
0 0/5 14,18 * * ? 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
0 0/30 9-17 * * ? 朝九晚五工作时间内每半小时
0 0 10,14,16 * * ? 每天上午10点,下午2点,4点
0 10,44 14 ? 3 WED 每年三月的星期三的下午2:10和2:44触发
0 0 23 L * ? 每月最后一天23点执行一次
0 15 10 ? * 6L 每月的最后一个星期五上午10:15触发
0 15 10 * * ? 2005 2005年的每天上午10:15触发
0 15 10 ? * 6#3 每月的第三个星期五上午10:15触发
2.3邮件任务
邮件发送需要引入spring-boot-start-mail
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-mailartifactId>
dependency>
SpringBoot 自动配置MailSenderAutoConfiguration(源码)
定义MailProperties内容,配置在application.properties中
spring.mail.host=smtp.qq.com
spring.mail.password=kdxhvcsofkuycjef
spring.mail.username=3521945255@qq.com
#开启加密验证
spring.mail.properties.mail.smtp.ssl.enable=true
自动装配JavaMailSenderImpl
@Autowired
JavaMailSenderImpl javaMailSender;
//简单邮件
@Test
void contextLoads() {
SimpleMailMessage mailMessage = new SimpleMailMessage();
mailMessage.setSubject("springboot邮件发送");
mailMessage.setText("邮件任务测试");
mailMessage.setTo("3521945255@qq.com");
mailMessage.setFrom("3521945255@qq.com");
javaMailSender.send(mailMessage);
}
//复杂邮件
@Test
void contextLoads1() throws MessagingException {
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
//组装
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true);
helper.setSubject("springboot复杂邮件");
helper.setText("内容",true);
helper.addAttachment("1.jpg",new File("D:\壁纸\wallhaven-nz67rg.jpg"));
helper.setTo("3521945255@qq.com");
helper.setFrom("3521945255@qq.com");
javaMailSender.send(mimeMessage);
}
分布式系统是 若干独立计算机的集合 ,这些计算机对于用户来说就像单个相关系统。
分布式系统是由一组通过网络进行通信、为了完成共同的任务而协调工作的计算机节点组成的系统。分布式系统的出现是为了用廉价的、普通的机器完成单个计算机无法完成的计算、存储任务。其目的是利用更多的机器,处理更多的数据。
分布式系统(distributed system)是建立在网络之上的软件系统。
首先需要明确的是,只有当单个节点的处理能力无法满足日益增长的计算、存储任务的时候,且硬件的提升(加内存、加磁盘、使用更好的CPU)高昂到得不偿失的时候,应用程序也不能进一步优化的时候,我们才需要考虑分布式系统。因为,分布式系统要解决的问题本身就是和单机系统一样的,而由于分布式系统多节点、通过网络通信的拓扑结构(网络可能会不可靠–崩掉),会引入很多单机系统没有的问题,为了解决这些问题又会引入更多的机制、协议,带来更多的问题。
3.2Dubbo文档
随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,急需一个 治理系统 确保架构有条不紊的演进。
1.单一应用架构:
适用于小型网站,将所有功能都部署到一个功能里,简单易用,以减少部署节点和成本。此时,用于简化增删改查工作量的数据访问框架(ORM)是关键。
缺点:性能扩展比较难,协同开发问题,不利于升级维护。
2.垂直应用架构:
当访问量逐渐增大,通过切分业务来实现各个模块独立部署,以提升效率,性能扩展也更方便。此时,用于加速前端页面开发的Web框架(MVC)是关键。
缺点:公用模块无法重复利用,开发性的浪费。
3.分布式服务架构:
当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心。此时,用于提高业务复用及整合的分布式服务框架(RPC)是关键。
4.流动计算架构:
当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心,提高资源利用率。此时,用于提高机器利用率的资源调度和治理中心(SOA)[ Service Oriented Architecture]是关键。
RPC(Remote Procedure Call)是指 远程过程调用 ,是一种进程间通信方式(类似HTTP),他是一种技术的思想,而不是规范。它允许程序调用另一台机器上的过程或函数,而不用程序员显式编码这个远程调用的细节。即程序员无论是调用本地的还是远程的函数,本质上编写的调用代码基本相同。
也就是说两台服务器A,B,一个应用部署在A服务器上,想要调用B服务器上应用提供的函数/方法,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义和传达调用的数据。
RPC基本原理:RPC两个核心模块:通讯,序列化。(序列化:数据传输需要转换)
推荐阅读文章:https://www.jianshu.com/p/2accc2840a1b
Apache Dubbo 是一款高性能、轻量级的开源Java RPC框架(Dubbo用来实现RPC),它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。
dubbo官网 :https://dubbo.apache.org/zh/index.html
dubbo文档(进入更快):https://dubbo.gitbooks.io/dubbo-user-book/content/preface/background.html
dubbo架构:
服务提供者(Provider):暴露服务的服务提供方,服务提供者在启动时,向注册中心注册自己提供的服务。
服务消费者(Consumer):调用远程服务的服务消费方,服务消费者在启动时,向注册中心订阅自己所需的服务,服务消费者从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
注册中心(Registry):注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长链接推送变更数据给消费者。
监控中心(Monitor):服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
zookeeper下载地址:http://archive.apache.org/dist/zookeeper/
配置:
运行/bin/zkServer.cmd ,初次运行可能遇到问题闪退 !解决方案:编辑zkServer.cmd文件末尾添加pause 。这样运行出错就不会退出,会提示错误信息,方便找到原因。
将 conf 目录下的 zoo_sample.cfg 文件,复制一份,重命名为 zoo.cfg
在安装目录下面新建一个空的 data 文件夹和 log 文件夹
修改 zoo.cfg 配置文件,将 dataDir=/tmp/zookeeper 修改成 zookeeper 安装目录所在的 data 文件夹,再添加一条添加数据日志的配置
双击 zkCli.cmd 启动程序(zkServer.cmd也是启动状态)
测试:
扩展:ZooKeeper audit is disabled:
zookeeper新版本启动的过程中,zookeeper新增的审核日志是默认关闭,所以控制台输出ZooKeeper audit is disabled,标准的修改方式应该是在zookeeper的配置文件zoo.cfg新增一行audit.enable=true
即可
4.3dubbo-admin安装
dubbo本身并不是一个服务软件,它其实就是一个jar包,能够帮你的java程序连接到zookeeper,并利用zookeeper消费、提供服务。
为了让用户更好的管理监控众多的dubbo服务,官方提供了一个可视化的监控程序dubbo-admin,不过这个监控即使不装也不影响使用。
1.下载dubbo-admin地址 :
https://github.com/apache/dubbo-admin/releases
https://github.com/apache/dubbo-admin
2.修改端口号D:\java文件\dubbo-admin-develop\dubbo-admin-server\src\main\resources
3.在项目目录下打包dubbo-admin:
mvn clean package -Dmaven.test.skip=true
第一次打包的过程有点慢,需要耐心等待,直到成功,出现BUILD SUCCESS!
4.执行目录D:\java文件\dubbo-admin-develop\dubbo-admin-server\target下的jar包
java -jar dubbo-admin-server-0.4.0.jar
此时zookeeper的服务zkServer.cmd一定要打开。
5.报错:
java.io.IOException: 远程主机强迫关闭了一个现有的连接。
at sun.nio.ch.SocketDispatcher.read0(Native Method)
at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:43)
at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:223)
at sun.nio.ch.IOUtil.read(IOUtil.java:192)
at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:380)
at org.apache.zookeeper.ClientCnxnSocketNIO.doIO(ClientCnxnSocketNIO.java:68)
at org.apache.zookeeper.ClientCnxnSocketNIO.doTransport(ClientCnxnSocketNIO.java:366)
at org.apache.zookeeper.ClientCnxn$SendThread.run(ClientCnxn.java:1145)
出现这个的原因是zookeeper客户端连接数太多,默认最大连接数是60
解决办法:修改zookeeper的配置文件zoo.cfg,添加参数:maxClientCnxns=200
6.测试:我们去访问一下 http://localhost:7001/ , 这时候我们需要输入登录账户和密码,我们都是默认的root、root,成功访问!
4.4SpringBoot + Dubbo + zookeeper
Dubbo 采用全 Spring 配置方式,透明化接入应用,对应用没有任何 API 侵入,只需用 Spring 加载 Dubbo 的配置即可,Dubbo 基于 Spring 的 Schema 扩展进行加载。
4.4.1provider-server
1.新建一个空项目,添加模块springboot,实现服务提供者:provider-server
public interface TicketService {
public String getTicket();
}
@org.apache.dubbo.config.annotation.Service//服务注册与发现,在项目启动的时候自动注入到注册中心
@Component//不用service的原因是dubbo也是service容易导错包
public class TicketServiceImpl implements TicketService {
@Override
public String getTicket() {
return "啦啦啦啦啦啦";
}
}
2.导入依赖:
<dependency>
<groupId>org.apache.dubbogroupId>
<artifactId>dubbo-spring-boot-starterartifactId>
<version>2.7.3version>
dependency>
<dependency>
<groupId>com.github.sgroschupfgroupId>
<artifactId>zkclientartifactId>
<version>0.1version>
dependency>
<dependency>
<groupId>org.apache.curatorgroupId>
<artifactId>curator-frameworkartifactId>
<version>2.12.0version>
dependency>
<dependency>
<groupId>org.apache.curatorgroupId>
<artifactId>curator-recipesartifactId>
<version>2.12.0version>
dependency>
<dependency>
<groupId>org.apache.zookeepergroupId>
<artifactId>zookeeperartifactId>
<version>3.4.14version>
<exclusions>
<exclusion>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-log4j12artifactId>
exclusion>
exclusions>
dependency>
3.在springboot配置文件中配置dubbo相关属性
server.port=8081
#服务应用的名字
dubbo.application.name=provider-server
#注册中的地址
dubbo.registry.address=zookeeper://127.0.0.1:2181
#扫描指定包下的服务
dubbo.scan.base-packages=com.moli.service
dubbo.protocol.port=20881
4.运行provider,打开zookeeper的zkServer.cmd ,可以打开监控器dubbo-admin查看是否注入到注册中心(这两项工作最好在项目运行前解决)。
已经监控到数据:
5.如果无法显示元数据,就在服务提供端添加元数据配置类
import org.apache.dubbo.config.MetadataReportConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class DubboConfig {
@Bean
public MetadataReportConfig metadataReportConfig() {
MetadataReportConfig metadataReportConfig = new MetadataReportConfig();
metadataReportConfig.setAddress("zookeeper://127.0.0.1:2181");
return metadataReportConfig;
}
}
4.4.2consumer-server
1.添加模块,实现服务消费者:consumer-server,导入依赖同provider
2.UserService
@Service//注册到容器中
public class UserService {
//我们需要拿注册中心的服务
@Reference//dubbo远程引用:pom坐标;或者可以定义路径相同的接口名----生产者的TicketService
TicketService ticketService;
public void buyTicket(){
String ticket = ticketService.getTicket();
System.out.println("在注册中心拿到"+ticket);
}
}
本来正常步骤是需要将服务提供者的接口打包,然后用pom文件导入;我们这里使用简单的方式,直接将服务的接口拿过来,路径必须保证正确,即和服务提供者相同。
3.测试
@Autowired
UserService userService;
@Test
void contextLoads() {
userService.buyTicket();
}
4.4.3小结
步骤:
前提:zookeeper服务开启
提供者 导入依赖配置注册中心地址,服务者发现名,要扫描的包在想要被注册的服务上面加一个注解@Service 消费者 导入依赖配置注册中心地址,自己的服务名从远程注入服务加个注解@Reference扩展:
强制关闭端口:
#根据端口号查询这个端口号的PID
netstat -ano|findstr "端口号"
#根据查出来的pid 强制关闭这个端口号
taskkill -F -PID 查出的号
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)