Spring 复习
1.什么是spring?
spring是一个轻量级的(核心包),非侵入式的一站式(数据持久层,we层,核心,aop)的框架
为了简化企业级开发.
核心IOC,AOP
IOC: 控制反转 把创建对象交给spring框架管理(创建对象与使用对象分离),管理对象的生命周期.
DI: 依赖注入 创建对象后,把对象属性赋值, 将关联的对象注入
AOP: 面向编程(是对=面向对象编程的补充,不是spring特有), 通过一个代理对象,在不修改原来代码的情况下.
对目标类进行功能的增强.
使得类与类之间的耦合度降低了. 简化了开发步骤.
2.springBean的管理
-
在xml中配
-
使用注解
依赖注入/自动注入
@Autowired
@Qualifier(value = "adminDao") spring中提供的,支持类型,对象名查找
@Resource(name = "adminDao") jdk中提供的,支持类型,对象名查找
3.spring JdbcTemplate
4.AOP
aop能够做什么
连接点,切入点,切面,通知(前置通知,后置通知,异常通知,返回通知,最终通知 环绕通知),代理,织入
xml
注解
5.spring事务管理
添加一个事务管理器类
事务方式:
1.编程式 在代码中自己开启,自己提交,回滚.
2.声明式 @Transactional修饰方法,类.
声明式事务失效的场景
事务传播行为: 是spring框架对事务的一个额外的增强
A方法 调用了 B方法
6.集成Mybatis
7.springWEB
流程
请求 ----->DispatcherServlet(总调度器)----映射处理器---->DispatcherServlet----->处理适配器---->自己的处理器
接收参数, 向前响应json 文件上传.
springBoot对spring项目的搭建做了简化
BeanFactory 和 ApplicationContext
BeanFactory 和 ApplicationContext 是接口
BeanFactory 接口是spring框架的顶层的接口,用来定义如何获取bean,判断等功能.
DefaultListableBeanFactory实现BeanFactory 接口,是主要的创建bean的工厂类.
ApplicationContext 接口间接的继承BeanFactory 接口,并且扩展一些新的功能.
区别
BeanFactory 面向spring框架,比较底层
ApplicationContext 由于又实现许多的接口,增加了额外的功能
实现了BeanFactory接口的工厂,是懒加载,获取bean是才会创建对象.
实现了ApplicationContext 接口的工厂,是在启动时加载所有的类,创建对象.
在 spring 容器中,BeanFactory 接口是 IOC 容器要实现的最基础的接口,定义了管理 bean 的最基本的方法,例如获取实例、基本的判断等,如下图:
BeanFactory 有非常多的实现类、每个实现类都有不同的职责(单一职责)功能,最强大的是:DefaultListableBeanFactory Spring 底层就是使用的该实现工厂一进行生产 Bean 的.
BeanFactory 还有多个子接口来进一步扩展 bean 相关的功能.
ApplicationContext也间接继承了BeanFactory,如果说BeanFactory是Sping的心脏,那么 ApplicationContext 就是完整的身躯了。它们都可以当做 Spring的容器,Spring 容器是生成 Bean 实例的工厂,并管理容器中的 Bean。
区别:
1.BeanFactory 是 Spring 框架的基础设施,面向 Spring 本身,是 Spring 中比较原始的 Factory,它不支持 AOP、Web 等 Spring 插件. 而 ApplicationContext 不仅包含了 BeanFactory 的所有功能,还支持 Spring 的各种插件,还以一种面向框架的方式工作以及对上下文进行分层和实现继承。
2.BeanFactroy 采用的是延迟加载形式来注入 Bean 的,即只有在使用到某个Bean 时(调用 getBean()),才对该 Bean 进行加载实例化,这样,我们就不能发现一些存在的 Spring 的配置问题。而 ApplicationContext 则相反,它是在容器启动时,一次性创建了所有的 Bean。这样,在容器启动时,我们就可以发现Spring 中存在的配置错误。相对于基本的 BeanFactory,ApplicationContext唯一的不足是占用内存空间。当应用程序配置 Bean 较多时,程序启动较慢。
SpringBean 的生命周期
宏观上来讲,springBean 的生命周期可以分为 5 个阶段:
1. 实例化 Instantiation
2. 属性赋值 Populate
3. 初始化 Initialization
4. 将 bean 对象放入到容器中,使用
5. 销毁 Destruction
细化
1.instantiate bean 对象实例化
2.populate properties 属性赋值
3.1 如果 Bean 实现 BeanNameAware 执行 setBeanName
3.2 如果 Bean 实现 BeanFactoryAware 或者 ApplicationContextAware 设置工厂 setBeanFactory 或者上下文对象 setApplicationContext 对象.
初始化
.........
3.3 如果存在类实现 BeanPostProcessor(AOP) ,执行postProcessBeforeInitialization
3.4 如果 Bean 实现 InitializingBean 执行 afterPropertiesSet如果配置了自己的初始化方法
3.5 如果存在类实现 BeanPostProcessor(AOP) ,执行postProcessAfterInitialization
4.完整的 bean 创建好,将 bean 对象放入到容器中,可以使用
5.销毁 如果 Bean 实现 DisposableBean 执行 destroy
如果配置了自己的销毁方法 指定销毁方法 customerDestroy.
Spring 中的 bean 是线程安全的吗?
Spring 容器中的 Bean 是否线程安全,容器本身并没有提供 Bean 的线程安全策略,因此可以说 Spring 容器中的 Bean 本身不具备线程安全的特性,但是具体还是要结合具体 scope 的 Bean 情况。
Spring 的 bean 作用域(scope)类型
1、singleton:单例,默认作用域。
2、prototype:原型,每次创建一个新对象。
3、request:请求,每次 Http 请求创建一个新对象,适用于........ 线程安全这个问题,要从单例 Bean 与原型 Bean 分别进行说明。
原型 Bean:
对于原型 Bean,每次创建一个新对象,也就是线程之间并不存在 Bean 共享,自然是不会有线程安全的问题。
单例 Bean:
对于单例 Bean,所有线程都共享一个单例实例 Bean,因此是存在资源的竞争。
Bean 又分为
有状态就是有数据存储功能(例如包含成员变量)
无状态就是不会保存数据
如果单例 Bean,是一个无状态 Bean,也就是线程中的操作不会对 Bean 的成员执行查询以外的操作,那么这个单例 Bean 是线程安全的。比如 Spring mvc 的 Controller、Service、Dao 等,这些 Bean 大多是无状态的,只关注于方法本身。
但是如果 Bean 是有状态的 那就需要开发人员自己来进行线程安全的保证,最简单的办法就是改变 bean 的作用域 把 "singleton"改为’‘protopyte’ 这样每次请求Bean 就相当于是 new Bean() 这样就可以保证线程的安全了。
controller、service 和 dao 层本身并不是线程安全的,只是如果只是调用里面的方法,而且多线程调用一个实例的方法,会在内存中复制变量,这是自己的线程的工作内存,是安全的。
测试证明单例 bean 不是线程安全的。
Bean 循环依赖
JAVA 中循环依赖场景很简单,就是 A 对象依赖了 B 对象,B 对象依赖了 A 对象。
那么循环依赖是个问题吗?
如果不考虑 Spring,循环依赖并不是问题,因为对象之间相互依赖是很正常的事情。
这样,A.B 就依赖上了.
Spring 中相互依赖注入会产生问题
在 Spring 中,一个对象并不是简单 new 出来了,而是会经过一系列的 Bean的生命周期,就是因为 Bean 的生命周期所以才会出现循环依赖问题。
产生循环依赖的问题,主要是:
A 创建时-->需要 B----B 去创建--->需要 A,
从而产生了循环。
spring 内部有三级缓存:
在 DefaultSingletonBeanRegistry 类中定义了 3 个 Map 对象充当缓存.
singletonObjects: 一级缓存,用于保存实例化、注入、初始化完成的 bean.
实例
earlySingletonObjects:二级缓存,用于保存实例化完成的 bean 实例,提前曝露对象.
singletonFactories: 三级缓存,用于保存创建 bean 的工厂.
循环依赖的根本原因是实例化和初始化是分开处理的。
Servlet 的过滤器与 Spring 拦截器区别
过滤器 Filter 是在请求进入容器后,但在进入 servlet 之前进行预处理,需要服务器来进行控制。
拦截器 Interceptor 是在请求进入 servlet 后,在进入 Controller 之前进行预处理的,Controller 中渲染了对应的视图之后请求结束。
Spring 常用注解
声明 bean 的注解
@Component:泛指各种组件
@Controller、@Service、@Repository 都可以称为@Component
@Controller:控制层
@Service:业务层
@Repository:数据访问层
Bean 的生命周期属性
@Scope 设置类型包括:设置 Spring 容器如何新建 Bean 实例
singleton:单例,一个 Spring 容器中只有一个 bean 实例,默认模式
protetype:每次调用新建一个 bean
request:web 项目中,给每个 http request 新建一个 bean
session:web 项目中,给每个 http session 新建一个 bean
globalSession:给每一个 global http session 新建一个 Bean 实例
注入 bean 的注解
@Autowired:由 Spring 提供
@Qualifier: 当有多个同一类型的 Bean 时,可以用@Qualifier(“name”)来指定。与
@Autowired 配合使用.
@Resource:由 java 提供
切面(AOP)相关注解
Spring 支持 AspectJ 的注解式切面编程
@Aspect:声明一个切面
@After:在方法执行之后执行(方法上)
@Before:在方法执行之前执行(方法上)
@Around:在方法执行之前与之后执行(方法上)
@PointCut:声明切点
@EnableAspectJAutoProxy:开启 Spring 对 AspectJ 代理的支持
SpringMVC 常用注解
@RestController : 该 注 解 为 一 个 组 合 注 解 , 相 当 于 @Controller 和
@ResponseBody 的组合,注解在类上,意味着,该 Controller 的所有方法都默认加上了@ResponseBody。
@RequestMapping:用于映射 web 请求,包括访问路径和参数
@ResponseBody:支持将返回值放到 response 内,而不是一个页面,通常用户返回 json 数据
@RequestBody:允许 request 的参数在 request 体中,而不是在直接连接的地址后面
其他注解
@JsonFormat: 此注解用于属性或者方法上(最好是属性上),可以方便的把 Date 类型直接转化为我们想要的模式.
@Transactional 注解放在类级别时,表示所有该类的公共方法都配置相同的事务属性信息。
SpringBoot 注解
@SpringBootApplication: 包含@Configuration、@EnableAutoConfiguration、@ComponentScan 通常用在主类上;
@RestControllerAdvice,@ExceptionHandler 用于统一异常处理,捕获指定的异常.
配置类相关注解
@Configuration:声明当前类为配置类
@Bean:注解在方法上,声明当前方法的返回值为一个 bean,替代 xml 中的方式
@ComponentScan:用于对 Component 类型注解进行扫描
SpringBoot 自动装配原理
自动装配基本流程概述
springBoot 启动时,首先对 application.yml 和 pom.xml 文件进行读取,获取到项目中使用到的第三方组件,然后读取 spring.factories 中的 spring 支持的配置类,最后加载项目中所使用到的组件配置类.
注解层面梳理
启动类
@SpringBootApplication 注解是一个复合注解
在@EnableAutoConfiguration 中有一个
@Import({AutoConfigurationImportSelector.class})注解,其中包含
AutoConfigurationImportSelector 类.
AutoConfigurationImportSelector 类中关键方法
启动类 run 方法层面梳理.