这个方法主要是解析传递进来的bean,这里只会传递一个bean,那就是AppConfig
public void parse(Set<BeanDefinitionHolder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition) {
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
else {
parse(bd.getBeanClassName(), holder.getBeanName());
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
}
}
this.deferredImportSelectorHandler.process();
}
这个方法主要是判断bd属于哪个类型,然后调用对应的parse方法,对于AppConfig对应的类型是AnnotatedBeanDefinition,那么进入第一个parse方法,其实每个parse方法最终调用的都是processConfigurationClass方法
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {
if (configClass.isImported()) {
if (existingClass.isImported()) {
existingClass.mergeImportedBy(configClass);
}
// Otherwise ignore new imported config class; existing non-imported class overrides it.
return;
}
else {
// Explicit bean definition found, probably replacing an import.
// Let‘s remove the old one and go with the new one.
this.configurationClasses.remove(configClass);
this.knownSuperclasses.values().removeIf(configClass::equals);
}
}
// Recursively process the configuration class and its superclass hierarchy.
// 递归处理configuration class和他的父类
SourceClass sourceClass = asSourceClass(configClass);
do {
// 解析配置的类
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);
this.configurationClasses.put(configClass, configClass);
System.out.println();
}
这个类看着很简单,其实这个是最复杂的了。主要的逻辑是将传递进来的configClass包装成SourceClass,然后循环调用doProcessConfigurationClass方法,在这个方法进行配置类的解析
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
// 由于 @Configuration 注解上有 @Component 注解
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// Recursively process any member (nested) classes first
// 首先递归处理嵌套类,这个是为了防止在含有@Component的类中还有内部类含有@Component注解
processMemberClasses(configClass, sourceClass);
}
// Process any @PropertySource annotations
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
else {
logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");
}
}
// Process any @ComponentScan annotations
/*
这里会将@ComponentScan注解中写入的包名下的所有类进行扫描,然后放入beanDefinitionMap中,接着继续调用parse方法就进入了递归
*/
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
// The config class is annotated with @ComponentScan -> perform the scan immediately
// 此处就是解析@ComponentScan中包名下的所有加了spring注解的类,并放入转换成beanDefinition
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if needed
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
// 此处是检查扫描出来的类是否加了@Configuration 注解
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), true);
// Process any @ImportResource annotations
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {
String[] resources = importResource.getStringArray("locations");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}
// Process individual @Bean methods
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// Process default methods on interfaces
processInterfaces(configClass, sourceClass);
// Process superclass, if any
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (superclass != null && !superclass.startsWith("java") &&
!this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
// Superclass found, return its annotation metadata and recurse
return sourceClass.getSuperClass();
}
}
// No superclass -> processing is complete
return null;
}
这个方法主要处理以下几个方面:
// 由于 @Configuration 注解上有 @Component 注解
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// Recursively process any member (nested) classes first
// 首先递归处理嵌套类,这个是为了防止在含有@Component的类中还有内部类含有@Component注解
processMemberClasses(configClass, sourceClass);
}
这个地方如果有内部类并且内部类中也有@Component注解的话,不管是静态内部类还是非静态内部类都会处理
private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
Collection<SourceClass> memberClasses = sourceClass.getMemberClasses();
if (!memberClasses.isEmpty()) {
// 需要处理的配置类的集合
List<SourceClass> candidates = new ArrayList<>(memberClasses.size());
for (SourceClass memberClass : memberClasses) {
// 如果内部类也是配置类,加入到candidates中
if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&
!memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {
candidates.add(memberClass);
}
}
OrderComparator.sort(candidates);
for (SourceClass candidate : candidates) {
if (this.importStack.contains(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
processConfigurationClass(candidate.asConfigClass(configClass));
}
finally {
this.importStack.pop();
}
}
}
}
}
处理@Component内部类的逻辑说完了,用一个例子来验证一个外部类获取静态和非静态内部类。还是用之前一个接口多个实现类的例子:
@Service
public class ServiceImpl {
@Resource(name = "conServiceA")
private MultiService multiService;
@Override
public String toString() {
return "ServiceImpl{" +
"service=" + multiService +
‘}‘;
}
@Component("conServiceA")
public static class ConServiceA implements MultiService{}
@Component("conServiceB")
public class ConServiceB implements MultiService{}
}
当时这两个内部类都是静态内部类,这里将ConServiceB改为非静态内部类,使用debug启动Main#main方法来看下
从上图中可以验证之前说的结果
处理含有@PropertySources注解
这个主要是处理配置文件,在启动配置类AppConfig中就有这个注解,再来看下:
@Configuration
@ComponentScan("com.xxx.spring.multiimpl")
@PropertySource("classpath:application.properties")
public class AppConfig {
}
这个类中的PropertySource注解就是在家配置文件,看下配置文件:
za.profile.env=test
za.data=grafana
很简单的两行配置,这两行配置看下是如何解析的:
// Process any @PropertySource annotations
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
else {
logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");
}
}
processPropertySource
这个方法主要是处理配置文件的,获取注解中的属性,对这些属性做处理,找到配置文件的位置,将这些配置文件加载到environment中的MutablePropertySources属性中
private void processPropertySource(AnnotationAttributes propertySource) throws IOException {
String name = propertySource.getString("name");
if (!StringUtils.hasLength(name)) {
name = null;
}
String encoding = propertySource.getString("encoding");
if (!StringUtils.hasLength(encoding)) {
encoding = null;
}
// 解析配置文件的位置
String[] locations = propertySource.getStringArray("value");
Assert.isTrue(locations.length > 0, "At least one @PropertySource(value) location is required");
boolean ignoreResourceNotFound = propertySource.getBoolean("ignoreResourceNotFound");
Class<? extends PropertySourceFactory> factoryClass = propertySource.getClass("factory");
PropertySourceFactory factory = (factoryClass == PropertySourceFactory.class ?
DEFAULT_PROPERTY_SOURCE_FACTORY : BeanUtils.instantiateClass(factoryClass));
for (String location : locations) {
try {
String resolvedLocation = this.environment.resolveRequiredPlaceholders(location);
// 根据文件位置将文件解析成Resource资源
Resource resource = this.resourceLoader.getResource(resolvedLocation);
// 将资源加载到environment中的MutablePropertySources属性中
addPropertySource(factory.createPropertySource(name, new EncodedResource(resource, encoding)));
}
catch (IllegalArgumentException | FileNotFoundException | UnknownHostException ex) {
// Placeholders not resolvable or resource not found when trying to open it
if (ignoreResourceNotFound) {
if (logger.isInfoEnabled()) {
logger.info("Properties location [" + location + "] not resolvable: " + ex.getMessage());
}
}
else {
throw ex;
}
}
}
}
private void addPropertySource(PropertySource<?> propertySource) {
String name = propertySource.getName();
MutablePropertySources propertySources = ((ConfigurableEnvironment) this.environment).getPropertySources();
if (this.propertySourceNames.contains(name)) {
// We‘ve already added a version, we need to extend it
PropertySource<?> existing = propertySources.get(name);
if (existing != null) {
PropertySource<?> newSource = (propertySource instanceof ResourcePropertySource ?
((ResourcePropertySource) propertySource).withResourceName() : propertySource);
if (existing instanceof CompositePropertySource) {
((CompositePropertySource) existing).addFirstPropertySource(newSource);
}
else {
if (existing instanceof ResourcePropertySource) {
existing = ((ResourcePropertySource) existing).withResourceName();
}
CompositePropertySource composite = new CompositePropertySource(name);
composite.addPropertySource(newSource);
composite.addPropertySource(existing);
propertySources.replace(name, composite);
}
return;
}
}
if (this.propertySourceNames.isEmpty()) {
propertySources.addLast(propertySource);
}
else {
String firstProcessed = this.propertySourceNames.get(this.propertySourceNames.size() - 1);
propertySources.addBefore(firstProcessed, propertySource);
}
this.propertySourceNames.add(name);
}
第二个方法看propertySources.addLast(propertySource);将解析好的资源添加到propertySources中,是否还记得之前说environment时有两个:systemEnvironment和systemProperties,这两个是什么时候添加进去的,从这行代码知道自定义资源是添加到systemEnvironment和systemProperties之后的。
还记得在初始化AnnotationConfigApplicationContext类时,要初始化AnnotatedBeanDefinitionReader对象,在AnnotatedBeanDefinitionReader的对应构造方法中有getOrCreateEnvironment方法获取environment,systemEnvironment和systemProperties是在这添加进去的,会调用StandardEnvironment#customizePropertySources
protected void customizePropertySources(MutablePropertySources propertySources) {
propertySources.addLast(
new PropertiesPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
propertySources.addLast(
new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
}
根据上面的代码可以看出systemProperties优先于systemEnvironment优先于我们自定义的配置文件。用代码验证下,这里只验证systemEnvironment优先于我们自定义的配置文件这块。
首先在启动的Main.java做如下配置:
新增一个配置类:
@Configuration
public class ParamConfig {
@Value("${za.profile.env}")
private String env;
public ParamConfig(){
//System.out.println("param config constructor...");
}
public String getEnv() {
return env;
}
public void setEnv(String env) {
this.env = env;
}
}
配置文件放在classPath下的application.properties文件中:
za.profile.env=test
Main.java
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
ParamConfig config = context.getBean("paramConfig",ParamConfig.class);
System.out.println(config.getEnv());
}
}
运行结果如下:
systemEnvironment
从这个运行结果就可以验证上面的结果
处理ComponentScans或者ComponentScan注解
这两个注解就是扫描指定包下的所有符合spring规则的类放入beanDefinitionMap中
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
// The config class is annotated with @ComponentScan -> perform the scan immediately
// 此处就是解析@ComponentScan中包名下的所有加了spring注解的类,并放入转换成beanDefinition
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if needed
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
// 此处是检查扫描出来的类是否加了@Configuration 注解
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
循环遍历ComponentScans,针对每一个ComponentScan调用parse方法将componentScan和注解元数据传递进去进行处理
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
BeanUtils.instantiateClass(generatorClass));
ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
scanner.setScopedProxyMode(scopedProxyMode);
}
else {
Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
}
scanner.setResourcePattern(componentScan.getString("resourcePattern"));
for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
for (TypeFilter typeFilter : typeFiltersFor(filter)) {
scanner.addIncludeFilter(typeFilter);
}
}
for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
for (TypeFilter typeFilter : typeFiltersFor(filter)) {
scanner.addExcludeFilter(typeFilter);
}
}
boolean lazyInit = componentScan.getBoolean("lazyInit");
if (lazyInit) {
scanner.getBeanDefinitionDefaults().setLazyInit(true);
}
Set<String> basePackages = new LinkedHashSet<>();
String[] basePackagesArray = componentScan.getStringArray("basePackages");
for (String pkg : basePackagesArray) {
String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
Collections.addAll(basePackages, tokenized);
}
for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
basePackages.add(ClassUtils.getPackageName(clazz));
}
if (basePackages.isEmpty()) {
basePackages.add(ClassUtils.getPackageName(declaringClass));
}
scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
@Override
protected boolean matchClassName(String className) {
return declaringClass.equals(className);
}
});
return scanner.doScan(StringUtils.toStringArray(basePackages));
}
在这个方法中就会看到什么样的注解是符合spring规则,会被放入beanDefinitionMap中进行后续的bean相关操作
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
Environment environment, @Nullable ResourceLoader resourceLoader) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
this.registry = registry;
if (useDefaultFilters) {
registerDefaultFilters();
}
setEnvironment(environment);
setResourceLoader(resourceLoader);
}
protected void registerDefaultFilters() {
this.includeFilters.add(new AnnotationTypeFilter(Component.class));
ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
try {
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
logger.trace("JSR-250 ‘javax.annotation.ManagedBean‘ found and supported for component scanning");
}
catch (ClassNotFoundException ex) {
// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
}
try {
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
logger.trace("JSR-330 ‘javax.inject.Named‘ annotation found and supported for component scanning");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
看registerDefaultFilters方法中添加默认类型过滤器,添加到includeFilters集合中
doScan扫描指定包下的类
这个方法就是扫描指定包下的类,将这些符合spring规则的类添加到beanDefinitionMap中
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
findCandidateComponents
该方法在父类ClassPathScanningCandidateComponentProvider中
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
}
else {
return scanCandidateComponents(basePackage);
}
}
从方法中可以看到扫描包路径的方式有两种:
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + ‘/‘ + this.resourcePattern;
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
boolean traceEnabled = logger.isTraceEnabled();
boolean debugEnabled = logger.isDebugEnabled();
for (Resource resource : resources) {
if (traceEnabled) {
logger.trace("Scanning " + resource);
}
if (resource.isReadable()) {
try {
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
if (isCandidateComponent(metadataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setResource(resource);
sbd.setSource(resource);
if (isCandidateComponent(sbd)) {
if (debugEnabled) {
logger.debug("Identified candidate component class: " + resource);
}
candidates.add(sbd);
}
else {
if (debugEnabled) {
logger.debug("Ignored because not a concrete top-level class: " + resource);
}
}
}
else {
if (traceEnabled) {
logger.trace("Ignored because not matching any filter: " + resource);
}
}
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to read candidate component class: " + resource, ex);
}
}
else {
if (traceEnabled) {
logger.trace("Ignored because not readable: " + resource);
}
}
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
}
return candidates;
}
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
for (TypeFilter tf : this.excludeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return false;
}
}
for (TypeFilter tf : this.includeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return isConditionMatch(metadataReader);
}
}
return false;
}
private boolean isConditionMatch(MetadataReader metadataReader) {
if (this.conditionEvaluator == null) {
this.conditionEvaluator =
new ConditionEvaluator(getRegistry(), this.environment, this.resourcePatternResolver);
}
return !this.conditionEvaluator.shouldSkip(metadataReader.getAnnotationMetadata());
}
对于excludeFilters和includeFilters这两个集合上面讲过,excludeFilter是需要排除的,如果解析出来的metadataReader对象和excludeFilter匹配上了,则返回false,即不符合spring扫描条件,不需要加入到bean;如果解析出来的metadataReader对象和includeFilter匹配上还需要调用shouldSkip方法判断@Conditional条件是否满足,如果满足则该对象符合spring扫描条件,添加到beanDefinitionMap中,否则不添加。
isCandidateComponent
这个方法是判断转换成ScannedGenericBeanDefinition对象的bean是否满足bean的定义要求,只有满足了bean的定义要求才能加入到candidates集合中(candidates集合是一个set集合,存放的是BeanDefinition对象)
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
AnnotationMetadata metadata = beanDefinition.getMetadata();
/*
如果该类是独立的(即它是顶级类或者静态内部类,可以独立于封闭类构造,这一步就把非静态内部类排除了) &&
(metadata.isConcrete() || (metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName())))
表示该类是一个具体类或者 该类是一个抽象类并且该类持有 Lookup 注解
满足以上两个条件,那么就算有资格作为候选组件
*/
return (metadata.isIndependent() && (metadata.isConcrete() ||
(metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName()))));
}
通过上面的注释可以得出:这里扫描的类是独立的,这个独立中的解释是顶级类或者静态内部类,这里只找出静态内部类,而非静态内部类却没有加载出来的,在说第一个注解@Component时,专门扫描的是内部类,包括了静态内部类和非静态内部类。
说完了findCandidateComponents方法,说明找到了所有符合spring扫描条件的对象,并添加到candidates集合中,组成了一个个的BeanDefinition对象,接下来就是对这个集合进行遍历,做一些列的判断,最终将符合条件的放入到beanDefinitionMap中。
resolveScopeMetadata
这个方法主要解析@Scope注解,为候选 bean 设置代理的方法 ScopedProxyMode,之前说过这个一般用在web应用,这里不做解析
generateBeanName
使用spring的beanName生成器为每个bean生成一个name,调用的是org.springframework.context.annotation.AnnotationBeanNameGenerator#generateBeanName
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
if (definition instanceof AnnotatedBeanDefinition) {
String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
if (StringUtils.hasText(beanName)) {
// Explicit bean name found.
return beanName;
}
}
// Fallback: generate a unique default bean name.
return buildDefaultBeanName(definition, registry);
}
这个生成beanName的规则是:
postProcessBeanDefinition
如果是AbstractBeanDefinition类型,则调用postProcessBeanDefinition,使用AbstractBeanDefinition的一些默认属性
protected void postProcessBeanDefinition(AbstractBeanDefinition beanDefinition, String beanName) {
beanDefinition.applyDefaults(this.beanDefinitionDefaults);
if (this.autowireCandidatePatterns != null) {
beanDefinition.setAutowireCandidate(PatternMatchUtils.simpleMatch(this.autowireCandidatePatterns, beanName));
}
}
public void applyDefaults(BeanDefinitionDefaults defaults) {
setLazyInit(defaults.isLazyInit());
setAutowireMode(defaults.getAutowireMode());
setDependencyCheck(defaults.getDependencyCheck());
setInitMethodName(defaults.getInitMethodName());
setEnforceInitMethod(false);
setDestroyMethodName(defaults.getDestroyMethodName());
setEnforceDestroyMethod(false);
}
processCommonDefinitionAnnotations
如果是AnnotatedBeanDefinition类型,则调用processCommonDefinitionAnnotations方法处理一些通用注解:@Lazy,@Primary,@DependsOn,@Role,@Description。从上面的方法中可以得出扫描出来符合条件的对象会被包装成ScannedGenericBeanDefinition对象然后放入candidates集合中,ScannedGenericBeanDefinition是AnnotatedBeanDefinition实现类
static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
if (lazy != null) {
abd.setLazyInit(lazy.getBoolean("value"));
}
else if (abd.getMetadata() != metadata) {
lazy = attributesFor(abd.getMetadata(), Lazy.class);
if (lazy != null) {
abd.setLazyInit(lazy.getBoolean("value"));
}
}
if (metadata.isAnnotated(Primary.class.getName())) {
abd.setPrimary(true);
}
AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
if (dependsOn != null) {
abd.setDependsOn(dependsOn.getStringArray("value"));
}
AnnotationAttributes role = attributesFor(metadata, Role.class);
if (role != null) {
abd.setRole(role.getNumber("value").intValue());
}
AnnotationAttributes description = attributesFor(metadata, Description.class);
if (description != null) {
abd.setDescription(description.getString("value"));
}
}
checkCandidate
校验重复bean
protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {
if (!this.registry.containsBeanDefinition(beanName)) {
return true;
}
BeanDefinition existingDef = this.registry.getBeanDefinition(beanName);
BeanDefinition originatingDef = existingDef.getOriginatingBeanDefinition();
if (originatingDef != null) {
existingDef = originatingDef;
}
if (isCompatible(beanDefinition, existingDef)) {
return false;
}
throw new ConflictingBeanDefinitionException("Annotation-specified bean name ‘" + beanName +
"‘ for bean class [" + beanDefinition.getBeanClassName() + "] conflicts with existing, " +
"non-compatible bean definition of same name and class [" + existingDef.getBeanClassName() + "]");
}
校验这个bean是否已经存在了,如果不存在返回true,说明可以将这个bean放入beanDefinitionMap中,如果存在需要校验已经存在bean和传递进来的bean是否兼容,如果兼容返回false,不需要再注册了;如果不兼容则抛出异常。
这里也就是使用@Component等组件注解标注bean的不能有重名的逻辑了
到这里就把ConfigurationClassParser#doProcessConfigurationClass方法中关于@ComponentScan或者@ComponentScans注解中的componentScanParser.parse介绍完了。这个方法介绍完,那么存在scannedBeanDefinitions集合中的beanDefinitionHolder都是符合spring条件的bean,从这些BeanDefinitionHolder中获取对应的BeanDefinition,然后调用ConfigurationClassUtils.checkConfigurationClassCandidate方法判断这些符合条件的bean中是否含有full或者lite中的注解,如果存在的话,递归调用parse方法再次进入doProcessConfigurationClass方法进行解析
处理含有@Import注解的bean
processImports(configClass, sourceClass, getImports(sourceClass), true);
@Import这是一个非常实用的注解,像我们平时用的@FeignClient注解,如果要使用这个注解需要使用@EnableFeignClients注解开启这个功能,而@EnableFeignClients注解中就有Import这个注解;还有使用AspectJ开启AOP功能,需要使用@EnableAspectJAutoProxy注解,而在这个注解中也有@Import这个注解的影子。上面这行代码就是处理@Import注解的,具体代码逻辑如下:
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
if (importCandidates.isEmpty()) {
return;
}
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
if (candidate.isAssignable(ImportSelector.class)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
ParserStrategyUtils.invokeAwareMethods(
selector, this.environment, this.resourceLoader, this.registry);
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
}
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
ParserStrategyUtils.invokeAwareMethods(
registrar, this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as an @Configuration class
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass));
}
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configClass.getMetadata().getClassName() + "]", ex);
}
finally {
this.importStack.pop();
}
}
}
这里需要声明一点:使用@Import注解引入的class本身不会在该方法中被加入到beanDefinitionMap中,这里只会加入到相应的缓存中,后续会在loadBeanDefinition方法中加入到beanDefinitionMap中
从上面的方法中可以得出以下结论:
循环遍历importCandidates集合,判断每个SourceClass是否是如下几个类型:
如果是ImportSelector类型:该class本身不会被注册为beanDefinition,但是它的selectImports方法返回的类路径的数组中类可能会被注册为beanDefinition,在该方法中会循环调用processImports方法处理selectImports方法返回的类路径中的类,直到遇到是ImportBeanDefinitionRegistrar类型或者是一个普通类
如果是ImportBeanDefinitionRegistrar类型:该class本身不会被注册为beanDefinition,但是它的registerBeanDefinitions方法可用于注册为beanDefinition,在该方法中仅仅是加入到importBeanDefinitionRegistrars集合中,等待后续loadBeanDefinition方法进行处理
如果是普通class类型:该class会尝试加入到beanDefinition中,但在该方法中只会调用processConfigurationClass方法处理并加入到configurationClasses缓存中,等待后续的loadBeanDefinition方法进行处理
处理@ImportResource注解
该注解主要是为了引入xml文件配置,如果你的项目是基于注解开发,但又有xml配置,此时可以使用该注解处理
*处理@Bean注解
这里是处理方法上含有@Bean注解,在该方法中同样是不会被注册为beanDefinition,仅仅是加入到beanMethods集合中,等待后续的处理
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
处理接口上的默认方法
这个是Java8之后的新特定,主要是处理接口上含有@Bean注解的方法,处理方式同上,仅仅是加入到beanMethods集合中等待后续处理
处理超类
配置类的父类同样会被解析,但是已"java"开头的类路径的父类不会被处理,比如Object类这样rt.jar中类
如果存在父类并且不是以"java"开头的并且在knownSuperclasses集合中不存在,那么将该类加入到knownSuperclasses集合中,并且返回父类。返回之后会继续调用processConfigurationClass方法进入到下一次的循环处理这个父类
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (superclass != null && !superclass.startsWith("java") &&
!this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
// Superclass found, return its annotation metadata and recurse
return sourceClass.getSuperClass();
}
}
以上就是处理所有对应的注解,在processConfigurationClass方法中有一个do while循环,终止条件是sourceClass为null,即一直处理直至返回null。
上面这些处理注解的是ConfigurationClassPostProcessor#processConfigBeanDefinitions方法中ConfigurationClassParser#parse方法处理的步骤。介绍到这是不是忘了前面说的什么了,这个方法就是如此的复杂。。
原文:https://www.cnblogs.com/yashon/p/15046037.html