下列spring系列参考【路人甲Java】的spring系列,每个系列的标题我都标注了原路径跳转,尊重原创,也感谢原创分享。可以通过标题点进去看更多的详细案例。 1-14个人觉得可以快速简单看看,15开始跟着代码案例多玩玩。
Spring系列第1篇:为何要学spring?
简化项目开发,让我们的项目更容易维护和扩展
Spring系列第2篇:控制反转(IoC)与依赖注入(DI)
1.IOC控制反转,是一种设计理念,将对象创建和组装的主动控制权利交给了spring容器去做,控制的动作被反转了,降低了系统的耦合度,利于系统维护和扩展,主要就是指需要使用的对象的组装控制权被反转了,之前是自己要做的,现在交给spring容器做了。
2.DI依赖注入,表示spring容器中创建对象时给其设置依赖对象的方式,通过某些注入方式可以让系统更灵活,比如自动注入等可以让系统变的很灵活,这个后面的文章会细说。
3.spring容器:主要负责容器中对象的创建、组装、对象查找、对象生命周期的管理等等操作。
Spring系列第3篇:Spring容器基本使用及原理
1.IOC容器是具有依赖注入功能的容器,负责对象的实例化、对象的初始化,对象和对象之间依赖关系配置、对象的销毁、对外提供对象的查找等操作,对象的整个生命周期都是由容器来控制。我们需要使用的对象都由ioc容器进行管理,不需要我们再去手动通过new的方式去创建对象,由ioc容器直接帮我们组装好,当我们需要使用的时候直接从ioc容器中直接获取就可以了。
2.那么spring ioc容器是如何知道需要管理哪些对象呢?
需要我们给ioc容器提供一个配置清单,这个配置支持xml格式和java注解的方式,在配置文件中列出需要让ioc容器管理的对象,以及可以指定让ioc容器如何构建这些对象,当spring容器启动的时候,就会去加载这个配置文件,然后将这些对象给组装好以供外部访问者使用。
3.这里所说的IOC容器也叫spring容器。
4.spring容器对象
spring内部提供了很多spring容器的接口和对象,常见几个容器接口+Impl
1.BeanFactory接口 它是spring容器的顶层接口,提供容器最基本的功能。
2.ApplicationContext接口 extends BeanFactory接口
AOP + 国际化 + 事件支持等等
3.ClassPathXmlApplicationContext类 implements ApplicationContext接口
4.AnnotationConfigApplicationContext类 implements ApplicationContext接口
Spring系列第4篇:xml中bean定义详解(-)
被spring管理的对象统称为bean,通过bean xml配置文件告诉spring容器需要管理哪些bean;我们需要给bean定义一个名称,spring内部将这些名称和具体的bean对象进行绑定,然后spring容器可以通过这个的名称找对我们需要的对象,这个名称叫做bean的名称,在一个spring容器中需要是唯一的。
Spring系列第5篇:创建bean实例这些方式你们都知道?
1.通过反射调用构造方法创建bean对象
<bean id="" class=""/> 无参构造
<bean id="" class=""> 有参构造
<constructor-arg index="0" value="" ref="">
2.通过静态工厂方法创建bean对象
<bean id="" class="" factory-method=""/> 静态工厂无参
<bean id="" class="" factory-method=""/> 实例工厂有参
<constructor-arg index="0" value=""/>
3.通过实例工厂方法创建bean对象
<bean id="aA" class="..."/>
<bean id="" factory-bean="aA" factory-method=""> 实例无参
<bean id="" factory-bean="aA" factory-method=""> 实例有参
<constructor-arg index="" value="" ref=""/>
4.通过FactoryBean创建bean对象
<bean id="" class="实现了FactoryBean接口的类,需要自己编写">
5.前三种方式最根本的区别还是创建方式的不同。
第一种,通过默认的无参构造方式创建,其本质就是把类交给Spring自带的工厂(BeanFactory)管理、由Spring自带的工厂模式帮我们维护和创建这个类。
如果是有参的构造方法,也可以通过XML配置传入相应的初始化参数,这种也是开发中用的最多的。
第二种,通过静态工厂创建,其本质就是把类交给我们自己的静态工厂管理,Spring只是帮我们调用了静态工厂创建实例的方法,
而创建实例的这个过程是由我们自己的静态工厂实现的,在实际开发的过程中,很多时候我们需要使用到第三方jar包提供给我们的类,
而这个类没有构造方法,而是通过第三方包提供的静态工厂创建的,这是时候,如果我们想把第三方jar里面的这个类交由spring来管理的话,
就可以使用Spring提供的静态工厂创建实例的配置。
第三种,通过实例工厂创建,其本质就是把创建实例的工厂类交由Spring管理,同时把调用工厂类的方法创建实例的这个过程也交由Spring管理,
看创建实例的这个过程也是有我们自己配置的实例工厂内部实现的。在实际开发的过程中,如Spring整合Hibernate就是通过这种方式实现的。
但对于没有与Spring整合过的工厂类,我们一般都是自己用代码来管理的。
Spring系列第6篇:玩转bean scope,避免跳坑里!
bean的作用域:
1.自带两种:singleton(默认单列,需要考虑线程安全问题)和 prototype(多例,考虑性能问题)
2.还有三种,是spring Web容器环境中才支持的request、session、application
3.也可以自定义scope,实现Scope接口
Spring系列第7篇:依赖注入之手动注入
1.spring依赖注入的方式:自动注入 + 手动注入(构造函数的方式、set属性的方式)
<!-- 通过构造器方式注入容器中的bean,还可以分为三种:根据构造器参数索引注入、根据构造器参数类型注入、根据构造器参数名称注入 -->
<constructor-arg index="0" ref="user"/>
<!-- 通过setter方式注入容器中的bean -->
<property name="userModel" ref="user"/>
2.自动注入分为:
byteName:按照名称进行注入
byType:按类型进行注入
constructor:按照构造方法进行注入
default:默认注入方式,按名称
3.创建bean四种方式 和 依赖注入方式 是两个概念( IOC 和 DI )
Q1:有参构造和构造器注入如何区分??? A1:构造器注入,分为无参和有参。
Spring系列第8篇:自动注入(autowire)详解
解决手动注入的不足:
1.注入的对象比较多时配置文件代码量暴增
2.新增或者删除了一些依赖,还需要手动去调整bean xml中的依赖配置信息,否则会报错,不利于维护和扩展
Spring系列第9篇:depend-on到底是干什么的?
spring不同bean的创建销毁顺序,通过depend-on干预bean创建和销毁顺序
<bean id="bean1" class="" depend-on="bean2,bean3; bean4" />
无依赖的bean创建顺序和定义的顺序一致,销毁顺序刚好相反
通过构造器强依赖的bean,会先创建构造器参数中对应的bean,然后才会创建当前bean,销毁顺序刚好相反
depend-on可以指定档期bean依赖的bean,通过这个可以确保depend-on指定的bean在当前bean创建之前先创建好,销毁顺序刚好相反
Spring系列第10篇:primary可以解决什么问题?
当从容器中查找一个bean的时候,如果容器中出现多个Bean候选者时,可以通过primary="true"将当前bean置为首选者,
那么查找的时候就会返回主要的候选者,否则将抛出异常。
Spring系列第11篇:bean中的autowire-candidate又是干什么的?
autowire-candidate:设置当前bean在被其他对象作为自动注入对象的时候,是否作为候选bean,默认值是true。
Spring系列第12篇:lazy-init:bean延迟初始化
spring bean初始化的方式2种方式:实时初始化 + 延时初始化 lazy-init="true"
Spring系列第13篇:使用继承简化bean配置(abstract & parent)
1.bean元素的abstract属性为true的时候可以定义某个bean为一个抽象的bean,相当于定义了一个bean模板,spring容器并不会创建这个bean,从容器中查找abstract为true的bean的时候,会报错BeanIsAbstractException异常
2.bean元素的parent属性可以指定当前bean的父bean,子bean可以继承父bean中配置信息,也可以自定义配置信息,这样可以覆盖父bean中的配置
Spring系列第14篇:lookup-method和replaced-method比较陌生,怎么玩的?
spring中 单例bean中使用多例bean三种方式:
1.implements ApplicationContextAware
2.lookup-method:方法查找,可以对指定的bean的方法进行拦截,然后从容器中查找指定的bean作为被拦截方法的返回值
<bean id="serviceA" class="com.javacode2018.lesson001.demo13.lookupmethod.ServiceA" scope="prototype"/>
<bean id="serviceB" class="com.javacode2018.lesson001.demo13.lookupmethod.ServiceB">
<lookup-method name="getServiceA" bean="serviceA"/>
</bean>
3.replaced-method:方法替换,可以实现bean方法替换的效果,整体来说比lookup-method更灵活一些
<bean id="serviceA" class="com.javacode2018.lesson001.demo14.ServiceA" scope="prototype"/>
<bean id="serviceB" class="com.javacode2018.lesson001.demo14.ServiceB">
<replaced-method name="getServiceA" replacer="serviceBMethodReplacer"/>
</bean>
Spring系列第15篇(Java动态代理&cglib代理)
JDK:InvocationHandler-invoke CGLIB:MethodInterceptor-intercept
1.proxy使用注意
jdk中的Proxy只能为接口生成代理类,如果你想给某个类创建代理类,那么Proxy是无能为力的,此时需要我们用到下面要说的cglib了。
Proxy类中提供的几个常用的静态方法大家需要掌握
通过Proxy创建代理对象,当调用代理对象任意方法时候,会被InvocationHandler接口中的invoke方法进行处理,这个接口内容是关键
2.CGLIB和Java动态代理的区别
Java动态代理只能够对接口进行代理,不能对普通的类进行代理(因为所有生成的代理类的父类为Proxy,Java类继承机制不允许多重继承);CGLIB能够代理普通类;
Java动态代理使用Java原生的反射API进行操作,在生成类上比较高效;CGLIB使用ASM框架直接对字节码进行操作,在类的执行过程中比较高效
Spring系列第16篇:深入理解java注解及spring对注解的增强(预备知识)
1.注解是干什么的?
1.注释给人看的,注解给机器看的
2.注解是对代码的一种增强,可以在代码编译或者程序运行期间获取注解的信息,然后根据这些信息做各种牛逼的事情。
2.一个注解可以使用多次么?如何使用?
1.默认情况下注解是不允许重复使用的。
2.如果我们想重复使用注解的时候,需要用到@Repeatable注解
3.@Inherited是做什么的?
@Inherit:实现类之间的注解继承,但是要注意:类可以继承父类上被@Inherited修饰的注解,而不能继承接口上被@Inherited修饰的注解
4.@Target中的`TYPE_PARAMETER和TYPE_USER`用在什么地方?
都是1.8以后的,类型参数上 TYPE_PARAMETER,跟泛型相关; 能用在任何类型名称上 TYPE_USE
5.泛型中如何使用注解?
TYPE_PARAMETER
6.注解定义可以实现继承么?
无法继承
7.spring中对注解有哪些增强?@Aliasfor注解是干什么的?
由于无法继承,就会存在 @A1{}; @A1 @B1{}; @B1 UseAnnotation13{};
此时有个问题:此时如果想在UseAnnotation13上给B1上的A1注解设置值是没有办法的,注解定义无法继承导致的,如果注解定义上面能够继承,那用起来会爽很多,spring通过@Aliasfor方法解决了这个问题。
Spring系列第17篇:@Configration和@Bean注解详解(bean批量注册)
1.spring中,类上加不加@Configuration注解,有什么区别?
@Configuration注解修饰的类,会被spring通过cglib做增强处理,通过cglib会生成一个代理对象,代理会拦截所有被@Bean注解修饰的方法,可以确保一些bean是单例的
2.不用@Configuration注解,能不能通过@Bean注解来注册bean?
不管@Bean所在的类上是否有@Configuration注解,都可以将@Bean修饰的方法作为一个bean注册到spring容器中
Spring系列第18篇:@ComponentScan、@ComponentScans详解(bean批量注册)
1.@ComponentScan注解是做什么的?
@ComponentScan用于批量注册bean,spring会按照这个注解的配置,递归扫描指定包中的所有类,将满足条件的类批量注册到spring容器中
一般在xml里面用<context:component-scan base-packing="xx.xx"/>
2.basePackages的方式和basePackageClasses的方式有什么区别?你建议用哪个?为什么?
可以通过value、basePackages、basePackageClasses 这几个参数来配置包的扫描范围
指定包名的方式配置扫描范围存在隐患,包名被重命名之后,会导致扫描实现,所以一般我们在需要扫描的包中可以创建一个标记的接口或者类,作为basePackageClasses的值,通过这个来控制包的扫描范围
3.useDefaultFilters有什么用?
可以通过useDefaultFilters、includeFilters、excludeFilters这几个参数来配置类的过滤器,被过滤器处理之后剩下的类会被注册到容器中
4.常见的过滤器有哪些类型?说说你知道的几个
如上。
5.@ComponentScan是在哪个类中处理的?说一下大概的解析过程?
@ComponentScan注解会被ConfigurationClassPostProcessor类递归处理,最终得到所有需要注册的类。
Spring系列第19篇:@import详解(bean批量注册)
1.@Import你用过么?是做什么的?
1.先看Spring对它的注释,总结下来作用就是和xml配置的 <import />标签作用一样,允许通过它引入@Configuration标注的类 , 引入ImportSelector接口和ImportBeanDefinitionRegistrar接口的实现,也包括 @Component注解的普通类。
2.总的来说:@Import可以用来批量导入需要注册的各种类,如普通的类、配置类,完成普通类和配置类中所有bean的注册。
2.@Import使用有几种方式?有何区别?
五/六种:
1.value为普通的类
@Import({Service1.class, Service2.class})
2.value为@Configuration标注的类
3.value为@CompontentScan标注的类
4.value为ImportBeanDefinitionRegistrar接口类型, 这个接口提供了通过spring容器api的方式直接向容器中注册bean。
4.1 定义ImportBeanDefinitionRegistrar接口实现类,在registerBeanDefinitions方法中使用registry来注册bean
4.2 使用@Import来导入步骤1中定义的类
4.3 使用步骤2中@Import标注的类作为AnnotationConfigApplicationContext构造参数创建spring容器
4.4 使用AnnotationConfigApplicationContext操作bean
5.value为ImportSelector接口类型
5.1 定义ImportSelector接口实现类,在selectImports返回需要导入的类的名称数组
5.2 使用@Import来导入步骤1中定义的类
5.3 使用步骤2中@Import标注的类作为AnnotationConfigApplicationContext构造参数创建spring容器
5.4 使用AnnotationConfigApplicationContext操作bean
6.value为DeferredImportSelector接口类型
见下面3
3.DeferredImportSelector是做什么的?他和ImportSelector有什么区别?
DeferredImportSelector是ImportSelector的子接口,既然是ImportSelector的子接口,所以也可以通过@Import进行导入,这个接口和ImportSelector不同地方有两点:
1.延迟导入,我们可以在它导入的类中判断一下容器中是否已经注册了某个bean。后面还会看到@Conditional这个注解,这个注解可以按条件来注册bean,通过@Conditional来结合DeferredImportSelector可以做很多事情。
2.指定导入的类的处理顺序
4.可以介绍介绍一下spring中哪些功能是通过@Import来实现的?
@Enablexxx
5.可以介绍一下spring中是如何解析@Import注解的么?
org.springframework.context.annotation.ConfigurationClassPostProcessor这个类处理的。
@Configuration、@Bean、@CompontentScan、@CompontentScans都是被这个类处理的
Spring系列第20篇:@Conditional通过条件来控制bean的注册
1.@Conditional是做什么的?
@Conditional注解是从spring4.0才有的,可以用在任何类型或者方法上面。
通过@Conditional注解可以配置一些条件判断,当所有条件都满足的时候,被@Conditional标注的目标才会被spring容器处理。
2.@Conditional多个条件是什么逻辑关系?
与
3.条件判断在什么时候执行?
1.配置类解析阶段:会得到一批配置类的信息,和一些需要注册的bean
2.bean注册阶段:将配置类解析阶段得到的配置类和需要注册的bean注册到spring容器中
4.ConfigurationCondition和Condition有什么区别?什么时候使用ConfigurationCondition?
1.ConfigurationCondition使用的比较少,很多地方对这个基本上也不会去介绍,Condition接口基本上可以满足99%的需求了,但是springboot中却大量用到了ConfigurationCondition这个接口。
2.区别:
配置类的处理会依次经过2个阶段:配置类解析阶段和bean注册阶段,Condition接口类型的条件会对这两个阶段都有效,
ConfigurationCondition让条件判断在bean注册阶段才起效。
3.使用场景:
判断bean存不存在的问题,通常会使用ConfigurationCondition这个接口,阶段为:REGISTER_BEAN,这样可以确保条件判断是在bean注册阶段执行的。
5.多个Condition执行的顺序是什么样的?可以配置优先级么?
1.默认情况下会按顺序执行。
2.自定义的Condition可以实现PriorityOrdered接口或者继承Ordered接口,或者使用@Order注解,通过这些来指定这些Condition的优先级。
排序规则:先按PriorityOrdered排序,然后按照order的值进行排序;也就是:PriorityOrdered asc,order值 asc
6.可以介绍一下@Conditional常见的一些用法么?
@Conditional注解是被下面这个类处理的: org.springframework.context.annotation.ConfigurationClassPostProcessor
7.@Conditional使用的3步骤
1.自定义一个类,实现Condition或ConfigurationCondition接口,实现matches方法,个人感觉这个是重点!!!
2.在目标对象上使用@Conditional注解,并指定value的指为自定义的Condition类型
3.启动spring容器加载资源,此时@Conditional就会起作用了
8.总结:
1.@Conditional注解可以标注在spring需要处理的对象上(配置类、@Bean方法),相当于加了个条件判断,通过判断的结果,让spring觉得是否要继续处理被这个注解标注的对象
2.spring处理配置类大致有2个过程:解析配置类、注册bean,这两个过程中都可以使用@Conditional来进行控制spring是否需要处理这个过程
3.Condition默认会对2个过程都有效
4.ConfigurationCondition控制得更细一些,可以控制到具体那个阶段使用条件判断
Spring系列第21篇:注解实现依赖注入(@Autowired、@Resource、@Primary、@Qulifier)
@Autowired - @Qualifier - required=true?
| _ @Primary - required=true?
@Autowired查找候选者可以简化为这样: 按类型找 -> 通过限定符@Qualifier过滤 -> @Primary -> @Priority -> 根据名称找(字段名称或者方法名称)
概括为:先按类型找,然后按名称找
1.通过注解的方式注入依赖对象,介绍一下你知道的几种方式
@Autowired注解
@Qualifier注解
@Resource注解
@Primary注解
@Bean中注入的几种方式
2.@Autowired和@Resource有何区别
1.前者spring的,后者jdk的
2.前者默认先按类型查找,后名称; 后者先按名称找,然后按类型找
3.说一下@Autowired查找候选者的过程
4.说一下@Resource查找候选者的过程
5.@Qulifier有哪些用法?@Qulifier加在类上面是干什么用的?
1.@Qualifier:限定符,可以在依赖注入查找候选者的过程中对候选者进行过滤。
2.单独用在类上
3.@Autowired结合@Qulifier指定注入的bean
4.用在方法参数上
5.用在setter方法上
6.@Primary是做什么的?
@Primary:设置为主要候选者
7.泛型注入用过么?
8.@Bean定义bean时注入依赖的几种方式
硬编码方式
@Autowired、@Resource的方式
@Bean标注的方法参数的方式
9.spring使用这个类处理@Autowired注解: org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
Spring系列第22篇:@Scope、@DependsOn、@ImportResource、@Lazy 详解
1.@Scope是做什么的?常见的用法有几种?
@Scope:用来定义bean 的作用域;
2种用法:第1种:标注在类上;第2种:和@Bean一起标注在方法上
2.@DependsOn是做什么的?常见的用法有几种?
@DependsOn:用来指定当前bean依赖的bean,可以确保在创建当前bean之前,先将依赖的bean创建好;
2种用法:第1种:标注在类上;第2种:和@Bean一起标注在方法上
3.@ImportResource干什么的?通常用在什么地方?
@ImportResource:标注在配置类上,用来引入bean定义的配置文件
4.@Lazy做什么的,通常用在哪些地方?常见的用法有几种?
@Lazy:让bean延迟初始化;
常见3种用法:第1种:标注在类上;第2种:标注在配置类上,会对配置类中所有的@Bean标注的方法有效;第3种:和@Bean一起标注在方法上
Spring系列第23篇:Bean生命周期详解
阶段1:Bean元信息配置阶段
1.Bean信息定义4种方式: API的方式、Xml文件方式、properties文件的方式、注解的方式
2.Spring容器启动的过程中,会将Bean解析成Spring内部的BeanDefinition对象结构。
3.BeanDefinition接口:bean定义信息接口;BeanDefinition接口上面还继承了2个接口:
AttributeAccessor接口:属性访问接口
BeanDefinition继承这个接口,内部实际上是使用了LinkedHashMap来实现这个接口中的所有方法,通常我们通过这些方法来保存BeanDefinition定义过程中产生的一些附加信息。
BeanMetadataElement:
BeanDefinition继承这个接口,getSource返回BeanDefinition定义的来源
4.总结:bean注册者只识别BeanDefinition对象,不管什么方式最后都会将这些bean定义的信息转换为BeanDefinition对象,然后注册到spring容器中。
阶段2:Bean元信息解析阶段
1.Bean元信息的解析就是将各种方式定义的bean配置信息解析为BeanDefinition对象。
2.Bean元信息的解析主要有3种方式:
xml文件定义bean的解析,XML方式解析:XmlBeanDefinitionReader
properties文件定义bean的解析,PropertiesBeanDefinitionReader
注解方式定义bean的解析,AnnotatedBeanDefinitionReader
阶段3:Spring Bean注册阶段
1.bean注册阶段需要用到一个非常重要的接口:BeanDefinitionRegistry,它extends AliasRegistry(别名注册接口)
2.BeanDefinitionRegistry 的唯一实现:DefaultListableBeanFactory,
大家可能看到有很多类也实现了BeanDefinitionRegistry接口,比如我们经常用到的AnnotationConfigApplicationContext,但实际上其内部是转发给了DefaultListableBeanFactory进行处理的,所以真正实现这个接口的类是DefaultListableBeanFactory。
下面要介绍的从阶段4到阶段14,也就是从:BeanDefinition合并阶段到Bean初始化完成阶段,都是在调用getBean从容器中获取bean对象的过程中发送的操作,以下过程均来自于这个方法: org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
阶段4:BeanDefinition合并阶段
1.bean定义可能存在多级父子关系,合并的时候进进行递归合并,最终得到一个包含完整信息的RootBeanDefinition
2.合并BeanDefinition会使用:org.springframework.beans.factory.support.AbstractBeanFactory#getMergedBeanDefinition
3.后面的阶段将使用合并产生的RootBeanDefinition。
阶段5:Bean Class加载阶段
1.这个阶段就是将bean的class名称转换为Class类型的对象。
2.上面得到了Bean Class对象以及合并之后的BeanDefinition,下面就开始进入实例化这个对象的阶段了。
3.Bean实例化分为3个阶段:前阶段、实例化阶段、后阶段;下面详解介绍。
阶段6:Bean实例化阶段(2个小阶段)
1.Bean实例化前阶段
DefaultListableBeanFactory,这个类中有个非常非常重要的字段:
private final List<BeanPostProcessor> beanPostProcessors = new CopyOnWriteArrayList<>();
BeanPostProcessor是一个接口,可以对bean的生命周期进行扩展。
2.Bean实例化阶段
SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors给开发者留个口子
阶段7:合并后的BeanDefinition处理
1.applyMergedBeanDefinitionPostProcessors{调用MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition}
2.postProcessMergedBeanDefinition有2个实现类
2.1 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
在 postProcessMergedBeanDefinition 方法中对 @Autowired、@Value 标注的方法、字段进行缓存
2.2 org.springframework.context.annotation.CommonAnnotationBeanPostProcessor
在 postProcessMergedBeanDefinition 方法中对 @Resource 标注的字段、@Resource 标注的方法、 @PostConstruct 标注的字段、 @PreDestroy标注的方法进行缓存
阶段8:属性赋值阶段(3个小阶段)
1.Bean实例化后阶段,会调用InstantiationAwareBeanPostProcessor接口的postProcessAfterInstantiation这个方法,
该方法返回false的时候,后续的Bean属性赋值前处理、Bean属性赋值都会被跳过了。
2.Bean属性赋值前阶段,会调用InstantiationAwareBeanPostProcessor接口的postProcessProperties方法,
该方法都返回空的时候,表示这个bean不需要设置属性,直接返回了,直接进入下一个阶段。
3.Bean属性赋值阶段
循环处理PropertyValues中的属性值信息,通过反射调用set方法将属性的值设置到bean实例中
PropertyValues中的值是通过bean xml中property元素配置的,或者调用MutablePropertyValues中add方法设置的值。
阶段9:Bean初始化阶段(5个小阶段)
Bean Aware接口回调阶段
Bean初始化前阶段
会调用BeanPostProcessor的postProcessBeforeInitialization方法,若返回null,当前方法将结束。
通常称postProcessBeforeInitialization这个方法为:bean初始化前操作。
Bean初始化阶段
调用InitializingBean接口的afterPropertiesSet方法
调用定义bean的时候指定的初始化方法。
初始化方法最终会赋值给下面这个字段: org.springframework.beans.factory.support.AbstractBeanDefinition#initMethodName
Bean初始化后阶段
调用BeanPostProcessor接口的postProcessAfterInitialization方法,返回null的时候,会中断上面的操作。
通常称postProcessAfterInitialization这个方法为:bean初始化后置操作。
Bean初始化完成操作
阶段10:所有单例bean初始化完成后阶段
所有单例bean实例化完成之后,spring会回调下面这个接口: SmartInitializingSingleton
阶段11:Bean的使用阶段
这个阶段就不说了,调用getBean方法得到了bean之后,大家可以随意使用,任意发挥。
阶段12:Bean销毁前阶段
1.触发bean销毁的几种方式:
1.调用org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#destroyBean
2.调用org.springframework.beans.factory.config.ConfigurableBeanFactory#destroySingletons
3.调用ApplicationContext中的close方法
2.Bean销毁阶段会依次执行
1.轮询beanPostProcessors列表,如果是DestructionAwareBeanPostProcessor这种类型的,会调用其内部的postProcessBeforeDestruction方法
2.如果bean实现了org.springframework.beans.factory.DisposableBean接口,会调用这个接口中的destroy方法
3.调用bean自定义的销毁方法
阶段13:Bean销毁阶段
Spring系列第24篇:父子容器详解
1.什么是父子容器? 为什么需要用父子容器? 父子容器如何使用?
1.spring是父容器,包含dao、service层,springmvc是自容器,只含controller层。
2.通常我们使用springmvc的时候,采用3层结构,controller层,service层,dao层;父容器中会包含dao层和service层,而子容器中包含的只有controller层;这2个容器组成了父子容器的关系,controller层通常会注入service层的bean。
3.采用父子容器可以避免有些人在service层去注入controller层的bean,导致整个依赖层次是比较混乱的。
4.父容器和子容器的需求也是不一样的,比如父容器中需要有事务的支持,会注入一些支持事务的扩展组件,而子容器中controller完全用不到这些,对这些并不关心,子容器中需要注入一下springmvc相关的bean,而这些bean父容器中同样是不会用到的,也是不关心一些东西,将这些相互不关心的东西隔开,可以有效的避免一些不必要的错误,而父子容器加载的速度也会快一些。
2.springmvc中只使用一个容器是否可以?
只使用一个容器是可以正常运行的。
Spring系列第25篇:@Value【用法、数据来源、动态刷新】
1.@Value的用法
@Value可以标注在字段上面,可以将外部配置文件中的数据,比如可以将数据库的一些配置信息放在配置文件中,然后通过@Value的方式将其注入到bean的一些字段中
2.@Value数据来源
1.来源于上面说的配置文件
2.也可以将配置信息放在db或者其他存储介质中,容器启动的时候,可以将这些信息加载到Environment中,@Value中应用的值最终是通过Environment来解析的,所以只需要扩展一下Environment就可以实现了。
3.@Value动态刷新的问题
1.动态@Value实现的关键是@Scope中proxyMode参数,值为ScopedProxyMode.DEFAULT,会生成一个代理,通过这个代理来实现@Value动态刷新的效果,这个地方是关键。
2.springboot中的@RefreshScope注解源码,和我们上面自定义的@RefreshScope类似,实现原理类似的。
Spring系列第26篇:国际化详解
1.Spring中国际化怎么用?
1.spring中国际化是通过MessageSource这个接口来支持的,内部有三个常用方法来获取国际化信息
String getMessage(String code, @Nullable Object[] args, @Nullable String defaultMessage, Locale locale);
String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException;
String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException;
2.常见3个实现类:
ResourceBundleMessageSource
这个是基于Java的ResourceBundle基础类实现,允许仅通过资源名加载国际化资源
ReloadableResourceBundleMessageSource
这个功能和第一个类的功能类似,多了定时刷新功能,允许在不重启系统的情况下,更新资源的信息
StaticMessageSource
它允许通过编程的方式提供国际化信息,一会我们可以通过这个来实现db中存储国际化信息的功能。
3.Spring中使用国际化的3个步骤
步骤一:创建国际化文件
步骤二:向容器中注册一个MessageSource类型的bean,bean名称必须为:messageSource
步骤三:调用AbstractApplicationContext中的getMessage来获取国际化信息,其内部将交给第二步中注册的messageSource名称的bean进行处理
2.国际化如何处理资源文件变化的问题?
spring国际化这块有个实现类,可以检测到配置文件的变化,就可以解决你这个问题
3.国际化资源配置放在db中如何实现?
StaticMessageSource支持硬编码的方式配置国际化信息。
4.自定义bean中使用国际化
只需实现MessageSourceAware这个接口,spring容器会自动调用这个方法,将MessageSource注入,然后我们就可以使用MessageSource获取国际化信息了。
27.观察者模式
实现方式:事件驱动模型
具体实现:事件源 + 事件 + 监听器
source ApplicationEvent ApplicationLister
使用: 事件广播器 + 事件广播器的简单实现
ApplicationEventMulticaster SimpleApplicationEventMulticaster