前面讲到了不少基础部分,都是围绕Java和数据库相关的,这些知识可以说是开发者都要知道的固有知识,但后面我要说的框架和中间件等就因人而异了,因为不同公司所使用的技术是不同的,可能我所说的内容并不在其他一些公司中见过,或者并不是最新的,这里还望仁者见仁,智者见智,只总结一下自己的收获。
目前我个人接触最多的是Spring、Spring Boot、Spring MVC、Spring Cloud当然分布式框架主流的还接触了Dubbo,后面说吧,持续关注一波~~
提到Spring就不得不说IOC控制反转DI依赖注入和AOP面向切面机制。
- Spring IOC:控制bean的创建、管理、整个生命周期,反转这个权利给spring容器。
- IOC初始化流程:xml文件或注解、读取为Resource、再解析为Beandefinition、最后注册Beanfactory接口。
- DI:依赖程序外部的资源和内部对象所需的资源,注入配置文件到内部对象。
- @AutoWired注入:优势简洁、 缺点用Field 注入构建对象实例时,若对象为空,则会空指针构造注入。
- Setter注入:优势是随用随创建、缺点是不能初始时创建。
- 接口注入:即重写接口的方法,若接口多个实现类,则@Primar、@Qualifier 指定。
- Bean生命周期包括:Bean实例化、Bean属性赋值、Bean初始化、Bean的使用、Bean的销毁。
- Bean实例化:初始化BeanFactory并加载Bean定义 (XML、注解读取解析并包装为Beandefinition) 的过程。
- 依赖注入:Bean属性赋值过程:检查单例缓存池Map(ConcurrentHashMap)是否有实例,有则缓存池或对应FactoryBean()获取,没有则递归向上寻找父级工厂获取bean实例,还没有则创建bean实例获取所有依赖bean实例(没有则实例化),调用createBean方法完成自身创建并返回自身bean实例。
- 处理接口:Bean初始化:Beanfactory工厂接口、前置处理接口BeanPostProcessor、初始化接口InitializingBean、后置处理接口BeanPostProcessor。
- Bean使用:bean 是由 Spring IoC 容器实例化、组装和管理的对象。
- Bean销毁:销毁前若实现了DisposableBean 接口,可执行destroy销毁前置方法。
- Bean销毁:若配置文件中含destroy-method属性,可执行指定方法后再进行销毁。
Spring AOP含:代理增强、通知、横切多业务处理 (拦截) ,底层都是动态代理。
- 静态代理的缺点:一个静态代理类只能代理一个委托类,即程序员编写接口与实现类实现代理效果;重复的代码逻辑不可重复利用,每个静态代理执行相同逻辑也要与委托类一对一。
- 动态代理:代理类和目标类的类型要兼容,实现接口一致,只有public方法才能进行CGLib代理。Spring中@Aspectj需要支持,启用后Spring为目标Bean自动生成代理,拦截/调用通知。如果类没实现InvocationHandler接口即未使用JDK动态代理,则AOP机制会用CGLib动态代理。
- CGLib通过类的继承完成,代理方法和类不能是final,static,private修饰的,CGLib拦截用FastClass机制中getindex和invoke根据方法名+描述符=建立方法的索引。
- 因在jdk6后对JDK动态代理进行了优化,在调用次数少时JDK效率高于cglib代理,只有在大量调用的时候cglib的效率高,但在1.8后JDK的效率都高于cglib。
Spring事务属性:
- Spring事务四大隔离级别:读未提交、读已提交、可重复读、可串行化。
- Spring事务七大传播行为:
- Propagation_required:外层无事务则内层新建事务,外层有事务则合并内层为1个事务。
- Propagation_require_new:外层无事务则内层新建事务,外层有事务则挂起后内层另新建事务。
- Propagation_supports:外层无事务则内层建立非事务执行,外层有事务则内层事务性无影响。
- Propagation_supported:外层无事务则内层建立非事务执行,外层有事务则挂起内层建立非事务执行
- Propagation_mandatory:外层无事务则调用内层时抛异常,外层有事务则调用外层时内层加入事务,调用内层时抛异常。
- Propagation_never:外层无事务则内层建立非事务执行,外层有事务则抛出异常。
- Propagation_nested:外层无事务则内层新建事务,外有事务则嵌套事务形成父子关系,即调外层时内层有事务,调内层时不受外层事务性影响。
- Spring开启事务并设置了传播机制则覆盖Mysql已有的事务隔离级别以及传播机制,若Mysql不支持该隔离级别或传播机制,则Spring的事务就也不会生效。
- Spring的设计模式:单例模式、代理模式、模板、工厂、观察者、包装器、适配器。
- 其中Spring的单例Bean是线程不安全的,可以定义ThreadLocal成员变量保存数据,解决线程安全问题。
- Spring事务底层:AOP实现,上面一个切面,关联的切点内有1个TransactionAttributeSource 对象会用解析器解析@Transactional注解,将这个事务定义的属性封装成一个事务定义对象AOP 拦截在事务拦截器中,先用平台事务管理器创建TransactionStatus 事务对象,里面包含了Transaction事务,关闭autocommit 自动提交,方法的执行处于一个事务中。事务的相关属性会保存在许多ThreadLocal中,交由1个事务同步管理器进行管理,则Spring 事务仅支持在一个线程中完成, 解决单列Bean线程安全问题。
- @Transactional业务方法能否执行commit/rollback:Spring默认取决于方法是否抛出runtimeException异常。若方法中有try{}catch(Exception e){}处理,则try代码块就脱离了事务的管理。若为try{..} catch(Exception e){ throw new RuntimeException ("...")}抛出运行时异常,则可以有事务。
- 事务方法必须是public修饰符,否则@Transactional注解不会生效,但是加注解也不会报错,只是没用。
- this.本方法的调用方式,被调用方法上注解是不生效的,因为无法在此进行切面增强。
- @Transactional属性参数:7种传播行为参数、4种隔离级别参数、timeout超时属性(执行超时后则回滚)、readOnly只读属性(默认关闭)、rollbackFor属性(指定哪种异常回滚,可指多种)、noRollbackFor属性(指定哪种异常抛出,可指多种)。
Spring循环依赖:
- 首先并不是只有setter注入才解决循环依赖,三级缓存也不是为了提高效率。
- 循环依赖的bean是单例的且不为全构造注入,多例bean由用户控制自行解决。
- 例如:A中注入B用setter,在B中注入A可为setter或构造注入,可解决循环依赖。
- 没有AOP流程时:创建A、实例化A对象、通过A对象创建工厂并放至三级缓存中、属性注入调用getBean(B)、创建并实例化并属性注入getBean(A)、缓存中获取到A对象(先搜索一二级缓存,都没有实例bean时,在三级缓存中获取到A对象工厂,工厂获取A对象放至二级,移除三级缓存中的工厂)、B完成属性注入并完成初始化bean、则A完成属性注入完成初始化bean。清除二级缓存并将A初始化后的bean存至一级缓存,以便后在一级缓存中即可拿到A初始化后的bean。
- 有AOP流程时:在(三级缓存中获取到A对象工厂,工厂获取到A的代理对象放至二级,移除三级中工厂)即在有AOP时,将获取的A对象的AOP代理对象存至二级缓存中,而非A对象。后续流程一致。
Spring Boot注解:
- 核心注解@SpringBootApplication,组合包含3个注解: (在类上添加)。
- @SpringBootConfiguration:组合了 @Configuration 注解,配置文件功能。
- @EnableAutoConfiguration:默认自动配置功能,也可关闭某个自动配置。
- @EnableAutoConfiguration 根据应用所声明的依赖对Spring框架自动配置。
- @ComponentScan组件扫描,扫@Component @Controller @Service等注解的类,将类注册为bean,可以定义要扫描的路径。
- @Configuration 指出该类是 Bean 配置的信息源,加在类上。
- @Controller:表示此类可接收Http请求,可通过返回String跳转到jsp、html页面。方法上加@ResponseBody,也可返回String、Object、Json等实体对象。
- @RestController 标注控制层组件(如struts中action),包含@Controller注解和@ResponseBody注解。
- @ResponseBody将返回值写入HTTP response body,防止@RequestMapping将返回值解析为跳转。
- @RequestMapping 处理请求地址映射,在类上则为所有响应请求方法父路径,包含6属性:params: 指定request必须含某些指定参数值,方法才处理请求;method: 指定请求method类型,GET、POST、PUT、DELETE等;consumes: 指定提交类型Content-Type: application/json、text/html;headers: 指定request必须含某些指定header值,方法才处理;value: 选定请求实际地址,可选定 URI Template 模式;produces: 指定返回内容类型,仅request头中(Accept)类型 含此指定类型才返回。
- @RequestBody接收http请求的json数据,并将json转换为java对象。
- @RequestParam方法的参数前面,@RequestParam String a request.getParameter("a")
- @PathVariable 路径变量,参数与大括号里的名字要相同,占位符路径。
- @Component 泛指组件,当组件不好归类的时候,使用此注解进行标注。
- @Repository 用于标注数据访问组件,即DAO 组件(Dao层)。
- @Service 用于标注业务层组件。
- @Bean 在方法上,产生一个bean并交给spring管理,自定义能力强,使用较多。
- @AutoWired 类型注入方式,它可标注类属性、方法、构造函数,用Bean完成自动装配,默认按类型装配。加上(required=false)时,找不到 bean 时不会报错。
- @Qualifier多个同一类型Bean时,@Autowired需要@Qualifier("name")来指定。
- @Resource(name="name",type="type") 括号内没有内容则默认按名称装配。
- @interface声明,SpringBoot配自定义注解。
- @Transient避免序列化:在MyBatis对应数据库的实体类中,属性加@Transient,则不会匹配数据库该的字段,属性独立,构造或Set-设值/使用。
- @Modifying注解,数据库修改操作使用,与@Query一起声明可自定义SQL。
- @Async+@Transactional在方法上开启事务,原理即是ThreadLocal。
- SpringBoot内置Tomcat(内含线程池,初始75个空线程):Tomcat7为BIO(每次请求都创建新线程)、Tomcat8即以上为NIO(之前讲过)。
SpringMVC流程:(开发部分:Handler、视图view,即后端业务、前端界面)
MyBatis执行流程:
- 读取MyBatis配置文件:MyBatis的全局配置文件mybatis_config.xml,封装成对象
- 加载映射文件:即SQL映射(配置了数据库的SQL语句),在mybatis_config.xml加载
- 构造会话工厂获取SqlSessionFactory:用SqlSessionFactoryBuilder构建,应用作用域
- 创建会话对象SqlSession:会话工厂创建对象,包含执行SQL的方法,线程独占1份
- Executor执行器:负责SQL语句的生成和查询缓存的维护,根据参数动态生成SQL
- MappedStatement对象:对解析的SQL封装,1个MappedStatement代表1个SQL语句标签
- 输入参数映射:基础类型、Map、List、POJO等,过程类似JDBC预编译处理参数
- 输出结果映射:可封装成多种类型,封装结果集过程=JDBC封装结果集过程
- MyBatis拦截器:分页、插入或更新时间、数据权限、SQL监控日志,3种注入(xml、配置类、注解):顺序拦截4种对象:拦截执行器的方法、拦截Sql语法构建的处理、拦截参数的处理、拦截结果集的处理。
SpringCloud(服务调用时,Ribbon检查是否有缓存,Ribbon从Eureka定期刷新本地缓存):
- Zuul路由网关:唯一对外入口,实现路由(服务路径屏蔽)、过滤器(限流设置信号量并发量、线程池大小、缓冲区大小、降级阈值、灰度发布平滑迁移版本、权限控制登录成功或token存至session缓存每次请求携带并统一在网关校验)。
- Zuul的路由网关是对外层,而Ribbon和Feign也可用于内部的传输路由网关
- 服务引用:RestTemplate 或 Open Feign,声明式服务调用Feign= Ribbon+Hystrix
- 服务降级(关闭访问量低的服务,资源为高访问量的提供服务)、 服务熔断(隔断服务异常的访问)。当服务不可访问时先降级后熔断。
- 服务降级,消费端代码控制 (处理调用已关闭的提供者或异常)、 服务熔断,提供端代码控制 (处理调用服务异常)。
- Hystrix 熔断关键参数:滑动窗口大小(20)、熔断器开关间隔(5s)、错误率(50%)即每20 个请求,50%失败时,熔断器打开返回失败,5s后,重新检测,是否再熔断
- Ribbon对客户端请求进行负载后请求服务端,Nginx对服务端进行负载提供给客户端。
- Ribbon负载均衡算法:随机策略、轮询策略、重试策略、自定义策略。
- Eureka服务注册中心:为AP高可用性,有心跳机制30s每次,剔除列表中3次未回应的服务。Eureka集群节点平等,15分钟内85%的服务心跳失败视为网络不稳,则保护注册信息不过期(保护机制)。
- 服务已宕机仍访问则会触发Eureka剔除、 而对于在触发保护机制时可能访问已失效未剔除的服务,需要容错、熔断处理。
- 服务宕机,客户端需要1~3个⼼跳感知,而基于Netflix的客户端使⽤Hystrix熔断机制来降级服务调⽤,从而及时感知到服务已失效。
- Eureka全挂时:客端可能缓存了服务实例则仍可用、 无Eureka时直接Ribbon请求服务导⼊eureka-client-cat也可用。
- Eureka集群:其中一个服务崩溃,新的Eureka节点会获取崩溃节点的信息,期间可能无法调用URL。
- Bus:Bus配合Config实现自动配置更新,支持Kafka和RabbitMQ,MQ的订阅通知,指定通知用Git修改Config配置,Bus推送post链接后加指定服务。
- Nacos= Eureka + config + Bus,Nacos(简化集成他们)。
- 分布式服务治理:处理服务调用关系、故障监控与处理、降级熔断、服务发现和收益率、参数配置。
- 需要服务治理的场景:服务调用URL过多时,代码配置繁琐,依赖混乱,启动顺序不清,服务过多时,性能分析难度大,故障定位与排查难度大,需要监控,负载均衡分配节点时,压力过大则需单独部署集群。
知识笔记,部分知识点因篇幅原因还是不够细致全面,多多包涵,如文章内容存在错误还望多多指正,后续继续更新中........