Spring boot 소스 코드 분석 - SpringBootApplication 주석 (8)
26518 단어 spring-boot
우 리 는 분명히 매우 이상 할 것 이다. SpringApplication. run (Chapter Profiles Application. class, args) 을 호출 할 것 이다.의 코드 는 어떻게 spring 을 시작 하고 모든 bean 을 불 러 오 는 지, 사실은 관건 은 SpringBootApplication 주석 입 니 다. 오늘 우 리 는 이 주 해 를 설명 하 겠 습 니 다.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class))
public @interface SpringBootApplication {
Class>[] exclude() default {};
String[] excludeName() default {};
@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};
@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
Class>[] scanBasePackageClasses() default {};
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class>[] exclude() default {};
String[] excludeName() default {};
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
}
spring 3.0 부터 자바 Config 방식 으로 설정 할 수 있 습 니 다. 구체 적 으로 spring 은 자바 류 를 프로필 로 처리 하여 코드 를 큰 설정 파일 의 어려움 에서 벗 어 날 수 있 습 니 다.
springboot 에 Bean DefinitionLoader 가 있 습 니 다. 바로 앞에서 말 한 Bean DefinitionReader 외관 모드 입 니 다. 자바 Config 방식 으로 설정 할 때 Annotated Bean DefinitionReader 를 사용 하여 register 방법 을 호출 했 습 니 다.
// AnnotatedBeanDefinitionReader
this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
// bean
this.annotatedReader.register(source);
public void register(Class>... annotatedClasses) {
for (Class> annotatedClass : annotatedClasses) {
registerBean(annotatedClass);
}
}
public void registerBean(Class> annotatedClass) {
registerBean(annotatedClass, null, (Class extends Annotation>[]) null);
}
@SuppressWarnings("unchecked")
public void registerBean(Class> annotatedClass, String name, Class extends Annotation>... qualifiers) {
// beandefinition
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
//this is new StandardAnnotationMetadata(beanClass, true);
// true
//
//abd.getMetadata()
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
// scopeMetadata
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
if (qualifiers != null) {
for (Class extends Annotation> qualifier : qualifiers) {
if (Primary.class == qualifier) {
abd.setPrimary(true);
}
else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
}
else {
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
// ScopedProxyMode
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
Assert.notNull(environment, "Environment must not be null");
this.registry = registry;
//Conditional
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
// AnnotationConfigProcessor
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
* 우선 클 라 스 설정 을 Annotated GenericBean Definition 으로 봉 합 니 다. 우 리 는 이러한 역할 을 봅 니 다.
1. GenericBeanDefinition Bean , bean ,BeanFactory bean
2.
this.metadata = new StandardAnnotationMetadata(beanClass, true);
public StandardAnnotationMetadata(Class> introspectedClass, boolean nestedAnnotationsAsMap) {
super(introspectedClass);
this.annotations = introspectedClass.getAnnotations();
this.nestedAnnotationsAsMap = nestedAnnotationsAsMap;
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
int factoryId = System.identityHashCode(beanFactory);
if (this.factoriesPostProcessed.contains(factoryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + beanFactory);
}
this.factoriesPostProcessed.add(factoryId);
if (!this.registriesPostProcessed.contains(factoryId)) {
// BeanDefinitionRegistryPostProcessor hook apparently not supported...
// Simply call processConfigurationClasses lazily at this point then.
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
}
enhanceConfigurationClasses(beanFactory);
}
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
// List
List configCandidates = new ArrayList();
String[] candidateNames = registry.getBeanDefinitionNames();
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
if (logger.isDebugEnabled()) {
//bean
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
// Return immediately if no @Configuration classes were found
if (configCandidates.isEmpty()) {
return;
}
// Sort by previously determined @Order value, if applicable
// Configuration
Collections.sort(configCandidates, new Comparator() {
@Override
public int compare(BeanDefinitionHolder bd1, BeanDefinitionHolder bd2) {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return (i1 < i2) ? -1 : (i1 > i2) ? 1 : 0;
}
});
// Detect any custom bean name generation strategy supplied through the enclosing application context
SingletonBeanRegistry singletonRegistry = null;
if (registry instanceof SingletonBeanRegistry) {
singletonRegistry = (SingletonBeanRegistry) registry;
if (!this.localBeanNameGeneratorSet && singletonRegistry.containsSingleton(CONFIGURATION_BEAN_NAME_GENERATOR)) {
BeanNameGenerator generator = (BeanNameGenerator) singletonRegistry.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
// Parse each @Configuration class
/*
* metadataReaderFactory = new CachingMetadataReaderFactory();
* problemReporter = new FailFastProblemReporter();
* environment
* resourceLoader = new DefaultResourceLoader();
* componentScanBeanNameGenerator = new AnnotationBeanNameGenerator();
*
*
*/
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
//
Set candidates = new LinkedHashSet(configCandidates);
Set alreadyParsed = new HashSet(configCandidates.size());
do {
//
parser.parse(candidates);
parser.validate();
Set configClasses = new LinkedHashSet(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
if (this.reader == null) {
// beandefinitionreader
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
// -- bean
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
candidates.clear();
if (registry.getBeanDefinitionCount() > candidateNames.length) {
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set oldCandidateNames = new HashSet(Arrays.asList(candidateNames));
Set alreadyParsedClasses = new HashSet();
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
for (String candidateName : newCandidateNames) {
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition beanDef = registry.getBeanDefinition(candidateName);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(beanDef.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(beanDef, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
}
while (!candidates.isEmpty());
// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
if (singletonRegistry != null) {
if (!singletonRegistry.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
singletonRegistry.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
}
if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
}
@ Componentscan 의 역할
또한 ConfigurationClassPostProcessor. class 에서 분석 할 때 @ ComponentScan 주 해 를 만 나 설명 설정 아래 의 모든 종 류 를 스 캔 한 다음 bean 을 등록 합 니 다.
EnableAutoConfiguration ImportSelector. class 의 역할
ConfigurationClassPostProcessor. class 라 는 등록 절단면 은 ConfigurationClassParser 류 의 parser. parse (candidates) 를 호출 할 때 EnableAutoConfiguration 의 설정 을 spring - boot - autoconfigure 프로젝트 아래 에 있 는 spring. factories 를 가 져 옵 니 다.그리고 스 캔 된 Configraution 을 모두 분석 합 니 다.
public void parse(Set configCandidates) {
this.deferredImportSelectors = new LinkedList();
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);
}
}
processDeferredImportSelectors();
}
private void processDeferredImportSelectors() {
List deferredImports = this.deferredImportSelectors;
this.deferredImportSelectors = null;
Collections.sort(deferredImports, DEFERRED_IMPORT_COMPARATOR);
for (DeferredImportSelectorHolder deferredImport : deferredImports) {
ConfigurationClass configClass = deferredImport.getConfigurationClass();
try {
String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata());
processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configClass.getMetadata().getClassName() + "]", ex);
}
}
}
따라서 spring. factories 에서 설명 하면 EnableAutoConfiguration 의 스 캔 류 는 상 자 를 열 고 해당 하 는 기능 을 사용 할 수 있 습 니 다.
AutoConfiguration Packages. Registrar. class 의 역할
자바 설정 확장 을 지원 하 는 관건 은 @ Import 주해 입 니 다. Spring 3.0 은 Configuration 류 에 다른 설정 류 를 도입 하 는 것 을 지원 합 니 다. ImportSelector 와 ImportBeanDefinitionRegistrar 의 실현 류 를 포함 합 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Keycloak이 Active Directory에 등록된 사용자로 인증할 수 있도록 합니다.사내 시스템을 출시함에 있어서, 전회사에서는 Web시스템마다 로그인하고 있어 혐오가 있었으므로, 꼭 싱글 사인온으로 하고 싶다고 생각했다. 그 실현에, 옛날 조금만 평가한 OpenAM라든지의 정보를 구구어 낚시하기 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.