第十次JAVA实习生面试题打卡
Posted Code_BinBin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第十次JAVA实习生面试题打卡相关的知识,希望对你有一定的参考价值。
springboot自动配置原理是什么?
1、在springboot的启动过程中,有一个步骤是创建上下文,如果不记得可以看下面的代码:
public ConfigurableApplicationContext run(String... args)
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] ConfigurableApplicationContext.class , context);
//此处完成自动装配的过程
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo)
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
listeners.started(context);
callRunners(context, applicationArguments);
catch (Throwable ex)
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
try
listeners.running(context);
catch (Throwable ex)
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
return context;
2、在prepareContext方法中查找load方法,一层一层向内点击,找到最终的load方法
//prepareContext方法
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner)
context.setEnvironment(environment);
postProcessApplicationContext(context);
applyInitializers(context);
listeners.contextPrepared(context);
if (this.logStartupInfo)
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
// Add boot specific singleton beans
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null)
beanFactory.registerSingleton("springBootBanner", printedBanner);
if (beanFactory instanceof DefaultListableBeanFactory)
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
if (this.lazyInitialization)
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
// Load the sources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
//load方法完成该功能
load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);
/**
* Load beans into the application context.
* @param context the context to load beans into
* @param sources the sources to load
* 加载bean对象到context中
*/
protected void load(ApplicationContext context, Object[] sources)
if (logger.isDebugEnabled())
logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
//获取bean对象定义的加载器
BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
if (this.beanNameGenerator != null)
loader.setBeanNameGenerator(this.beanNameGenerator);
if (this.resourceLoader != null)
loader.setResourceLoader(this.resourceLoader);
if (this.environment != null)
loader.setEnvironment(this.environment);
loader.load();
/**
* Load the sources into the reader.
* @return the number of loaded beans
*/
int load()
int count = 0;
for (Object source : this.sources)
count += load(source);
return count;
3、实际执行load的是BeanDefinitionLoader中的load方法,如下:
//实际记载bean的方法
private int load(Object source)
Assert.notNull(source, "Source must not be null");
//如果是class类型,启用注解类型
if (source instanceof Class<?>)
return load((Class<?>) source);
//如果是resource类型,启动xml解析
if (source instanceof Resource)
return load((Resource) source);
//如果是package类型,启用扫描包,例如@ComponentScan
if (source instanceof Package)
return load((Package) source);
//如果是字符串类型,直接加载
if (source instanceof CharSequence)
return load((CharSequence) source);
throw new IllegalArgumentException("Invalid source type " + source.getClass());
4、下面方法将用来判断是否资源的类型,是使用groovy加载还是使用注解的方式
private int load(Class<?> source)
//判断使用groovy脚本
if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source))
// Any GroovyLoaders added in beans DSL can contribute beans here
GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);
load(loader);
//使用注解加载
if (isComponent(source))
this.annotatedReader.register(source);
return 1;
return 0;
5、下面方法判断启动类中是否包含@Component注解,但是会神奇的发现我们的启动类中并没有该注解,继续更进发现MergedAnnotations类传入了一个参数SearchStrategy.TYPE_HIERARCHY,会查找继承关系中是否包含这个注解,@SpringBootApplication–>@SpringBootConfiguration–>@Configuration–>@Component,当找到@Component注解之后,会把该对象注册到AnnotatedBeanDefinitionReader对象中
private boolean isComponent(Class<?> type)
// This has to be a bit of a guess. The only way to be sure that this type is
// eligible is to make a bean definition out of it and try to instantiate it.
if (MergedAnnotations.from(type, SearchStrategy.TYPE_HIERARCHY).isPresent(Component.class))
return true;
// Nested anonymous classes are not eligible for registration, nor are groovy
// closures
return !type.getName().matches(".*\\\\$_.*closure.*") && !type.isAnonymousClass()
&& type.getConstructors() != null && type.getConstructors().length != 0;
/**
* Register a bean from the given bean class, deriving its metadata from
* class-declared annotations.
* 从给定的bean class中注册一个bean对象,从注解中找到相关的元数据
*/
private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
@Nullable BeanDefinitionCustomizer[] customizers)
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
if (this.conditionEvaluator.shouldSkip(abd.getMetadata()))
return;
abd.setInstanceSupplier(supplier);
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));
if (customizers != null)
for (BeanDefinitionCustomizer customizer : customizers)
customizer.customize(abd);
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
/**
* Register the given bean definition with the given bean factory.
* 注册主类,如果有别名可以设置别名
*/
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException
// Register bean definition under primary name.
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
String[] aliases = definitionHolder.getAliases();
if (aliases != null)
for (String alias : aliases)
registry.registerAlias(beanName, alias);
//@SpringBootApplication
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) )
public @interface SpringBootApplication
//@SpringBootConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration
//@Configuration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration
当看完上述代码之后,只是完成了启动对象的注入,自动装配还没有开始,下面开始进入到自动装配。
6、自动装配入口,从刷新容器开始
@Override
public void refresh() throws BeansException, IllegalStateException
synchronized (this.startupShutdownMonitor)
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
// 此处是自动装配的入口
invokeBeanFactoryPostProcessors(beanFactory);
7、在invokeBeanFactoryPostProcessors方法中完成bean的实例化和执行
/**
* Instantiate and invoke all registered BeanFactoryPostProcessor beans,
* respecting explicit order if given.
* <p>Must be called before singleton instantiation.
*/
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory)
//开始执行beanFactoryPostProcessor对应实现类,需要知道的是beanFactoryPostProcessor是spring的扩展接口,在刷新容器之前,该接口可以用来修改bean元数据信息
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME))
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
8、查看invokeBeanFactoryPostProcessors的具体执行方法
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors)
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
Set<String> processedBeans = new HashSet<>();
if (beanFactory instanceof BeanDefinitionRegistry)
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
//开始遍历三个内部类,如果属于BeanDefinitionRegistryPostProcessor子类,加入到bean注册的集合,否则加入到regularPostProcessors
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors)
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor)
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
else
regularPostProcessors.add(postProcessor);
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
// Separate between BeanDefinitionRegistryPostProcessors that implement
// PriorityOrdered, Ordered, and the rest.
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
//通过BeanDefinitionRegistryPostProcessor获取到对应的处理类“org.springframework.context.annotation.internalConfigurationAnnotationProcessor”,但是需要注意的是这个类在springboot中搜索不到,这个类的完全限定名在AnnotationConfigEmbeddedWebApplicationContext中,在进行初始化的时候会装配几个类,在创建AnnotatedBeanDefinitionReader对象的时候会将该类注册到bean对象中,此处可以看到internalConfigurationAnnotationProcessor为bean名称,容器中真正的类是ConfigurationClassPostProcessor
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
//首先执行类型为PriorityOrdered的BeanDefinitionRegistryPostProcessor
//PriorityOrdered类型表明为优先执行
for (String ppName : postProcessorNames)
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class))
//获取对应的bean
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
//用来存储已经执行过的BeanDefinitionRegistryPostProcessor
processedBeans.add(ppName);
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
以上是关于第十次JAVA实习生面试题打卡的主要内容,如果未能解决你的问题,请参考以下文章