Spring
特点
- 轻量级:完整的Spring框架可以在一个只有1M多的JAR文件里发布;非侵入式的(spring应用中的对象不依赖与spring的特定类);
- 控制反转(IOC):创建对象的控制权被反转到了Spring框架上;
- 面向切面(AOP):Spring支持面向切面工程,并且把应用业务逻辑和系统服务分开;
- 容器
- 框架集合
bean生命周期
- 根据配置情况调用 Bean 构造方法或工厂方法实例化 Bean;
- 利用依赖注入完成 Bean 中所有属性值的配置注入;
- 如果 Bean 实现了 BeanNameAware 接口,则 Spring 调用 Bean 的 setBeanName() 方法传入当前 Bean 的 id 值;
- 如果Bean实现了BeanFactoryAware接口,则Spring调用setBeanFactory()方法传入当前工厂实例的引用;
- 如果Bean实现了ApplicationContextAware接口,则Spring调用setApplicationContext()方法传入当前ApplicationContext实例的引用;
- 如果BeanPostProcessor和Bean关联,则Spring将调用该接口的预初始化方法postProcessBeforeInitialization方法对Bean进行加工操作,此处非常重要,Spring的AOP就是利用它实现的;
- 如果Bean实现了Initialization接口,则Spring将调用afterPropertiesSet方法;
- 如果在配置文件中通过init-method属性指定了初始化方法,则调用该初始化方法;
- 如果BeanPostProcessor和Bean关联,则Spring将调用该接口的初始化方法postProcessAfterInitialization方法。注:以上工作完成以后就可以应用这个Bean了,那这个Bean是一个Singleton的,所以一般情况下我们调用同一个id的Bean会是在内容地址相同的实例,当然在Spring配置文件中也可以配置非Singleton;
- 如果Bean实现了DisposableBean接口,则Spring会调用destroy()方法将Spring中的Bean销毁;如果在配置文件中通过destroy-method属性指定了Bean的销毁方法,则Spring将调用该方法对Bean进行销毁。
Spring中,两个id相同的bean会报错吗?
首先在同一XML配置文件中不能存在id相同的两个bean,否则spring容器在启动时会报错,因为id这个属性表示bean里边的唯一标志符号,所以spring在启动的时候回去验证id的唯一性,一旦发现重复会报错,这个错误发生在spring多xml文件进行解析转化为BeanDefinition的一个阶段。但是在两个不同的xml配置文件里边可以存在id相同的两个bean,IOC容器在加载Bean的时候默认会把多个相同id的bean进行覆盖。在spring3.x版本以后,这个问题就发生了变化,它提供了一个@Configuration注解去声明一个配置类,然后使用@Bean这个注解去实现bean的声明,如果我们在同一个配置类里边去声明多个相同名字的Bean,Spring IOC容器在解析的时候只会注册第一个声明Bean的一个实例。
IOC
通常,我们实例化一个对象时,都是使用类的构造方法来new一个对象,这个是由我们自己来控制的,而控制反转就把new对象的工作交给了Spring容器。
IOC的主要实现方式有两种:依赖查找和依赖注入。依赖注入是一种更可取的方式。
依赖查找和依赖入注入的区别
依赖查找:主要是容器为组件提供一个回调接口和上下文环境。这样一来,组件就必须自己使用容器提供的API来查找资源和协作对象,控制反转进体现在那些回调方法上,容器调用这些回调方法,从而应用代码获取到资源。
依赖注入:组件不做定位查询,只提供标准的java方法让容器去决定依赖关系。容器全权负责组件的装配,把符合依赖关系的对象通过JavaBean属性或构造方法传递给需要的对象。
依赖注入方式
- 注解注入方式;
- Set注入方式
- 构造器注入方式
- 静态工厂注入方式
AOP
面向切面编程就是纵向的编程,AOP主要一般应用与签名验签、参数校验、日志记录、事务控制、权限控制、性能统计、异常处理等;
- 切面(Aspect):共有功能的实现,如日志切面、权限切面、验签切面等。在实际开发中通常是一个存放共有功能实现的标准java类,当java类使用了@Aspect注解修饰时,就能被AOP容器识别为切面;
- 通知(Advice):切面的具体实现。就是要给目标对象织入的事情。以目标方法为参照点,根据放置的地方不同,可分为前置通知(Before)、后置通知(AfterReturning)、异常通知(AfterThrowing)、最终通知(After)与环绕通知(Around)。在实际开发中通常是切面类中的一个方法,具体属于哪类通知,通过方法上的注解区分;
- 连接点(JoinPoint):程序在运行过程中能够插入切面的地点。例如,方法调用、异常抛出等。Spring只支持方法级的连接点。一个类的所有方法前、后、抛出异常时等都是连接点;
- 切入点(Pointcut):用于定义通知应该切入到哪些连接点上。不同的通知通常需要切入到不同的连接点上,这种精准的匹配是由切入点的正则表达式来定义的;切点就是来定义哪些类里边的哪些方法会得到通知;
- 目标对象(Target):那些即将切入切面的对象;
- 代理对象(Proxy):将通知应用到目标对象之后被动态创建的对象,是程序运行过程中的产物。目标对象被织入共有功能后产生的对象
- 织入(Weaving):将切面应用到目标对象从而创建一个新的代理对象的过程。
Pointcut用法
execution(modifier-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
- 修饰符匹配 modifier-pattern?例:public、private
- 返回值匹配 ret-type-pattern?可以用“*”表示任意返回值
- 类路径匹配 declaring-type-pattern? 全路径的类名
- 方法名匹配 name-pattern 可以指定方法名或者用 * 表示所有方法;set星号表示所有以set开头的方法
- 参数匹配 (param-pattern) 可以指定具体的参数类型,多个参数用“,”分隔;可以用 * 表示匹配任意类型的参数;可以用(…)表示零个或多个任意参数
- 异常类型匹配 throws-pattern? 例:throws Exception
其中后边跟着?表示可选项
例:
@Pointcut("execution(public * cn.wbnull. springbootdemo.controller.*.*(..))")
private void sign() {
}
常用注解
- @Component:泛指组件,当组件不好归类的时候,可以使用这个注解进行标注
- @Controller:控制层组件
- @RestController:相当于@Controller和@ResponseBody的组合效果
- @Service:业务层组件
- @Repository:用于注解DAO层,在daoImpl类上面注解
- @ResponseBody:将Controller的方法返回的对象,转换为指定格式后,写入Response对象的body数据区;
- @RequestMapping:用来处理请求地址映射的注解,可用于类上或方法上;
- @Autowired:可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作;
- @PathVariable:用于将请求URL中的模板变量映射到功能处理方法的参数上;
- @RequestParam:类似一种request.getParameter(“name”);
- @Valid:实体数据校验;
- @CookieValue:用来获取Cookie中的值;
实例化的三种方式
构造器实例化、静态工厂方式实例化、实例工厂方式实例化。
隔离级别
- DEFAULT(默认):使用数据库默认的事务隔离级别,另外四个与JDBC隔离级别一致;
- READ_UNCOMMITTED(读未提交):事务最低的隔离级别,允许一个事务读取另一个事务未提交的数据,可能产生脏读、不可重复读和幻象读;
- READ_COMMITTED(读已提交):保证一个事务修改的数据提交之后才能被另一个事务读取。可以避免脏读,但是可能会出现不可重复读和幻象读;
- REPEATABLE_READ(可重复读):除了保证一个事务不能读取另一个事务未提交的数据外,还保证了不可重复读,可以防止脏读和不可重复读,但是可能出现幻象读;
- SERIALIZABLE(串行化):代价最高但是最可靠的隔离级别,事务被处理为顺序执行。可以防止脏读、不可重复读和幻象读。
事务传播属性
- REQUIRED(默认属性):如果存在事务,则支持当前事务,不存在事务,则开启一个新的事务;
- MANDATORY:支持当前事务,如果当前没有事务,则抛出异常;
- NEVER:以非事务方式运行,如果当前存在事务,则抛出异常:
- NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,就把当前事务挂起;
- REQUIRES_NEW:新建事务,如果当前没有事务,就以非事务方式运行;
- SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式运行;
- NESTED:支持当前事务,并且新增一个SavePoint点,与当前事务同步提交或回滚。
spring三级缓存
解决Bean的循环依赖问题
- 单例对象缓存:存放完全初始化后的Bean
- 早期单例对象的缓存:存放原始Bean,并且存在尚未填充的属性
- 单例工厂的缓存:存放的是工厂对象,工厂对象的目的是生成Bean实例
在Bean的创建过程中,spring会适当的从这三个缓存中检索或者放入对象,确保即使存在循环依赖的情况下,也能成功的去创建和注入Bean
springMVC
springMVC的运行原理
- 客户端发送请求,直接请求到DispatcherServlet。
- DispatcherServlet根据请求信息调用HandlerMaping,解析获取对应的Handler;
- 解析到对应的Handler后,开始有HandlerAdapter适配器处理;
- HandlerAdapter会根据Handler来调用真正的处理器开始处理请求,并返回一个ModelAndView对象,Model是返回的数据,View是一个逻辑上的View;
- ViewResolver会根据逻辑上的View查找实际的View;
- DispatcherServlet把返回的Model传给View,通过View返回给请求者。
springboot
自动装配原理
自动装配是springboot的核心,实际上SpringFramework早就实现了这个功能,SpringBoot只是在其基础上,通过SPI的方式,做了进一步优化。
首先@SpringBootApplication是一个复合注解,可以把它看作是@Configuration、@EnableAutoConfiguration、@ComponentScan注解的集合,实现自动装配的核心注解就是@EnableAutoConfiguration,它上边是有一个@Import注解导入了一个AutoConfigurationImportSelector,这个类里边实现了selectImports方法,这个方法最终就会从META-INF/spring.factories文件中读取@EnableAutoConfiguration类路径为key的类名称列表,然后会通过加载核心类方式过滤当前项目并不需要加载的配置类,然后把需要加载的配置类名称数组返回之后进行加载;
springcloud
五大常用组件:
- 服务注册中心:Eureka
- 负载均衡:ribbon
- 熔断器:Hystrix
- 网关:Gateway
- 分布式配置:SpringCloudConfig
Eureka
就是服务注册中心,对外暴露自己的地址。提供者启动后向Eureka注册自己的信息(地址、提供什么服务),消费者会向Eureka订阅服务,Eureka会将对应服务的所有提供者地址列表发送给消费者,并且定期更新。提供者定期会通过http方式向Eureka刷新自己的状态(心跳-续约)。
Hystrix
Hystrix是一个延迟和容错库,用于隔离访问远程服务、第三方库,防止出现级联失败。
解决雪崩问题
Hystrix解决雪崩的问题主要是服务降级,包括线程隔离、服务熔断;
- 线程隔离&服务降级:Hystrix会为每个依赖的服务分配一个小的线程池,如果线程池已满调用将立即被拒绝,默认不采取排队的方法,加速失败判断时间。如果线程已满或者请求超时,则会进行降级处理,服务降级(优先保证核心服务,而非核心服务不可用或弱可用)虽然会导致请求失败,但是不会造成阻塞,而且最多会影响这个依赖服务对应的线程池中的资源,对其他服务没有影响。请求在超过一秒后都会返回错误信息,这是因为Hystrix默认超时时间为1秒。
- 服务熔断:也叫断路器,Hystrix的服务熔断机制,可以实现弹性容错。一定时间内请求失败百分比达到阈值,则触发熔断,默认失败比的阈值是50%,请求次数不低于20次。断路器打开之后,通过断路的方式,将后续请求直接拒绝,一段时间(默认5秒)之后允许部分请求通过,如果调用成功则关闭断路器,否则继续打开,拒绝请求的服务。