微服务阶段
JavaSE:OOP
MySQL:持久化
HTML+CSS+JS+jQuery+框架:视图,框架不熟练,CSS不好
Javaweb:独立开发MVC三层架构的网站
SSM:框架 简化了开发流程 配置也开始较为复杂
SpringBoot
什么是SpringBoot
Spring Boot基于Spring 开发,Spirng Boot本身并不提供Spring框架的核心特性以及扩展功能,只是用于快速、敏捷地开发新一代基于Spring框架的应用程序。也就是说,它并不是用来替代Spring 的解决方案,而是和Spring框架紧密结合用于提升Spring 开发者体验的工具。SpringBoot以约定大于配置的核心思想,默认帮我们进行了很多设置,多数Spring Boot应用只需要很少的Spring 配置。同时它集成了大量常用的第三方库配置(例如Redis、MongoDB、Jpa、RabbitMQ、Quartz等等),Spring Boot应用中这些第三方库几乎可以零配置的开箱即用。
简单来说就是SpringBoot其实不是什么新的框架,它默认配置了很多框架的使用方式,就像maven整合了所有的jar包, spring boot整合了所有的框架。
Spring Boot的主要优点:
- 为所有Spring开发者更快的入门
- 开箱即用,提供各种默认配置来简化项目配置
- 内嵌式容器简化Web项目
- 没有冗余代码生成和XML配置的要求
微服务
什么是微服务
微服务是一种架构风格,它要求我们在开发一个应用的时候,这个应用必须构建成一系列小服务的组合;可以通过http的方式进行互通。要说微服务架构,先得说说过去我们的单体应用架构。
单体应用架构
所谓单体应用架构(all in one)是指,我们将一个应用的中的所有应用服务都封装在一个应用中。
无论是ERP、CRM或是其他什么系统,你都把数据库访问,web访问,等等各个功能放到一个war包内。
- 这样做的好处是,易于开发和测试;也十分方便部署;当需要扩展时,只需要将war复制多份,然后放到多个服务器上,再做个负载均衡就可以了。
- 单体应用架构的缺点是,哪怕我要修改一个非常小的地方,我都需要停掉整个服务,重新打包、部署这个应用war包。特别是对于一个大型应用,我们不可能吧所有内容都放在一个应用里面,我们如何维护、如何分工合作都是问题。
微服务架构
all in one的架构方式,我们把所有的功能单元放在一个应用里面。然后我们把整个应用部署到服务器上。如果负载能力不行,我们将整个应用进行水平复制,进行扩展,然后在负载均衡。
所谓微服务架构,就是打破之前all in one的架构方式,把每个功能元素独立出来。把独立出来的功能元素的动态组合,需要的功能元素才去拿来组合,需要多一些时可以整合多个功能元素。所以微服务架构是对功能元素进行复制,而没有对整个应用进行复制。
这样做的好处是:
1.节省了调用资源。
2.每个功能元素的服务都是一个可替换的、可独立升级的软件代码。
如何构建微服务
一个大型系统的微服务架构,就像一个复杂交织的神经网络,每一个神经元就是一个功能元素,它们各自完成自己的功能,然后通过http相互请求调用。比如一个电商系统,查缓存、连数据库、浏览页面、结账、支付等服务都是一个个独立的功能服务,都被微化了,它们作为一个个微服务共同构建了一个庞大的系统。如果修改其中的一个功能,只需要更新升级其中一个功能服务单元即可。
但是这种庞大的系统架构给部署和运维带来很大的难度。于是,spring为我们带来了构建大型分布式微服务的全套、全程产品:
- 构建一个个功能独立的微服务应用单元,可以使用springboot,可以帮我们快速构建一个应用;
- 大型分布式网络服务的调用,这部分由spring cloud来完成,实现分布式;
- 在分布式中间,进行流式数据计算、批处理,我们有spring cloud data flow。
- spring为我们想清楚了整个从开始构建应用到大型分布式应用全流程方案。
SpringBoot原理初探
自动配置
pom.xml
-
spring-boot-dependencies在父工程中存放核心依赖
- 在写或者引入一些SpringBoot依赖的时候,不需要指定版本,就因为这些版本仓库
启动器
-
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency>
- 启动器:说白了就是SpringBoot的启动场景
- 比如spring-boot-starter-web,它会自动导入web环境下的依赖
- spring boot会将所有的功能场景,变成一个个启动器
- 如果要使用什么功能,就只需要找到对应的启动器就可以
主程序
-
//@SpringBootApplication:标注这个类是一个spring boot的应用 启动类下的所有被导入 @SpringBootApplication public class HelloworldApplication { public static void main(String[] args) { //将spring boot启动起来 通过反射 SpringApplication.run(HelloworldApplication.class, args); } }
- 注解
-
@SpringBootConfiguration:springboot的配置 @Configuration:spring配置类 @Component:说明这也是一个spring的组件 @EnableAutoConfiguration:自动配置 @AutoConfigurationPackage:自动配置包 @Import({Registrar.class}):自动配置 包注册 @Import({AutoConfigurationImportSelector.class}):自动导入选择 //获取所有配置 List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes); //获取候选的配置 protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader()); Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct."); return configurations; } protected Class<?> getSpringFactoriesLoaderFactoryClass() { return EnableAutoConfiguration.class; } META-INF/spring.factories:自动配置的核心文件
-
流程图:自动配置原理分析 | ProcessOn免费在线作图,在线流程图,在线思维导图
结论:SpringBoot所有自动配置都是在启动的时候扫描并加载:spring.factories所有的自动配置类都在这里面,但是不一定生效,要判断条件是否成立,只要导入了对应的start,就有对应的启动器,有了启动器,自动装配就会生效,就配置成功。
- springboot在启动的时候,从类路径下/META-INF/ spring.factories获取指定的值
- 将这些自动配置的类导入容器,自动配置就会生效,帮我进行自动配置!
- 以前我们需要自动配置的东西,现在springboot帮我们做了!
- 整合javaEE,解决方案和自动配置的东西都在spring-boot-autoconfigure-2.2.0.RELEASE.jar这个包下
- 它会把所有需要导入的组件,以类名的方式返回,这些组件就会被添加到容器;
- 容器中也会存在非常多的xxAutoConfiguration的文件(@Bean),就是这些类给容器中导入了这个场景需要的所有组件;并自动配置,@Configuration , JavaConfig !
- 有了自动配置类,免去了我们手动编写配置文件的工作!
Run
//@SpringBootApplication:标注这个类是一个spring boot的应用
@SpringBootApplication
public class HelloworldApplication {
public static void main(String[] args) {
//将spring boot启动起来 通过反射
SpringApplication.run(HelloworldApplication.class, args);
}
}
最初以为就是运行了一个main方法,没想到却开启了一个服务;
SpringApplication.run分析
分析该方法主要分两部分,一部分是SpringApplication的实例化,二是run方法的执行;
SpringApplication
这个类主要做了以下四件事情
- 推断应用的类型是普通的项目还是Web项目
- 查找并加载所有可用初始化器,设置到initializers属性中
- 找出所有的应用程序监听器,设置到listeners属性中
- 推断并设置main方法的定义类,找到运行的主类
关于SpringBoot,谈谈你的理解:
- 自动装配
- run()
SpringBoot配置
配置文件
SpringBoot使用一个全局的配置文件,配置文件名称是固定的.
- application.properties
- 语法结构: key=value.
- application.yml
- 语法结构: key:空格value
配置文件的作用︰修改SpringBoot自动配置的默认值,因为SpringBoot在底层都给我们自动配置好了;
yml
可以直接给实体类赋值
自动配置原理
application.yml和spring.factories的联系
//表示这是一个配置类
@Configuration(proxyBeanMethods = false)
//自动配置属性: HttpProperties
@EnableConfigurationProperties
//Spring的底层注解: 根据不同的条件 来判断当前配置或者类是否生效
@ConditionalOnWebApplicatioin(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnClass(CharacterEncodingFilter.class)
@ConditionalOnProperty(prefix = "spring.http.encoding",value = "enabled",matchIfMissing = true)
精髓:
1) 、SpringBoot启动会加载大量的自动配置类
2)、我们看我们需要的功能有没有在SpringBoot默认写好的自动配置类当中;
3)、我们再来看这个自动配置类中到底配置了哪些组件;(只要我们要用的组件存在在其中,我们就不需要再手动配置了)
4)、给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们只需要在配置文件中指定这些属性的值即可;
xxxxAutoConfigurartion:自动配置类;给容器中添加组件
xxxxProperties:封装配置文件中相关属性;
SpringBoot Web开发
总结:
- 在springboot中,可以使用一下方式处理静态资源
- webjars localhost:8080/webjars/
- public static /** resources 直接映射到localhost:8080/
- 优先级: resources>static(默认)>public
首页如何定制
factory.ico
模板引擎
thymeleaf
结论:只要需要使用thymeleaf,只需要导入对应的依赖就可以了,将html放在templates目录下即可。
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
自定义视图解析器
//如果 你想diy一些定制化的功能 只要写这个组件 然后将它交给spring boot ,spring boot就会帮我们自动装配
//扩展 springmvc
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
// public interface ViewResolver 实现了视图解析器接口的类 我们就可以把它看做视图解析器
@Bean
public ViewResolver myViewResolver(){
return new MyViewResolver();
}
//自定义一个自己的视图解析器MyViewResolver
private class MyViewResolver implements ViewResolver {
@Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
return null;
}
}
}
在springboot中,有非常多的XXX Configuration帮助我们进行扩展配置,只要看见这个,就需要注意。
springboot - 员工管理练习项目
- 首页配置:
- 注意点,所有页面的静态资源都需要使用thymeleaf接管
- url:@{}
- 页面国际化:
- 我们需要配置i8n文件
- 如果需要在项目中进行按钮自动切换,需要自定义一个组件LovaleResolver
- 记得将自己写的组件配置到spring容器@Bean
- #{}
- 登录+拦截器
- 员工列表展示
- 提取公共页面
- th:fragment=" "
- th:replace=" "
- 如果要传递参数,可以直接使用()传参,接受判断即可
- 列表循环展示
- 提取公共页面
- 添加员工
- 按钮提交
- 跳转到添加页面
- 添加员工成功
- 返回首页
- CRUD
- 404页面
前端:
- 模板:别人写好的,我们拿来就用根据需要改
- 框架:组件:自己手动组合拼接 Bootstrap,Layui,semantic-ui
- 栅格系统
- 导航栏
- 侧边栏
- 表单
Data
Druid
@Configuration
public class DruidConfig {
@ConfigurationProperties(prefix = "spring.datasource")
@Bean
public DataSource druidDataSource(){
return new DruidDataSource();
}
//后台监控:web.xml 死代码 直接使用
//因为Springboot内置了servlet容器 所以没有web.xml
@Bean
public ServletRegistrationBean statViewServlet(){
ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid/**");
//后台需要有人登录 账号密码配置
HashMap<String, String> initParameters = new HashMap<>();
//增加配置
initParameters.put("loginUsername","admin"); // 登录key是固定的 loginUsername loginPassword
initParameters.put("loginPassword","123456");
//允许谁可以访问
initParameters.put("allow","localhost");
//禁止谁能访问
bean.setInitParameters(initParameters); //设置初始化参数
return bean;
}
//filter
public FilterRegistrationBean webStatFilter(){
FilterRegistrationBean<Filter> bean = new FilterRegistrationBean();
bean.setFilter(new WebStatFilter());
//可以过滤哪些请求
HashMap<String, String> initParameters = new HashMap<>();
//这些东西不进行统计
initParameters.put("exclusions","*.js,*.css,/druid/*");
return bean;
}
}
数据源配置
type: com.alibaba.druid.pool.DruidDataSource
#SpringBoot默认是不注入这些属性的 需要自己绑定
#druid 数据源专有配置
initialSize: 5
minIdle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuert: SELECT 1 FROM DUAL
testwhileIdle: false
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
#配置监控统计拦截的filters stat:监控统计 log4j: 日志记录 wall:防御sql注入
#如果允许时报错 java.lang.ClassNotFoundException: org.apache.log4j.Priority
#则导入log4j 依赖即可 Maven地址: https://mvnrepository.com/artifact/Log4j/log4j
filters: stat,wall,log4j
maxPoolPreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
Mybatis
整合包
mybatis-spring-boot-starter
- 导入包
- 配置文件
- mybatis配置
- 编写sql
- service层调用dao层
- controller调用service
SpringSecurity(安全)
在web开发中,安全第一位。过滤器,拦截器
非功能性需求
做网站:安全应该在什么时候考虑?设计之初
- 漏洞,隐私泄露
- 架构一旦确定,不好修改
Shiro
什么是Shiro?
- Apache Shiro是一个Java的安全(权限)框架。
- Shiro 可以非常容易的开发出足够好的应用,其不仅可以用在JavaSE环境,也可以用在JavaEE环境。
- Shiro可以完成,认证,授权,加密,会话管理,Web集成,缓存等。
有哪些功能?
- Authentication:身份认证、登录,验证用户是不是拥有相应的身份;
- Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限.即判断用户能否进行什么操作,如:验证某个用户是否拥有某个角色,或者细粒度的验证某个用户对某个资源是否具有某个权限!
- Session Manager:会话管理,即用户登录后就是第一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通的JavaSE环境,也可以是Web环境;
- Cryptography:加密,保护数据的安全性,如密码加密存储到数据库中,而不是明文存储;
- web Support: Web支持,可以非常容易的集成到Web环境;
- Caching: 缓存,比如用户登录后,其用户信息,拥有的角色、权限不必每次去查,这样可以提高效率·Concurrency: Shiro支持多线程应用的并发验证,即,如在一个线程中开启另一个线程,能把权限自动的传播过去
- Testing:提供测试支持;
- Run As:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问;
- Remember Me:记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了
Shiro架构(外部)
从外部看Shiro,即从应用程序角度来观察如何使用shiro完成工作:
- subject: 应用代码直接交互的对象是Subject,也就是说Shiro的对外API核心就是Subject,Subject代表了当前的用户,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是Subject,如网络爬虫,机器人等,与Subject的所有交互都会委托给SecurityManager; Subject其实是一个门面,SecurityManageer才是实际的执行者
- SecurityManager:安全管理器,即所有与安全有关的操作都会与SercurityManager交互,并且它管理着所有的Subject,可以看出它是Shiro的核心,它负责与Shiro的其他组件进行交互,它相当于SpringMVC的DispatcherServlet的角色
Swagger
学习目标:
- 了解Swagger的作用和概念
- 了解前后端分离
- 在SpringBoot中集成Swagger
Swagger简介
前后端分离
Vue + SpringBoot
后端时代:前端只用管理静态页面;HTML==》后端,模板引擎JSP
前后端分离时代:
- 后端:后端控制层,服务层,数据访问层
- 前端:前端控制层,视图层
- 伪造后端数据,json。已经存在了,不需要后端,前端依旧可以跑起来
- 前后端如何交互?API接口
- 前后端相对独立,松耦合;
- 前后端甚至可以部署在不同的服务器上;
产生一个问题:
- 前后端集成联调,前端人员和后端人员无法做到,及时协商,尽早解决,最终导致问题集中爆发;
解决方案:
- 首先制定schema,实时更新最新的API,降低集成风险;
- 早些年:制定Word文档;
- 前后端分离:
- 前端测试后端接口:postman
- 后端提供接口,需要实时更新最新的消息及改动
Swagger
- 号称世界最流行的API框架;
- RestFul API 文档在线自动生成工具 API文档与API定义同步更新
- 直接运行,可以在线测试API接口;
- 支持多种语言:Java,PHP...
官网:API Documentation & Design Tools for Teams | Swagger
在项目中使用Swagger需要Springfox;
- swagger2
- ui
SpringBoot集成Swagger
- 新建一个springboot-web项目
- 导入相关依赖
<dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>3.0.0</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>3.0.0</version> </dependency>
- 编写一个Hello工程
- 配置Swagger ==》 Config
@Configuration @EnableSwagger2 //开启Swagger2 public class SwaggerConfig { }
- 测试运行,http://localhost:8080/swagger-ui.html
配置Swagger
Swagger的bean实例Docket;
@Configuration
@EnableSwagger2 //开启Swagger2
public class SwaggerConfig {
//配置了Swagger的Docket的bean实例
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo());
}
//配置Swagger信息 ==》 apiInfo
private ApiInfo apiInfo(){
//作者信息
Contact contact = new Contact("hzx","http://localhost:8080","1113769147@qq.com");
return new ApiInfo(
"hzx的SwaggerAPI文档",
"即使再小的帆也能远航",
"1.0",
"http://localhost:8080",
contact,
"Apache 2.0",
"http://www.apache.org/licenses/LICENSE-2.0",
new ArrayList());
}
}
Swagger配置扫描接口
Docket.select()
//配置了Swagger的Docket的bean实例
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
//RequestHandlerSelectors配置要扫描接口的方式
//basePackage指定要扫描的包
//any() 扫描全部
//none 都不扫描
//withclassAnnotation 扫描类上的注解 参数是一个注解的反射对象
//withMethodAnnotation 扫描方法上的注解
.apis(RequestHandlerSelectors.basePackage("com.hzx.controller"))
//paths 过滤什么路径
.paths(PathSelectors.ant("/hzx/**"))
.build();
}
配置是否启动Swagger
docket里有enable 设置为false 不启动
我只希望我的Swagger在生产环境中使用,在发布的时候不适用?
- 判断是否是生产环境 flag = false
- 注入enable(flag)
@Bean
public Docket docket(Environment environment){
//设置要显示的Swagger环境
Profiles profiles = Profiles.of("dev","test");
//获取项目环境 通过environment.acceptsProfiles判断环境
boolean b = environment.acceptsProfiles(profiles);
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
//enable是否启动Swagger 如果为false 则Swagger不能在浏览器中访问
.enable(b)
.select()
//RequestHandlerSelectors配置要扫描接口的方式
//basePackage指定要扫描的包
//any() 扫描全部
//none 都不扫描
//withclassAnnotation 扫描类上的注解 参数是一个注解的反射对象
//withMethodAnnotation 扫描方法上的注解
.apis(RequestHandlerSelectors.basePackage("com.hzx.controller"))
//paths 过滤什么路径
// .paths(PathSelectors.ant("/hzx/**"))
.build();
}
配置API文档的分组
.groupName("hzx")
如何配置多个分组?多个Docket实例即可
@Bean
public Docket docket1(){
return new Docket(DocumentationType.SWAGGER_2).groupName("a1");
}
@Bean
public Docket docket2(){
return new Docket(DocumentationType.SWAGGER_2).groupName("a2");
}
@Bean
public Docket docket3(){
return new Docket(DocumentationType.SWAGGER_2).groupName("a3");
}
实体类配置
//@Api(注释)
@ApiModel("用户实体类")
public class User {
@ApiModelProperty("用户名")
public String username;
@ApiModelProperty("密码")
public String password;
}
任务
异步任务~@Async
定时任务~@Scheduled
邮件发送~
public void sendMail() throws MessagingException {
MimeMessage mimeMessage = mailSender.createMimeMessage();
MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true);
mimeMessageHelper.setSubject("你好啊");
mimeMessageHelper.setText("<p>1111</p>",true);
mimeMessageHelper.addAttachment("1.jpg",new File(""));
mimeMessageHelper.setTo("1113769147@qq.com");
mimeMessageHelper.setFrom("1113769147@qq.com");
mailSender.send(mimeMessage);
}
分布式Dubbo+Zookeeper
什么是分布式系统?
在《分布式系统原理与范型》一书中有如下定义:“分布式系统是若干独立计算机的集合,这些计算机对于用户来说就像单个相关系统”;
分布式系统是由一组通过网络进行通信、为了完成共同的任务而协调工作的计算机节点组成的系统。分布式系统的出现是为了用廉价的、普通的机器完成单个计算机无法完成的计算、存储任务。其目的是利用更多的机器,处理更多的数据。
分布式系统(distributed system)是建立在网络之上的软件系统。
首先需要明确的是,只有当单个节点的处理能力无法满足日益增长的计算、存储任务的时候,且硬件的提升(加内存、加磁盘、使用更好的CPU)高昂到得不偿失的时候,应用程序也不能进一步优化的时候,我们才需要考虑分布式系统。因为,分布式系统要解决的问题本身就是和单机系统一样的,而由于分布式系统多节点、通过网络通信的拓扑结构,会引入很多单机系统没有的问题,为了解决这些问题又会引入更多的机制、协议,带来更多的问题。。。
RPC
什么是RPC?
RPC【Remote Procedure Call】是指远程过程调用,是一种进程间通信方式,他是一种技术的思想,而不是规范。它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数,而不用程序员显式编码这个远程调用的细节。即程序员无论是调用本地的还是远程的函数,本质上编写的调用代码基本相同。
也就是说两台服务器A,B,一个应用部署在A服务器上,想要调用B服务器上应用提供的函数/方法,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义和传达调用的数据。为什么要用RPC呢?就是无法在一个进程内,甚至一个计算机内通过本地调用的方式完成的需求,比如不同的系统间的通讯,甚至不同的组织间的通讯,由于计算能力需要横向扩展,需要在多台机器组成的集群上部署应用。RPC就是要像调用本地的函数一样去调远程函数;
RPC两个核心模块:通信、序列化
Dubbo
什么是dubbo?
Apache Dubbo |'dxbeu|是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。
步骤:
前提:zookeeper服务已开启
- 提供者提供服务
- 导入依赖
- 配置注册中心的地址,以及服务发现名,和要扫描的包
- 在想要被注册的服务上面 增加一个注解@Service
- 消费者如何消费
- 导入依赖
- 配置注册中心的地址,配置自己的服务名
- 从远程注入服务@Reference
学习Java关注狂神说