配置类的full与lite&@Configuration解析&@componentScan解析注册&涉及AOP代理模式的
2020-06-19 10:52:35 1 举报
登录查看完整内容
配置类的full与lite
作者其他创作
大纲/内容
获取beanDefinitionHolder的:targetDefinition(beanDefinition)、originalBeanName(即beanName),targetBeanName(scopedTarget.+BeanName的值)
beanNameGenerator获取beanName
this.registry.containsBeanDefinition(beanName)
运行beanDefinition覆盖,allowBeanDefinitionOverriding设置为false,如果beanDefinitionMap有重复的key存在时就会抛异常,就是由这个参数决定的。如果把这个参数设置为true,那么就允许相同key情况下beanDefinition实例的覆盖
非静态方法
ScannedGenericBeanDefinition:存储@Component、@Service、@Controller等注解注释的类AnnotatedGenericBeanDefinition:存储@Configuration注解注释的类
获取指定的bean的name,如果没指定,则用方法名作为beanName
只有@Component修饰的才会解析后直接注册到容器,其他的这几种都是后面的方法来进行注册
不处理
@EnableAspectJAutoProxy 开启AOP
处理@Imports修饰的类
相互不矛盾,spring说的是使用spring的aop默认是JDK动态代理,源码中设置一些类的默认代理模式是其他动态代理与springAOP使用时是无关的。
对不同的BeanDefinitionHolder.getBeanDefinition()进行区分判断
将这个beanDefinitionName和原来的beanDefinitionNames全加到一个新集合作为beanDefinitionNames
具体实现
如果堆栈中没有
创建动态代理对象
处理@Component的类
获取动态代理类型
处理@PropertySource
将targetDefinition的自动装配的属性赋值给proxyDefinition
setUniqueFactoryMethodName(methodName)
字节码创建方法bean来保证了单例
beanDefinition instanceof AbstractBeanDefinition
BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法
@Import类型分类
通过传来的beanName,到beanDefinitionMap中获取对应的beanDefinition
没有
findCandidateComponents(basePackage);
判断是否已经被标记开始创建
核心方法二:加载并注册
对beanDefinition进行判断
不为null,赋值为existingDef
对获取的beanDefinition集合中每一个beanDefinition进行处理
①@Import②实现ImportSelector接口,实现selectImports返回的要导入的Import类集合③实现ImportBeanDefinitionRegistrar接口,进行自定义注册导入的类④要导入的常规组件类
返回最终的beanDefinition集合
PropertySourceFactory
注册
加载@ImportedResources指定配置文件所配置的bean,并注册到容器
同一个文件扫描两次newDefinition.getSource() != null && newDefinition.getSource().equals(existingDefinition.getSource())
parse(Set configCandidates)
@Import(AspectJAutoProxyRegistrar.class)public @interface EnableAspectJAutoProxy { /** * Indicate whether subclass-based (CGLIB) proxies are to be created as opposed * to standard Java interface-based proxies. The default is {@code false}. */ boolean proxyTargetClass() default false;
添加到环境配置类的属性中
加载注册@bean修饰的方法bean到容器
if (enableAspectJAutoProxy != null) { if (enableAspectJAutoProxy.getBoolean(\"proxyTargetClass\")){ AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); } if (enableAspectJAutoProxy.getBoolean(\"exposeProxy\")) { AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); }
public ScopedProxyFactoryBean() {\t\tsetProxyTargetClass(true);\t}
显式注册重写bean-->已存在的beanDefinition是注解注入的类,比如@component,@service修饰的类!(existingDefinition instanceof ScannedGenericBeanDefinition)
创建ConfigurationClassBeanDefinition,对相关属性进行赋值
如果有@Order修饰的,按照指定的顺序排序
实现PriorityOrdered的beanFactory后置处理器
创建并返回beanDefinitionHolder
AnnotatedBeanDefinition
如果是@Cconfiguration修饰的设置为full
synchronized (this.beanDefinitionMap)
后置处理器处理beanDefinition:postProcessBeanDefinition
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
spring默认使用JDK,原因可能是jdk动态代理会随着JDK版本迭代而更新,但是有时候会出现类型转化异常,所以springboot的2.x版本设置了默认类型为CGLIB,只可以通过配置项spring.aop.proxy-target-class=false来进行修改,proxyTargetClass配置已无效。
https://docs.spring.io/spring/docs/5.2.0.RELEASE/spring-framework-reference/core.html#aop-introduction-proxies
excludeFilters
最终返回beanDefinition集合作为解析的结果
@ComponentScan扫描bean,返回@ComponentScan修饰的beanDefinitionHolder集合,并将bean注册到容器
处理接口的default修饰的方法
将definitionHolder代理对象放到beanDefinition集合
初始化bean设置为默认值(ClassPathBeanDefinitionScanner的BeanDefinitionDefaults,eg:setAutowireMode(defaults.getAutowireMode());),比如lazyInit,AutowireMode,DependencyCheck(配置的<bean depends-on=\"...\"/>),InitMethodName等基础属性。
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR=org.springframework.context.annotation.internalConfigurationBeanNameGenerator内部可配置的bean名称生成器
判断是否被@Conditional修饰
解析条件装配配置,按条件装配
返回true
//获取该类的注解 metadata = metadataReader.getAnnotationMetadata();
includeFilters
NO
递归调用
为null
没有属性
isCandidateComponent
proxyDefinition设置proxyTargetClass属性为flase
循环执行
解析所有的beanDefinition,且将@Component修饰的beanDefinition注册到容器中
resetBeanDefinition(beanName);
@Dependson与@ConditionalOnBea的区别
处理公共beanDefinition注解AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
核心方法一:解析全过程
targetDefinition添加属性AutoProxyUtils.preserveTargetClass : trueproxyTargetClass属性不用设置,因为默认true
判断ConfigurationClass是否需要跳过
注册配置类
获取工厂
existingDefinition不为空,且新注册的bean是单例bean
@ComponentScan的属性excludeFilters指定哪些类不被扫描到,includeFilters指定哪些类被扫描到eg:@Configuration@ComponentScan(value = \"指定包名\
JDK动态代理
processConfigBeanDefinitions(BeanDefinitionRegistry registry)
递归处理beanDefinition
true
指定路径下所有的class文件Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
DependsOn源码注释
通过import导入的类都保存在importRegistry中,需要移除ConfigurationClassthis.importRegistry.removeImportingClass(configClass.getMetadata().getClassName())
执行实现importselector的类重新实现的selectImports方法,并将返回的需要导入的beanName集合注册到容器中
//增强@Configuration修饰的配置类 enhanceConfigurationClasses(beanFactory);
通过beanName到beanDefinitionMap查,没有已存在的beanDefinition
获取@bean修饰的属性值
将targetDefinition的基础属性赋值给proxyDefinition
角色级别为0:用户自己定义的bean。角色级别为1:外部配置类角色级别为2:Spring内部定义的bean
existingDefinition != null
配置类中的@bean获取bean实例时
静态工厂方法
@Dependson注解是在另外一个实例创建之后才创建当前实例,也就是,最终两个实例都会创建,只是顺序不一样@ConditionalOnBean注解是只有当另外一个实例存在时,才创建,否则不创建,也就是,最终有可能两个实例都创建了,有可能只创建了一个实例,也有可能一个实例都没创建
加到扫描到的类的beanDefinition集合中
AbstractBeanDefinition
解析@Bean修饰的方法bean
注解设置setBeanClass否则设置setBeanClassName
是
收集到这个集合中Collection<SourceClass> memberClasses = sourceClass.getMemberClasses();
registerBeanDefinitions
配置类增强成CGlib类型
创建beanDefinition加载器
processConfigurationClass(ConfigurationClass configClass)
refresh()方法中的invokeBeanFactoryPostProcessors(beanFactory);详解
处理@ComponentScan
ConfigurationClassPostProcessor#postProcessBeanFactory
@Conditional修饰的需要跳过
ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry
到conditionEvaluator获取,按指定条件进行装配
Y
将ImportRegistry注册为bean以支持ImportAware@Configuration类
核心解析
registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass)
org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForBeanMethod
//将targetDefinition自动装配属性关闭的targetDefinition.setAutowireCandidate(false); targetDefinition.setPrimary(false);
校验通过的
检查工厂的bean创建阶段是否已经开始
是配置类
AspectJAutoProxyRegistrar
loadBeanDefinitionsForBeanMethod(beanMethod);
((ConfigurableEnvironment)this.environment).getPropertySources()
this.reader.loadBeanDefinitions(configClasses);
不用解析,返回false
是full?
AOP
如果都不满足条件
这个方法可以借鉴,写一些包扫描的功能。最底层实现包扫描的方法:org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#scanCandidateComponents底层获取指定路径下所有的class文件的方法org.springframework.core.io.support.PathMatchingResourcePatternResolver#getResources
N
对beanDefinition进行校验,验证并准备为该bean定义的方法覆盖,检查是否存在具有指定名称的方法
所以特别注意spring中ScopedProxyFactoryBean默认是使用CGlib动态代理,而不是大部分的spring默认动态代理为JDK动态代理
1.移除 这个bean的合并beanDefinition2.从单例缓存中移除相应的bean(如果有的话)3.通知所有后处理器指定的bean定义已重置。4.重置所有将 这个bean作为父bean的beanDefinition(递归地)
根据注册器,beanDefinitionHolder,scopeMetadata,获取definitionHolder的动态代理对象
获取internalConfigurationBeanNameGenerator的单例对象beanName生成器
获取初始beanDefinition
实现示例:RootBeanDefinition rootBeanDefinition=new RootBeanDefinition(Lj.class); registry.registerBeanDefinition(\"lj\
转换成RootBeanDefinition
full类型的将执行
根据beanDefinition及其元数据metadata,获取这个beanDefinition的基础属性的注解信息,比如Lazy,@Primary(配置多个bean时,指定默认优先选择注入哪个),DependsOn(控制bean加载顺序),Role(bean的角色,0是用户自定义,1是外部配置的bean,2是spring内部bean),Description(bean的描述)
已存在的beanDefinition角色级别低于新的beanDefinition
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
allowBeanDefinitionOverriding为false
直接返回beanDefinitionHolder
保存bean定义的注册类如果含有其对应的beanName:this.registry.removeBeanDefinition(configClass.getBeanName());
((AbstractBeanDefinition) beanDefinition).validate();
basePackages:就是@ComponentScan的值,即指定的扫描的包名路径
以前的版本是直接移除beanName,现在是先判断是否处于启动注册阶段,再进行相应的移除
retrieveBeanMethodMetadata
removeManualSingletonName(beanName);
setFactoryBeanName
configCandidates.sort
@component,@Import,@ImportResource或方法上配置了@bean等等其他注解设置为lite
找到指定路径下所有被@Component修饰的类
比如配置数据源
处理内容
判断是否与配置类的beanName一样,冲突了则抛出BeanDefinitionStoreException异常
无注解的普通类
scanCandidateComponents
实现方法
对指定的包名进行扫描scanner.doScan(StringUtils.toStringArray(basePackages));
抛异常BeanDefinitionOverrideException
扫描等价的class两次newDefinition.equals(existingDefinition)
processImports
configClass.isImported()
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
具体判断内容
解析@ImportResource
不为NO,则需要动态代理
调用的抽象方法
设置AutowireMode,Autowire,是否是自动装配的候选,初始化时一定执行的方法,销毁时的方法,设置ScopedProxyMode,如有必要,将原始bean定义替换为目标bean定义
将通过校验方法的beanDefinition加到集合中:configCandidates.add
metadata.getScopedProxyMode()
满足任何一个条件,都返回false
判断是否是配置类
判断目标beanDefinition是否是配置类
配置类有属性,是full或lite型
解析name,value以及encoding
false:
processInterfaces
CGlib动态代理
自定义类实现importselector接口的业务方法selectImports返回的import类集合,也就是等同于@Import。
通过beanName和beanDefinition创建beanDefinitionHolder
ScopedProxyFactoryBean源码
processPropertySource该类型都是k:v类型
解析中最后一步都是注册beanDefinition,专门进行一下详解
配置类是否设置属性(第一次进行该方法是没有设置属性的)
将beanDefinition放入beanDefinitionMap
创建配置类解析器
执行注册后置处理器
判断是不是@Component修饰的类
需要校验的beanDefinition为newBeanDefinition,比较existingDefinition 与newBeanDefinition
将definitionHolder代理对象注册
this.importStack.push(configClass); try { processConfigurationClass(candidate.asConfigClass(configClass)); } finally { this.importStack.pop(); }
是否是@Import修饰,或者是通过其他实现importselector返回结果来导入的
获取对应的beanDefinition赋值为existingDefinition
有
full
递归处理了配置列及其父类层次结构 解析注解
scopeMetadataResolver获取scope,设置beanDefinition的scope
这后面的几种类只解析,每种类解析后都会加到各类bean对应的全局MAP中,并不注册到容器。后面又专门的方法去解析
方法bean和非方法bean的区别:非方法bean:通过beanClass进行注册,通过scope来设置单例多例。方法bean是没有beanClass的,是通过factoryMethodName来实例化bean,且autowridMode设置为3通过构造器构造,scope也是没值的,因为方法bean是通过@Configuration注解来保证单例的。没有注解的就是多例(@Configuration修饰配置类会设置为full类型)
后期会在其他地方,通过字节码技术进行spring的CGLIB的动态代理完成对@Configuration修饰的配置类进行动态增强
0 条评论
回复 删除
下一页