图1
调用refresh() 方法,来解析注解。
图2
执行已经注册的后置处理器.
图3
726行gentBeanFactoryPostProcessors() 方法,返回的List 是 是程序员 通过调用AnnotationConfigAppLicationContext.addBeanFactoryPostprocessor() 方法手动添加的。如果没有添加这个list就是空。调用invokeBeanFactoryPostProcessors()方法,图7
图4
图5
图6
图7
根据图3知道gentBeanFactoryPostProcessors() 方法为空,因为没有手动调用AnnotationConfigAppLicationContext.addBeanFactoryPostprocessor() 所以benFactoryPostProcessors为空。 定义了存放BeanFactoryPostProcessor 的list regularPostProcessors,和存放BeanDefinitionRegistryPostProcessor 的list registryProcessorsList 因为gentBeanFactoryPostProcessors() 获取的list为空,所以这两个list都为空。
遍历postProcessorNames ,把每一个ppName放在prrocessedBFeans中。
这个不重要,是排序的。和上面差不多。为什么要写两遍啊。因为通过判断 if(!processedBeans.contains(ppName)) ,有可能这个是在之后新添加的ppName,所以processedBeans中没有的。
为什么这里在处理BeanFactoryPostProcessors的i时候的还要在处理一次BeanDefinitionRegistryPostProcessor。因为如果有一些类继承了BeanDefinitionReistryPostProcessor类,所以要再执行一下他的父类。 例如ConfigurationClassPostProcesstor的类就是继承了BeanDefinitionRegistryProcessor类。 registryProcessors中包含的是BeanDefinitionRegistryProcessor 。regularPostProcessors的list中包含了BeanFactoryPostProcessors的类。
图8
图9
ConfigurationClassPostProcessor 类继承BeanDefinitionRegistryPostPrpcessor 类。 所以 调用的ConfigurationClassPostProcessor 类的postProcessBeanDefinitionRegistry()方法。
图10
图11
图12
获取那beanDefinitionMap中6个对象的bean中的名字, 遍历,获取他们的bd, 判断bd 的confinurationClass属性是full或者lite 则认为已经处理过。
检查注解是不是@Configuartion 或者 @Component @ComponentScan,@Import @ImportResource 把db添加到configCandidates的list中。
排序不重要.
bd的名称生成器,如果有就利用,没有就用spring默认.
把 加了configCandidates的list去重得到 cadidataes来保证 Appconfig类只处理一次。
图13-0
图13
图14
图15
就是判断当前这个注解类有没有被其他类Imported.如果是证明就已经存在了。
把configClass转换成sourceClass。调用doProcessConfigurationClass()。 .
图16
处理内部类 就是在AppConfig类里的内部类.不重要,一般没有用到,propertySources下次课讲。
处理componentScan注解。为什么要循环,因为componentScan注解是一个数组。图21.
parse()方法。图17componentScan ='com.luban'
处理Import 有3中情况,第一中是ImportSelector,第二种是ImportBeanDefinitionRegistrar ,第三种情况是普通类。图36 应用实例1,图37应用实例2 图38 源码分析。
图17
new ClassPathBeanDefinitionScanner () 这个是真正解析@componscan注解的scan对象。而不AnnotationConfigApplicationContext的scanner对象图27 。那什么时候用呢,图28会用到AnnotationConfigApplicationContext的scanner对象.80行得到名字生成器,生成名字放到beanDefinitionMap中的的名字。85行讲到web的时候才讲。
遍历当中的过滤 。根据includeFilter 和excludeFilter 不同设置不同的scanner中。在扫描中过滤。是否懒加载默认不是懒加载。拿到所有包的名字
调用核心代码doScan()代码
图18
循环包,调用findCandidateComponents(basePackage) 利用asm技术读取class文件。 findCandidateComponents 调用scanCandidateComponents 返回的是ScannedGenericBeanDefinition ( ScannedGenericBeanDefinition extends GenericBeanDefinition extends AbstractBeanDefinition) ,所以为这个bd设置默认值。
如果加了注解的就处理这个注解。图34
加入到beanDefinitionMap中。图35
图19
图20
利用asm技术来读取文件 并转换成resources文件。
ScannedGenericBeanDefinition 的继承关系图29 ScannedGenericBeanDefinition extends GenericBeanDefinition extends AbstractBeanDefinition
图20-0
图21
图22
是不是接口,是不是能被创建,如果是接口永远不可能被放到beanDefinitMap中。
图23
图28
图29
图30
图31
spring 为bd设置默认值。lazy默认读取的是appconfig 的值 ,autowireMode 默认是autowire_no no的时候首先会bytype,然后再回byname
图32
图33
图34
判断每一个bd,判断如果bd 所对应的类中加了@Lazy的注解,取出注解的值 覆盖之前的默认值,如果没有就用之前的默认值。
图35
图36
ImportSelector 实例1.
图37
ImportSelector 实例2 。动态的实现(如果加了@EanbleLuabn注解会有动态代理,如果没有加不会有动态代理 )动态代理。
图38
首先判断这个类(MyImportSeletector)是不是实现了ImportSelector接口,得到他的Calss对象,635行调用它selectImports方法。得到类的全类名。依次把数组的类名转换为SourceClass类,然后,放在List中返回,递归调processImports()方法处理。
processImports()第一次调用的的时候,第三参数importCandidates获取的是 @Impolrt(MyImportSeletector.class) 的value值也就是参数为MyImprotSelectector类,这个类的接口 是Selector,所以 走的是 if(candidate.isAssignable(ImportSelector.class)){} 这个分支。第二次不用获取,直接把IndexDao3的全类名传进去,他既不是实现selector接口 也不是实现ImportBeanDefinitionRegistrar的接口所以走的else()分支。图15调用 processConfigurationClass() 。把indexDao3的全类名存在configurationClasses的map中。.
图39
图40
图41
图42
把这个类名数组遍历并转换为soruceClsass类型添加到annotatedClasses的List中。
图43
图44
图45
图46
图47
图48
图49
图50
图51
configurationClassPostProcessors类中postProcessBeanFactory()方法。
图51-0
如果加了@Configuration 会使用cglib动态代理 打断点是xxx.proxy对象,如果不加不会使用 打断点是Appconfig对象。如果加了Configuration indexDao1就会被调用一遍 dao1-init 会打印一遍,如果没有加会调用两遍 dao1-init 会打印两遍。
图52
判断是不是一个全注解的类 full 也就加了@Configuration 就会放在configBeanDefs的map中。
图53
图54
当前类做为父类。enHancer.SetSuperclass(configSuperClass); 那为什么又要增强一个EnhancedConfiguration这样的接口呢,因为这个接口继承了BeanFactoryAware 。BeanFactryAware又继承了Aware ,并实现了SetBeanFactory()方法。那我们产生的代理对象就能够得到BeanFactory对象。那问题来了,为什么要得到这个BeanFactroy对象。图59有详细说明。
enhancer.setStrategy()是cglib生成类的一个策略。图60 。添加一个方法的过滤器,callbackFilter()。 参考例子图63.问题来了为什么不用jdk动态代理呢,因为jdk是基于接口的,appconfig不一定是实现接口的。
图55
图56
图57-0
图57-1
判断返回的是不是一个factoryBean ,对返回的对象再次进行代理,enhanceFactoryBean() 图图57-3。 为什么要进行两次代理呢,图 57
图57-2
图57-3
图57-4
图57-5
第一次代理为 getObject() 方法,第二次代理为new IndexDao2代理。
图57-6
图57-8
自动注入一个beanFactory 。类似调用setBeanFactory()方法。
图58
图59
为什么要得到这个BeanFactroy对象。目标对对象 可以不可以拿到原始对象,可以如例子说,new IndexDao1() ,每调一次就会new一次,无法满足spring的单例要求。 那怎么生成单例的呢,只会产生一个对象呢,给目标对象做一个代理生成代理类,然后在代理类中改变他的行为,例如可以先从容器中获取,如果没有就new 一个,如果有return。 代理类直接可以通过factory.getBean()方法来获取可以用的类。
图60
spring扩展实现,继承了DefaultGeneratorStrategy . declare_field声明一个属性。 为什么要声明一个属性呢,
图61
默认生成策略是DefaultGeneratorStrategy类 ,有生成字节码的,有生成类的。
图62
因为 生成的代理类 appconfigProxy 一定是继承Appconfig 实现 BeanFactory方法的。 肯定有个属性为BeanFactory 。spring 为这个代理类生成的属性。
图62-0
图63
o 为目标对象,method 为目标方法,methodProxy为代理方法。
利用cglib成功拦截目标对象。
cglib是操作字节码基于父类来的。是继承。