1、spring的IoC Container, Events, Resources, i18n, Validation, Data Binding, Type Conversion, SpEL, AOP.中章节1.10.9生成静态组件索索引会加快spring扫描速度。
2、@Qualifier(“xxx”)这个注解可以指定名字@Autowired注入
3、@Autowired不是自动注入,是手动注入。其中实现"implements BeanFactoryPostProcessor"重写其中的"postProcessBeanFactory",从"ConfigurableListableBeanFactory"中取出要注入类的类,打印此getAutowireMode()。能看出这个注解不是自动注入。
其中spring的4种自动注入模型于章节"IoC Container, Events, Resources, i18n, Validation, Data Binding, Type Conversion, SpEL, AOP."1.4.5有4中装配模式byType,byName,no,这三种的AutowireMode分别是 2,1,0;@Autowired所打印出来的是0,也就是说Autowired是一个注解他跟spring 的4中注入模型没一点关系。,,如果一个类中有且只有一个构造方法,
4、@DependsOn控制bean加载顺序
5、如何把对象放入spring 中, @Bean ,AnnotationConfigApplicationContext.getBeanFactory、implements FactoryBean(类出产生过程交于自己控制)与@Component区别是Component是spring控制这个类的产生过程。
动态代理
代理----增加---改变(目标对象的动态代理就是去改变这个对象)
心有多大地有多大。动态代理就是创建一个我们想要的对象,就是生成一个java文件然后编译成我们java的class文件
@Scope 原型
每次获取都会拿到不同的对象。从源码来说单例是被缓存了,原型没有。
beanDefiniton
bean是有spring 管理----完整的声明周期,当spring容器启动后,扫描出来符合spring的bean,然后验证能不能实例化初始化声明周期,spring中使用 beanDefiniton 来描述一个bean,对bean进行建模 。beanDefiniton中的属性能对应xml中的属性。
对象是new出来的是编译出来的。
一个bean一定是一个对象,一个对象不一定是个bean
Spring容器 第一步扫描,第二步解析就有beanDefiniton 对象存于map中,第三步验证,第四步遍历map得到beanDefiniton 实例化spring扫描完之后执行spring的BeanDefinitionRegistryPostProcessor------ConfigurationClassPostProcessor,将对应的class变成beanDefiniton 然后放到spring存放beanDefiniton 的map中。
spring容器 中有存beanDefiniton 的map,有一个单例池map。
spring提供AttributeAccessor提供对BeanDefinition元数据操作的api,但是并没有直接让程序员去操作而是遵循一个开闭原则(BeanMetadataAttributeAccessor)。
BeanDefinition有抽象类是为了扩展,这个抽象类是个模板。
RootBeanDefinition-------可以作为父BeanDefinition出现—真实的BeanDefinition------不能作为子BeanDefinition出现(本身是一个父类在设置为子类会报错)。一般来冲当一个模板
ChildBeanDefinition通过构造方法设置的,parentName是最大的局限性。不能作为父类
GenericBeanDefinition可以取代ChildBeanDefinition但是取代不了RootBeanDefinition(其中有个merge方法必须是RootBeanDefinition接收)。
所有在xml定义出来bean最后的bean都是GenericBeanDefinition;
AnnotatedGenericBeanDefinition主要用来解析AppConfig加了@Configuration注解的
ScannedGenericBeanDefinition 用来描述标注 @Component 注解的 Bean
Spring在完成扫描和解析(类—beanDefiniton)用到策略模式invokeBeanFactoryPostProcessors
Mybatis的@MapperScan注解中的@import的MapperScannerRegistrar先放在spring存放的ImportBeanDefinitionRegistrar中,到了某个时机执行ImportBeanDefinitionRegistrar中registerBeanDefinitions方法。(spring是注册一个bd,然后通过spring 那个执行策略,才把对应的dao什么扫描出来)
spring-mybatis在完成Mapper扫描时候将自动注入设置为了bytype使用@Autowired注解注入Mapper时有重大意义(上图);
1.Bean工厂后置处理器 spring先执行程序员通过API提供的addBeanFactoryPostProcessor();在执行spring内置的和程序员提供的(实现PriorityOrdered);在执行程序员提供没有特点的实现的BeanDefinitionRegistryPostProcessor---------postProcessBeanDefinitionRegistry;
2、BeanFactoryPostProcessor 执行父类的,先执行实现了BeanDefinitionRegistryPostProcessor的
BeanFactoryPostProcessor ----- postProcessBeanFactory;在执行实现BeanFactoryPostProcessor ----- postProcessBeanFactory
@Configuration是使用cglib代理,为了保证产生一个代理对象,(Bean有多个相互想用时候使对象只被创建一次)
Spring循环引用
单例(set的变体)–不能以构造方法注入,spring默认是支持循环依赖的,循环依赖是可以关闭的。
创建bean的时候有个判断是不是开启循环依赖,是单例且是不是true(Spring默认情况下设置为true)且bean正在创建。
spring的三级缓存从二级拿出来比较麻烦三级是一个工厂,循环依赖—工厂产生一个符合确实需求的当前对象
Autowired和Resouse分别使用不同的后置处理器
@Autowired------AutowiredAnnotationBeanPostProcessor
@Resouse--------CommonAnnotationBeanPostProcessor
BenaPostprocessor---------bean的后置处理器-----干预bean 的初始化和实例化过程
AOP
核心是继承BeanPostprocessor的postProcessAfterInitalization
Aspect-----切面
Join point—连接点–aop–代理—增强对象\类–某个方法
ABC----是public的第一个String类型的参数
ABC----是public的String类型的参数
pointCut----切点------某一类型连接点的集合
advice—通知
{
1、logic----逻辑
2、执行时机,在方法之前还是之后
}
电影–高清----改变----打码
target----目标对象
porxy-----代理对象
weaving—织入-----过程
登录-----需要记录时间、权限认证等横切问题抽象出来一个类就是切面
sping代理对象 单例是在容器初始化产生的,原型和懒加载是在getBean的时候
================================
一spring通过构造方法实例化bean的原理
首先实例化这个对象-----推断构造方法;
自动注入—通过构造方法自动;
手动注入—
在第一次调用后置处理器;
如果没有提供改造方法----可用构造方法为null–也就是没有提供
如果提供默认构造方法为一个-----可用也是为空–如果为空会调用默认无参数构造方法
如果提供多个构造方法,spring都觉得为空(spring不知道要使用那个没有合适的所以为空)选择最优的构造方法
如果提供了多个 加入@Autotrue 返回这个;
如果提供了多个 且加入@Autotrue异常;
如果提供了多个 且加入@Auto==false 返回多个构造方法然后再去推断;
如果提供一个构造方法–带参数则会使用这个
自动注入
- spring中的自动注入是基于xml,在xml中加入default-autowrie:bytype、byname,且提供了set方法;
- @Autowried(可以说是手动注入) type(是通过类型找,而不是byType) name(是通过名字找,而不是byName),spring提供的,由AutowiredAnnotationBeanPostProcessor处理器解析
- @Resoure(可以说是手动注入) name(是通过名字找,而不是byName) type(是通过类型找,而不是byType) ,由CommonAnnotationBeanPostProcessor后置处理器解析
- spring的注入方式有几种{
2种 构造方法、set方法、也可以可以从spring容器中取出来在放进去
3种
} - 注入模型-----no、byType(通过类型找到然后通过set方法注入)、byName通过名字找到然后通过set方法名字注入,constructor推断构造方法解析构造方法的参数
- 被注解lockup加的方法上面,可以使scope对象每次都不一样+
- spring当时属性注入和初始化回调,属性在前
- 4种注入模型可以通过implements BeanFactoryPostProcessor,然后取出对应的bean,然后可以通过设置AutowireMode属性来设置当前bean使用什么注入
- Autowried和4中注入模型本质上的区别,注入模型需要set方法,Autowried是通过fileld.set
- 容器回调方法 implements SmartLifecycle; start(容器没启动后搞事情,),stop(),isRunning(),isAutoStartup(将true开启会自动调用),stop(Runnable callback)(如果调用了callback.run()会立马停止),getPhase(顺序 越小越先)
- @PostConstruct 生命周期初始化回调方法会在属性填充后运行
- 如果service有多个实现类可以加个注解@Qualifier(“名字”)
- 当前类要在某个类之前实例化@DependsOn(“名字”)
- implements FactoryBean
之所以能够注入是因为自动装配的原因,有且只有一个构造方法。
动态代理
- 对象存在即合理。
- 通俗点说,电影>>>>>无码>>>>>有码,就是被代理了,所以代理可以被称为是改变,因为不一定都是增强。
- 动态代理,一个生成的.java文件被load到虚拟中成为一个.class文件
BeanDefinition
- spring当中的class
- BeanDefinition就是来定义一个bean(建模)
- BeanDefinition中的常量是为了快速把模型建起来
- BeanDefinition所有的属性都能在xml中找到与之对应
- 容器中的拿BeanDefinition==BeanDefinition map.()
- spring容器一切ApplicationContext对象子类都可以称为容器(代码角度),有spring各种组件组成的(理论)例如单例池。
- 其中有一个属性是不是抽象类(可以设置一个BeanDefinition为抽象类作为模板)。BeanDefinition是一个接口
- RootBeanDefinition-------可以作为父BeanDefinition出现—真实的BeanDefinition------不能作为子BeanDefinition出现(本身是一个父类在设置为子类会报错)。一般来冲当一个模板
- ChildBeanDefinition通过构造方法设置的,parentName是最大的局限性。不能作为父类
- GenericBeanDefinition可以取代ChildBeanDefinition但是取代不了RootBeanDefinition(其中有个merge方法必须是RootBeanDefinition接收)。
所有在xml定义出来bean最后的bean都是GenericBeanDefinition;
Bean声明周期
- bean的声明周期初始化实在spring扫描的时候开始的。从spring 扫描开始
在spring拿ConfigurationClassPostProcessor会去判断这个bean是否存在容器如果不存在就去实例化。 - spring启动的时候开天辟地5bd
- spring在执行BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry会会去扫描,在ConfigurationClassPostProcessor这个实现类中
在下面图片这一步判断是不是全配置类,根据ConfigurationClassUtils下CONFIGURATION_CLASS_FULL和CONFIGURATION_CLASS_LITE查看.
循环依赖
默认支持循环依赖,在springbean 的声明周期某个部分允许不允许循环依赖,spring中有个属性默认是true
getBean
AOP
在spring中是通过后置处理器BeanPostProcessor中的postProcessAfterInitialization产生的代理对象。
spring代理对象什么时候产生-------spring bean什么时候产生
如果是单例的初始化产生
如果是原型的在getBean时候产生
如果是懒加载是在getBean时候产生
一个被扫描的类并不是自动注入
后置处理器
bean工厂后置处理器能干预初始化
bean后置处理器可以干预bean的实例化过程
初始化
实例化{
之前的后置处理器-----场景第一次调用后置处理器
}
第一次调用后置处理器
判断这个类要不要做代理,如果要做代理将此类放入map
中
第二次调用后置处理器
实例化对象,一般情况下项目中都是单例,需要解析对象,解析这个对象如何创建----反射----调用构造方法,这时候spring就推断要使用那个构造方法。spring推断构造方法----推断-什么样子的构造方法–就是为了实例化一个bean
//如果是自动注入的通过构造方法注入,就把所有符合的拿出来
//如果是手动注入,多个构造方法没有指定要推断那个构造方法,那就不推断,如果只有无参构造也不推断,直接调用无参构造
其中手动注入是调用后置处理器SmartInstantiationAwareBeanPostProcessor中的determineCandidateConstructors方法第一次推断。
手动注入:{
1、如果没有提供构造方法可用的构造方法就没有返回null
2、如果提供了默认构造方法有且只有一个返回null不
3、如果提供多个构造方法spring就会迷茫不知道用那个返回null不
4、如果提供多个构造方法且有个方法提供@Autowired(true)就用这个构造方法
5、如果提供多个构造方法有多个@Auto(true)抛出异常
6、如果提供一个构造方法带参数则用这个}
为null 不是自动装配调用默认无参构造
返回不为空或者自动装配,还要继续推断构造方法推断出最优的构造方法
自动装配
1、如果只有一个构造方法,没有传参,通过解析也没用解析到带有参数的构造方法(无参构造的时候)
2、当提供多个,spring先确认实例化的参数要几个,然对构造方法进行排序(排序方式看修饰符 长度 参数的精准度),然后进行推断首先拿到的构造的方法参数要大于spring确认参数的个数,然后计算差异值找到最合适的构造方法,如果发现循环出来模糊不清参数差异值一样的则的八成调用倒序排列的第一个。
sping先去扫描然后实例化bean,实例化这个bean先去推断构造方法,spring自己创建对象使用,查看有没有提供工厂方法
第三次调用后置处理器
通过后置处理器来应用合并之后的BeanDefinitionPostProcessors,应用BeanDefinitionPostProcessors就是把BeanDefinitionPostProcessors里面的信息拿出来,信息指的需要注入的属性
对于spring来说需要拿到父类的信息,合并后的bean对应的BeanDefinition转换为RootBeanDefinition
spring在扫描的时候在根据类型找BeanDefinitionRegistryPostProcessor名字的时候完成了合并(因为在取名字的时候不能拿原始的BeanDefinition对象,因为有父类所以在这里完成了合并),spring是在验证bean是否合理之前合并一次BeanDefinition(先从缓存中取,没有再去合并),然后再去解析对象
spring 的合并是遍历子类的信息set给父类
作用
CommonAnnotationBeanPostProcessor.postProcessMergedBeanDefinition
1、调用父类的方法查找所有生命周期回调方法–初始化和销毁
2、前类所有要注入的点(方法、属性等找出这些属性方便填充属性) @Resource
AutowiredAnnotationBeanPostProcessor.postProcessMergedBeanDefinition
1、前类所有要注入的点(方法、属性等找出这些属性方便填充属性) @Autowired
第四次调用后置处理器
提前暴露工厂
第五次、第六次调用后置处理器
bean的属性填充