22
33让 java 开发模块化,并且全面。Spring 通过控制反转降低耦合性,一个对象的依赖通过被动注入的方式而非主动 new,还通过代理模式实现了面向切面编程。
44
5- ## IOC 是什么,什么是 Spring IOC 容器?
5+ ## IOC 是什么,什么是 Spring IOC 容器?⭐
66
7- IOC 是一种设计思想。 ** IOC 容器是 Spring 用来实现 IOC 的载体, IOC 容器在某种程度上就是个Map(key,value),key是 name 属性,Map 是对应的对象。** 容器创建 Bean 对象, 使用依赖注入来管理对象之间的相互依赖关系,配置它们并管理它们的完整生命周期,很大程度上简化应用的开发,降低了耦合度。
7+ IOC 是一种设计思想。 ** IOC 容器是 Spring 用来实现 IOC 的载体, IOC 容器在某种程度上就是个Map(key,value),key是 name 属性,value 是对应的对象。** 容器创建 Bean 对象, 使用依赖注入来管理对象之间的相互依赖关系,配置它们并管理它们的完整生命周期,很大程度上简化应用的开发,降低了耦合度。
88
99容器通过读取提供的配置,比如 XML,注解或 Java 代码来接收对象信息进行实例化,配置和组装。
1010
11- ### IoC 的实现机制⭐
11+ Spring在创建容器时有一个点就是利用了模板方法设计模式设计了 refresh 方法,这个方法是模板方法,低级容器实现了 obtainFreshBeanFactory 的抽象方法,调用 refreshBeanFactory 加载了所有 BeanDefinition 和 Properties 到 ** DefaultListableBeanFactory ** 容器中。发送了注册事件后高级容器启动功能,比如接口回调,监听器,创建单例bean,发布事件等功能。
1212
13- 实现原理就是工厂模式加反射机制。
13+ ### IoC 的实现机制/初始化流程⭐
1414
15- * Spring 容器在启动的时候,先会保存所有注册进来的 Bean 的定义信息, 注册到 BeanFactory 中。 注册也只是将这些信息都保存到了注册中心(说到底核心是一个 beanName-> beanDefinition 的 map)
16- * 设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean,如environment、systemProperties
17- * 如果有 Bean 实现了 BeanFactoryPostProcessor 接口,Spring 会负责调用里面的 postProcessBeanFactory 方法,这是一个扩展方法
18- * 注册 BeanPostProcessor 的实现类,这是在 Bean 初始化前后执行的方法
15+ 主要实现原理就是工厂模式加反射机制。
16+
17+ 调用 refresh() 方法:
18+
19+ * 刷新准备,设置开始时间,状态, 初始化占位符等操作
20+
21+ * 获取内部的 BeanFactory,Spring 容器在启动的时候,先会保存所有注册进来的 Bean 的定义信息, 注册到 BeanFactory 中。
22+ * 设置 BeanFactory 的类加载器和后置处理器,添加几个 BeanPostProcessor,手动注册默认的环境 bean
23+ * 为子类提供后置处理 BeanFactory 的扩展能力,初始化上下文之前,可以复写 postProcessBeanFactory这个方法
24+ * 执行 Context 中注册的 BeanFactory 后置处理器,对 SpringBoot 来说,这一步会进行 BeanDefintion 的解析
25+ * 按优先级在 BeanFactory 注册 Bean 的后置处理器,这是在 Bean 初始化前后执行的方法
1926* 初始化国际化,事件广播器的模块,注册事件监听器
20- * 然后 ** Spring容器就会创建这些单例 Bean**
21- 1 . 用到这个 Bean 的时候;利用 getBean 创建 Bean,创建好以后保存在容器中;
22- 2 . 统一创建剩下所有的 Bean 的时候;调用 finishBeanFactoryInitialization() 初始化所有剩下的单例 Bean。
27+ * 然后 ** Spring容器就会创建这些非延迟加载的单例 Bean**
2328* 最后广播事件,ApplicationContext 初始化/刷新完成
2429
2530具体源码实现分析请看我的另一篇文章 。
@@ -36,24 +41,68 @@ IOC 是一种设计思想。 **IOC 容器是 Spring 用来实现 IOC 的载体
3641
3742- ** Singleton** - 每个 Spring IoC 容器仅有一个单实例。
3843- ** Prototype** - 每次请求都会产生一个新的实例。
39- - ** Request** - 每一次 HTTP 请求都会产生一个新的实例,并且该 bean 仅在当前 HTTP 请求内有效。
40- - ** Session** - 每一次 HTTP 请求都会产生一个新的 bean,同时该 bean 仅在当前 HTTP session 内有效。
41- - ** Global-session** - 类似于标准的 HTTP Session 作用域,不过它仅仅在基于 portlet 的 web 应用中才有意义。如果你在 web 中使用 global session 作用域来标识 bean,那么 web 会自动当成 session 类型来使用。
44+ - ** Request** - 每次请求都会创建一个实例
45+ - ** Session** - 在一个会话周期内只有一个实例
46+ - Global-session - 类似于标准的 HTTP Session 作用域,5.0版本后已不再使用
47+ - ** Appilcation** - 在一个 ServletContext 中只有一个实例
48+ - ** Websocket** - 在一个 Websocket 只有一个实例
4249
43- 仅当用户使用支持 Web 的 ApplicationContext 时,最后三个才可用 。
50+ 仅当用户使用支持 Web 的 ApplicationContext 时,最后几个才可用 。
4451
4552#### Bean 的生命周期⭐
4653
47- 防止篇幅过长和内容重复,请看 SpringIOC 源码分析
54+ * Bean容器/BeanFactory 通过对象的构造器或工厂方法先实例化 Bean;
55+
56+ * 再根据 Resource 中的信息再通过设定好的方法(典型的有setter,统称为BeanWrapper)对 Bean 设置属性值,得到 BeanDefintion 对象,然后 put 到 beanDefinitionMap 中,调用 getBean 的时候,从 beanDefinitionMap 里拿出 Class 对象进行注入(** 使用了反射** ),同时如果有依赖关系,将递归调用 getBean 方法,即依赖注入的过程。
57+
58+ * 检查 xxxAware 相关接口,比如 BeanNameAware,BeanClassLoaderAware,ApplicationContextAware( BeanFactoryAware)等等,如果有就调用相应的 setxxx 方法把所需要的xxx传入到 Bean 中。
59+
60+ ** 补充** :关于 Aware ,Aware 就是感知的意思, Aware 的目的是为了让Bean获得Spring容器的服务。 实现了这类接口的 bean 会存在“意识感”,从而让容器调用 setxxx 方法把所需要的 xxx 传到 Bean 中。
61+
62+ * 此时检查是否存在有于 Bean 关联的任何 BeanPostProcessors, 执行 postProcessBeforeInitialization() 方法(前置处理器)。
63+
64+ * 如果 Bean 实现了InitializingBean接口(正在初始化的 Bean),执行 afterPropertiesSet() 方法。
65+
66+ * 检查是否配置了自定义的 init-method 方法,如果有就调用。
67+
68+ * 此时检查是否存在有于 Bean 关联的任何 BeanPostProcessors, 执行 postProcessAfterInitialization() 方法(后置处理器)。返回 wrapperBean(包装后的 Bean)。
69+
70+ * 这时就可以开始使用 Bean 了,当容器关闭时,会检查 Bean 是否实现了 DisposableBean 接口,如果有就调用 destory() 方法。
71+
72+ * 如果 Bean 配置文件中的定义包含 destroy-method 属性,执行指定的方法。
73+
74+ 上面整个过程就是 Bean 的整个生命周期了。
75+
76+ ** Bean 单例和多例的情况:**
4877
49- #### Spring 中的单例 bean 的线程安全问题
78+ 在实际情况中一般并不会实现很多扩展接口,我们知道,Bean 的基本类型分为 singleton(单例) 和 prototype(原型/多例) 两种,在容器创建过程中,单例 Bean 默认跟随容器一起实例化,而当我们指定 Bean节点的 lazy-init=”true” 时,只有在第一次获取 Bean 的时候才会初始化 Bean。当然,如果想让所有单例 Bean 都延迟加载,可以在根节点设置此属性。
5079
51- Spring容器中的Bean是否线程安全,容器本身并没有提供 Bean 的线程安全策略,因此可以说 Spring 容器中的Bean本身不具备线程安全的特性,但是具体还是要结合具体 scope 的 Bean 去研究。
80+ 当 scope="prototype" 时,容器也会延迟初始化 Bean,并不会立刻创建对象,而是在第一次请求该 bean 时才初始化(如调用 getBean 方法时)。和单例不同的情况是:在对象销毁时,容器不会帮我们调用任何方法。
5281
53- 常见的有两种解决办法:
82+ Spring不能对一个 prototype bean 的整个生命周期负责:容器在初始化、配置、装饰或者是装配完一个 prototype 实例后,将它交给客户端,随后就对该prototype 实例不闻不问了。
5483
55- 1 . 在Bean对象中尽量避免定义可变的成员变量(不太现实)。
56- 2 . 在类中定义一个ThreadLocal成员变量,将需要的可变成员变量保存在 ThreadLocal 中(推荐的一种方式)。
84+ 也许你会问,那么怎么释放被 prototype 作用域 bean 占用的资源?
85+
86+ 我们可以通过 Bean 的后置处理器, 该处理器持有要被清除的bean的引用。
87+
88+ Spring 被设计成** 一个管理应用程序模块定义的容器以及工厂,而不是管理模块自身的容器** ,让模块可以分别独立开发,实现了模块之间的解耦。
89+
90+ 为什么要使用Spring:
91+
92+ 1 . Spring提供一个容器/工厂,统一管理模块的定义,根据需要创建。
93+ 2 . 把模块的配置参数统一管理,模块不需要自行读取配置。
94+ 3 . Spring提供依赖注入,把依赖的模块自动推送进来,不需要模块自己拉取。
95+ 4 . 此外,Spring提供了对很多其他第三方框架的集成功能,减少了样板代码(boilerplate)。
96+
97+ ## 常见扩展接口
98+
99+ BeanFactoryPostProcessor:处理所有bean前,对bean factory进行预处理
100+ BeanDefinitionRegistryPostProcessor:可以添加自定义的bean
101+ BeanPostProcessor:支持在Bean初始化前、后对bean进行处理
102+ ApplicationContextAware:可以获得ApplicationContext及其中的bean
103+ InitializingBean:在bean创建完成,所有属性注入完成后执行
104+ DisposableBean:在bean销毁前执行
105+ ApplicationListener:用来监听产生的应用事件
57106
58107### Spring的后置处理器
59108
@@ -118,9 +167,9 @@ Spring使用了三级缓存解决了循环依赖的问题。在populateBean()给
118167
119168** 现在再来了解一下三级缓存:**
120169
121- 1 . ` singletonObjects ` :第一级单例缓存池 。用于存放完全初始化好的 bean,** 从该缓存中取出的 bean 可以直接使用**
170+ 1 . ` singletonObjects ` :第一级,单例缓存池 。用于存放完全初始化好的 bean,** 从该缓存中取出的 bean 可以直接使用**
1221712 . ` earlySingletonObjects ` :第二级。提前曝光的单例对象的cache,存放原始的 bean 对象(尚未填充属性的 bean)
123- 3 . ` singletonFactories ` :第三纪单例对象工厂缓存 。单例对象工厂的cache,存放 bean 工厂对象
172+ 3 . ` singletonFactories ` :第三级,单例对象工厂缓存 。单例对象工厂的cache,存放 bean 工厂对象
124173
125174** 了解完缓存就可以开始了解单例 Bean 的创建过程:**
126175
@@ -161,56 +210,14 @@ JDK 动态代理基于接口,所以只有接口中的方法会被增强,而
161210
162211### 实现原理
163212
164- JDK动态代理:基于反射,生成实现代理对象接口的匿名类,通过生成代理实例时传递的InvocationHandler处理程序实现方法增强。
213+ JDK动态代理:基于反射,利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
165214CGLIB动态代理:基于操作字节码,通过加载代理对象的类字节码,为代理对象创建一个子类,并在子类中拦截父类方法并织入方法增强逻辑。底层是依靠ASM(开源的java字节码编辑类库)操作字节码实现的。
166215
167- ## AspectJ 和 Spring AOP 的对比:
168-
169- ** Spring AOP:**
170-
171- - 它基于动态代理来实现。默认地,如果使用接口的,用 JDK 提供的动态代理实现,如果没有接口,使用 CGLIB 实现。大家一定要明白背后的意思,包括什么时候会不用 JDK 提供的动态代理,而用 CGLIB 实现。
172- - Spring 的 IOC 容器和 AOP 都很重要,Spring AOP 需要依赖于 IOC 容器来管理。
173- - Spring AOP 只能作用于 Spring 容器中的 Bean,它是使用纯粹的 Java 代码实现的,只能作用于 bean 的方法。
174- - Spring 提供了 AspectJ 的支持,一般来说我们用** 纯的** Spring AOP 就够了。
175- - 很多人会对比 Spring AOP 和 AspectJ 的性能,Spring AOP 是基于代理实现的,在容器启动的时候需要生成代理实例,在方法调用上也会增加栈的深度,使得 Spring AOP 的性能不如 AspectJ 那么好。
176-
177- ** AspectJ:**
178-
179- - 属于静态织入,它是通过修改代码来实现的,它的织入时机可以是:
180- - Compile-time weaving:编译期织入,如类 A 使用 AspectJ 添加了一个属性,类 B 引用了它,这个场景就需要编译期的时候就进行织入,否则没法编译类 B。
181- - Post-compile weaving:也就是已经生成了 .class 文件,或已经打成 jar 包了,这种情况我们需要增强处理的话,就要用到编译后织入。
182- - ** Load-time weaving** :指的是在加载类的时候进行织入,要实现这个时期的织入,有几种常见的方法。1、自定义类加载器来干这个,这个应该是最容易想到的办法,在被织入类加载到 JVM 前去对它进行加载,这样就可以在加载的时候定义行为了。2、在 JVM 启动的时候指定 AspectJ 提供的 agent:` -javaagent:xxx/xxx/aspectjweaver.jar ` 。
183-
184- - AspectJ 能干很多 Spring AOP 干不了的事情,它是 ** AOP 编程的完全解决方案** 。Spring AOP 致力于解决的是企业级开发中最普遍的 AOP 需求(方法织入),而不是力求成为一个像 AspectJ 一样的 AOP 编程完全解决方案。
185- - 因为 AspectJ 在实际代码运行前完成了织入,所以大家会说它生成的类是没有额外运行时开销的。
216+ ## AspectJ 和 Spring AOP
186217
187218### 区别
188219
189- ** Spring AOP 属于运行时增强,而 AspectJ 是编译时增强。** Spring AOP 基于代理(Proxying),而 AspectJ 基于字节码操作(Bytecode Manipulation)。
190-
191- Spring AOP 已经集成了 AspectJ ,AspectJ 应该算的上是 Java 生态系统中最完整的 AOP 框架了。AspectJ 相比于 Spring AOP 功能更加强大,但是 Spring AOP 相对来说更简单,
192-
193- 如果我们的切面比较少,那么两者性能差异不大。但是,当切面太多的话,最好选择 AspectJ ,它比Spring AOP 快很多。
194-
195- ### ** 什么是切点(JoinPoint)**
196-
197- 程序运行中的一些时间点, 例如一个方法的执行, 或者是一个异常的处理.
198-
199- 在 Spring AOP 中, join point 总是方法的执行点。
200-
201- ### ** 什么是通知(Advice)?**
202-
203- 特定 JoinPoint 处的 Aspect 所采取的动作称为 Advice。Spring AOP 使用一个 Advice 作为拦截器,在 JoinPoint “周围”维护一系列的拦截器。
204-
205- ### ** 有哪些类型的通知(Advice)?**
206-
207- - ** Before** - 这些类型的 Advice 在 joinpoint 方法之前执行,并使用 @Before 注解标记进行配置。
208- - ** After Returning** - 这些类型的 Advice 在连接点方法正常执行后执行,并使用@AfterReturning 注解标记进行配置。
209- - ** After Throwing** - 这些类型的 Advice 仅在 joinpoint 方法通过抛出异常退出并使用 @AfterThrowing 注解标记配置时执行。
210- - ** After (finally)** - 这些类型的 Advice 在连接点方法之后执行,无论方法退出是正常还是异常返回,并使用 @After 注解标记进行配置。
211- - ** Around** - 这些类型的 Advice 在连接点之前和之后执行,并使用 @Around 注解标记进行配置。
212-
213-
220+ ** Spring AOP 属于运行时增强,而 AspectJ 是编译时增强。**
214221
215222## springAOP 项目中的实际应用
216223
@@ -274,25 +281,64 @@ View是一个接口,实现类支持不同的View类型(jsp、freemarker、pd
274281
275282## 常用注解
276283
277- * @ Controller 负责注册一个bean 到spring 上下文中.
284+ ** 类型类 **
278285
279- * @ ResponseBody 将java对象转换成json格式的字符串,返回给浏览器
286+ - @ Controller :负责注册一个bean 到spring 上下文中
280287
281- 该注解用于将 Controller 的方法返回的对象,通过适当的 ** HttpMessageConverter ** 转换为指定格式后,写入到 Response 对象的 body 数据区。
288+ - @ Service
282289
283- ** HttpMessageConverter是处理器适配器创建的,用于数据转换 ** 。
290+ - @ Repository
284291
285- * @ RequestBody 接收JSON数据
292+ - @ Component
286293
287- 该注解用于读取 Request 请求的 body 部分数据,使用系统默认配置的 HttpMessageConverter 进行解析,然后把相应的数据绑定到要返回的对象上
294+ - @ Configuration :声明当前类为配置类,相当于xml形式的Spring配置
288295
289- * @ RequestController ** @ RestController = @ ResponseBody + @ Controller **
296+ - @ Bean :注解在方法上,声明当前方法的返回值为一个 bean
290297
291- * @ PathVariable URL 中的 {xxx} 占位符可以通过 @ PathVariable (“xxx“) 绑定到操作方法的入参中。
298+ ** @ Bean 和 @ Component 的区别 **
292299
293- * @ControllerAdvice 使一个Contoller成为全局的异常处理类,类中用@ExceptionHandler 方法注解的方法可以处理所有Controller发生的异常。
300+ * @Component 在类上使用,表示这是一个组件类,需要 Spring 为这个类创建 Bean
301+
302+ * @Bean 在方法上使用,告诉 Spring 这个方法将返回一个 Bean 对象,需要把返回的对象注册到应用上下文中
303+
304+ ** 设置类**
305+
306+ - @Required :确保值一定被设置
307+ - @Autowired && @Qualifier
308+ - @Qualifier :当一个接口有多个实现的时候,为了指名具体调用哪个类的实现。
309+ - @Scope :生命周期
310+
311+ ** Web类**
294312
295- * RequestMapping 是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
313+ - @RequestMapping && @GetMapping @ PostMapping
314+
315+ - RequestMapping:用于映射Web请求,包括访问路径和参数(类或方法上)
316+
317+ - @PathVariable && @RequestParam
318+
319+ - @PathVariable :用于接收路径参数,比如@RequestMapping (“/hello/{name}”)申明的路径,将注解放在参数中前,即可获取该值,通常作为Restful的接口实现方法。
320+
321+ - @RequestBody && @ResponseBody
322+
323+ - @RequestBody 接收JSON数据
324+
325+ 该注解用于读取 Request 请求的 body 部分数据。允许request的参数在request体中,而不是在直接连接在地址后面。(放在参数前)
326+
327+ - @ResponseBody 将java对象转换成json格式的字符串,返回给浏览器。该注解用于将 Controller 的方法返回的对象,写入到 Response 对象的 body 数据区。 (返回值旁或方法上)
328+
329+
330+ ** 功能类**
331+
332+ - @ImportResource :引用类
333+ - @ComponentScan :自动扫描
334+ - @EnableCaching && Cacheable: 开启注解式的缓存支持/缓存
335+ - @Transactional :开启事务
336+ - @Aspect && Poincut:切面和切点
337+ - @Scheduled :来申明这是一个任务
338+
339+ * @RequestController ** @RestController =@ResponseBody +@Controller ** 意味着,该Controller的所有方法都默认加上了@ResponseBody 。
340+
341+ * @ControllerAdvice 使一个Contoller成为全局的异常处理类,类中用@ExceptionHandler 方法注解的方法可以处理所有Controller发生的异常。
296342
297343* @ModelAttribute 最主要的作用是将数据添加到模型对象中,用于视图页面展示时使用。 等价于 model.addAttribute("attributeName", abc)。
298344
@@ -335,7 +381,7 @@ View是一个接口,实现类支持不同的View类型(jsp、freemarker、pd
335381
336382在` @Transactional ` 注解中如果不配置` rollbackFor ` 属性,那么事物只会在遇到` RuntimeException ` 的时候才会回滚,加上` rollbackFor=Exception.class ` ,可以让事物在遇到非运行时异常时也回滚。
337383
338- ## 事务传播行为⭐
384+ ## 事务传播行为/机制 ⭐
339385
340386事务传播行为(propagation behavior)指的就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行。
341387
0 commit comments