从Jetty web容器启动启动注意到
for (ServletContextListener listener : _servletContextListeners)
{
//调用对应配置的listener的contextInitialized方法
callContextInitialized(listener,event);
_destroySerletContextListeners.add(listener);
}
复制代码
容器启动会执行ServletContextListener的contextInitialized方法,对于Spring来说,它就是执ContextLoaderInitialized方法。
ContextLoaderListener
它是一个Bootstrap listener,用来启动和关闭Spring的根WebApplicationContext
@Overridepublic void contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
}
复制代码
进入初始化后,可以看到spring项目中启动的时候,经常看到的启动时间位置
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
...
servletContext.log("Initializing Spring root WebApplicationContext");
Log logger = LogFactory.getLog(ContextLoader.class);
if (logger.isInfoEnabled()) {
logger.info("Root WebApplicationContext: initialization started");
}
long startTime = System.currentTimeMillis();
…
if (logger.isInfoEnabled()) {
long elapsedTime = System.currentTimeMillis() - startTime;
logger.info("Root WebApplicationContext initialized in " + elapsedTime + " ms");
}
...
}
catch (RuntimeException | Error ex) {
logger.error("Context initialization failed", ex);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
throw ex;
}
复制代码
ServletContext: servlet用来和servlet容器交互的类
可以看到这就是启动的地方了!
首先会检查是不是已经有root WebApplicationContext
,如果存在,就会报错
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
throw new IllegalStateException(
"Cannot initialize context because there is already a root application context present - " +
"check whether you have multiple ContextLoader* definitions in your web.xml!");
}
…
// Store context in local instance variable, to guarantee that// it is available on ServletContext shutdown.
if (this.context == null) {
this.context = createWebApplicationContext(servletContext);
}
…
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
…
return this.context;
...
}
复制代码
创建一个context分为两个步骤
-
获取到底使用哪种类型的class。
获取class,可以在web.xml中通过 ‘contextClass’标签,定义在context_param中public static final String CONTEXT_CLASS_PARAM = "contextClass"; … //web.xml中初始化会加载存放到servletContext中 String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM); 复制代码
自定义的类必须是ConfigurableWebApplicationContext 的子类,否则抛出异常
if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) { throw new ApplicationContextException("Custom context class [" + contextClass.getName() + "] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]"); } 复制代码
没有定义则直接在spring自带的ContextLoader.properties中取找到对应的默认加载类
//ContextLoader.properties自定义内容如下 org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext ... private static final String DEFAULT_STRATEGIES_PATH = "ContextLoader.properties"; … ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class); defaultStrategies = PropertiesLoaderUtils.loadProperties(resource); ... contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName()); 复制代码
-
初始化。使用获取对应构造函数执行初始化
return instantiateClass(clazz.getDeclaredConstructor());
,默认就是XmlWebApplicationContext
初始化之后,对于刚启动的项目来说,它肯定需要加载对应的东西,首先会去加载它的父context,这对于spring 5来说,只是返回null。
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
if (!cwac.isActive()) {
if (cwac.getParent() == null) {
//加载父上下文的主要理由是,允许多个 root web application的应用能够都成为他们所共享的 EAR或者EJB 的子类。如果没有对应的场景,父上下文并没有什么重要性
ApplicationContext parent = loadParentContext(servletContext);
cwac.setParent(parent);
}
//读取配置更新spring web容器
configureAndRefreshWebApplicationContext(cwac, servletContext);
}
复制代码
读取配置,而配置的来源就是在web.xml中配置的contextConfigLocation
。
String CONFIG_LOCATION_DELIMITERS = ",; \t\n";
...
public static final String CONFIG_LOCATION_PARAM = "contextConfigLocation";
...
sc.getInitParameter(CONFIG_LOCATION_PARAM);
...
setConfigLocations(StringUtils.tokenizeToStringArray(location, CONFIG_LOCATION_DELIMITERS));
…
public static final String GLOBAL_INITIALIZER_CLASSES_PARAM = "globalInitializerClasses";
public static final String CONTEXT_INITIALIZER_CLASSES_PARAM = "contextInitializerClasses”;
…
AnnotationAwareOrderComparator.sort(this.contextInitializers);
for (ApplicationContextInitializer<ConfigurableApplicationContext> initializer : this.contextInitializers) {
//按照顺序执行自定义的initializer的初始化,给新建的 webapplicationcontext添加特定的资源
initializer.initialize(wac);
}
复制代码
最后真正的开始执行配置的加载与更新,即IOC容器的初始化开始。IOC容器初始化结束之后,设置为root WebApplicationContext
,至此web项目的初始化结束
下面以默认的 XmlWebApplicationContext为例阐述springmvc初始化的过程
IoC的含义
IoC意指控制反转,对于庞大的项目来说,如果合作的对象引用或依赖关系的管理由具体的对象完成,会导致代码的高度耦合和可测试性降低,这种现象的解决之道就是把对象之间的依赖关系注入交给IoC容器来执行,让IoC容器来处理一代对象之间的关系
Spring本身实现了IoC容器的规范,它的具体实现就是BeanFactory
。
- 获取bean
- 获取bean的别名
- 获取bean的类型
- 校验bean的类型
- 识别容器是否包含指定的bean
- 判断bean是singleton还是prototype
要使得IoC容器使用起来,可以想到,必定会经过如下过程
- 创建IoC抽象的配置资源,对于Spring来说,就是程序运行起来需要哪些bean,通过配置去告知框架
- 创建一个bean容器,对于Spring来时,他就是BeanFactory的一些实现
- 创建一个读取配置资源的工具,对于用户指定的配置文件,需要被加载,以Spring来说就是要把配置文件转成对应的BeanDefinition
- 对都的配置资源进行解析,完成载入和注册
至此开始使用IoC容器。Spring为了这整个过程更加的便捷,提供了一个更高级形态的Ioc容器ApplicationContext
- EnvironmentCapable:拥有获取应用运行环境的能力
- ListableBeanFactory: 拥有枚举所有bean实例的能力
- HierarchicalBeanFactory:能够获取父bennFactory的能力 -MessageSource:能够提供message的参数胡和国际化的能力
- ApplicationEventPublisher:拥有发布消息的能力
- ResourcePatternResolver:拥有能够从给定路径提取资源并加载资源的能力
在spring的默认启动中,使用的XmlWebApplicationContext就实现了ApplicationContext接口。
IOC容器XmlWebApplicationContext初始化
继续回到初始化的流程,它会执行对应的refresh方法,整体过程如下
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
prepareRefresh();
// 新建beanFactory,加载bean配置
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 配置一个beanFactory的标准特征
prepareBeanFactory(beanFactory);
...
//针对不同的beanFactory,配置不同的特征
postProcessBeanFactory(beanFactory);
// 调用BeanFactory的后置处理器,这些后置处理器都是在bean定义中向容器注册的
invokeBeanFactoryPostProcessors(beanFactory);
...
// 初始化ApplicationEventMulticaster,如果没有指定bean ‘applicationEventMulticaster',新建一个SimpleApplicationEventMulticaster,用来给注册的所有listener发布事件
initApplicationEventMulticaster();
...
// 把所有实现了ApplicationListener的接口当做listener,添加到ApplicationEventMulticaster的listener中
registerListeners();
// 初始化所有的非懒加载的bean
finishBeanFactoryInitialization(beanFactory);
// 清除资源的缓存,初始化 lifecycleProcessor,如果没有bean 'lifecycleProcessor’存在,默认新建DefaultLifecycleProcessor,并启动,最后发布ContextRefreshedEvent,如果需要处理MBEAN相关,注册进MBEAN server
finishRefresh();
….
}finally {
// 清除掉之前用的所有缓存,包括反射、注解、类加载
resetCommonCaches();
}
}
}
复制代码
prepareRefresh
设置启动的时间,标识已经启动了,对于xmlWebApplicationContext来说, 会把对应的Servlet配置替换成整整的servletContext和servletConfig实例,并校验已经标为必须要有的properties是能够获取到的
public static final String SERVLET_CONTEXT_PROPERTY_SOURCE_NAME = "servletContextInitParams";
public static final String SERVLET_CONFIG_PROPERTY_SOURCE_NAME = "servletConfigInitParams”;
...
String name = StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME;
...
sources.replace(name, new ServletContextPropertySource(name, servletContext));
...
name = StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME;
...
sources.replace(name, new ServletConfigPropertySource(name, servletConfig));
...
复制代码
obtainFreshBeanFactory
- 查看之前是否存在BeanFactory,有的话关闭
- 建一个新的beanFactory.加载对应的Bean资源
创建beanFactory核心如下
new DefaultListableBeanFactory(getInternalParentBeanFactory());
…
loadBeanDefinitions(beanFactory);
…
复制代码
开始执行加载
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
//加载xml的类
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
...
loadBeanDefinitions(beanDefinitionReader);
}
复制代码
加载配置文件,首先就是要获取配置文件的位置,
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
...
//它就是web.xml中配置的“contextConfigLocation”
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
复制代码
然后通过XmlBeanDefinitionReader依次加载所有的配置文件
//AbstractBeanDefinitonReader.loadBeanDefinitions
//首先是根据路径去获取对应的文件,转为Resource
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
//然后加载进来
int count = loadBeanDefinitions(resources);
...
复制代码
文件查找的方法
以PathMatchingResourcePatternResolver为例
String CLASSPATH_ALL_URL_PREFIX = "classpath*:";
...
public Resource[] getResources(String locationPattern) throws IOException {
//找到对应的前缀,classpath
if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {
if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {
//匹配 classpath*:开始查找
return findPathMatchingResources(locationPattern);
}
else {
//去掉前缀开始查找
return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));
}
}else{
//对于不是war开头的,找到对应的冒号坐标
int prefixEnd = (locationPattern.startsWith("war:") ? locationPattern.indexOf("*/") + 1 :
locationPattern.indexOf(':') + 1);
if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {
//符合Ant风格的方式,开始查找
return findPathMatchingResources(locationPattern);
}
。。。
}
}
复制代码
具体查找文件的方式为
protected Set<Resource> doFindAllClassPathResources(String path) throws IOException {
Set<Resource> result = new LinkedHashSet<>(16);
ClassLoader cl = getClassLoader();
//通过classLoader去查找对应的文件
Enumeration<URL> resourceUrls = (cl != null ? cl.getResources(path) : ClassLoader.getSystemResources(path));
while (resourceUrls.hasMoreElements()) {
URL url = resourceUrls.nextElement();
result.add(convertClassLoaderURL(url));
}
...
return result;
}
复制代码
加载文件
找到文件的位置之后,开始加载文件
//XmlBeanDefinitionReader.doLoadBeanDefinitions
…
//使用DefaultDocumentLoader来加载
Document doc = doLoadDocument(inputSource, resource);
//加载到文件便开始注册bean
int count = registerBeanDefinitions(doc, resource);
...
复制代码
注册bean核心内容如下
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
//创建一个委托类,并填充默认的配置到DocumentDefaultsDefinition,比如 lazy-init,autowire等等,然后触发默认的属性已经注册完毕
this.delegate = createDelegate(getReaderContext(), root, parent);
...
parseBeanDefinitions(root, this.delegate);
...
this.delegate = parent;
}
复制代码
- 创建代理,它会填充的默认配置,处理如下
protected void populateDefaults(DocumentDefaultsDefinition defaults, @Nullable DocumentDefaultsDefinition parentDefaults, Element root) { //获取xml文件的根节点 //获取 default-lazy-init 属性 String lazyInit = root.getAttribute(DEFAULT_LAZY_INIT_ATTRIBUTE); if (DEFAULT_VALUE.equals(lazyInit)) { //如果属性中是默认值:default,如果有父设置,沿用之前的,否则,设置为 false lazyInit = (parentDefaults != null ? parentDefaults.getLazyInit() : FALSE_VALUE); } defaults.setLazyInit(lazyInit); 。。。 //获取 default-autowire 属性 String autowire = root.getAttribute(DEFAULT_AUTOWIRE_ATTRIBUTE); if (DEFAULT_VALUE.equals(autowire)) { //如果是默认值 default,就设置为 no autowire = (parentDefaults != null ? parentDefaults.getAutowire() : AUTOWIRE_NO_VALUE); } defaults.setAutowire(autowire); 。。。 //如果存在 default-init-method ,那么获取这个默认的init-method并设置成对应的initMethod if (root.hasAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE)) { defaults.setInitMethod(root.getAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE)); } else if (parentDefaults != null) { defaults.setInitMethod(parentDefaults.getInitMethod()); } ... defaults.setSource(this.readerContext.extractSource(root)); } 复制代码
- 代理会去读到这个文件的命名空间Uri,对不同的命名空间,分别解析
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) { String namespaceUri = getNamespaceURI(ele); if (namespaceUri == null) { return null; } NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); .... return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); } 复制代码
NamspaceHandler存在各种对应的实现
通过获取对应的命名空间,来解析对应的配置
-
ContextNamespaceHandler
public void init() { ... registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser()); //熟悉的componenet-scan registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser()); ... } 复制代码
-
TaskNamespaceHandler
public void init() { this.registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser()); this.registerBeanDefinitionParser("executor", new ExecutorBeanDefinitionParser()); this.registerBeanDefinitionParser("scheduled-tasks", new ScheduledTasksBeanDefinitionParser()); this.registerBeanDefinitionParser("scheduler", new SchedulerBeanDefinitionParser()); } 复制代码
-
UtilNamespaceHandler
public void init() { registerBeanDefinitionParser("constant", new ConstantBeanDefinitionParser()); registerBeanDefinitionParser("property-path", new PropertyPathBeanDefinitionParser()); registerBeanDefinitionParser("list", new ListBeanDefinitionParser()); registerBeanDefinitionParser("set", new SetBeanDefinitionParser()); registerBeanDefinitionParser("map", new MapBeanDefinitionParser()); registerBeanDefinitionParser("properties", new PropertiesBeanDefinitionParser()); } 复制代码
从这里可以看到,遇到对应的标签名字,分别对应不同的解析器来解析对应的内容。
解析xml文件的标签
以ComponentScanBeanDefinitionParser
为例,解析过程如下
String CONFIG_LOCATION_DELIMITERS = ",; \t\n”;
。。。
public BeanDefinition parse(Element element, ParserContext parserContext) {
//获取basepackage标签
String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
//多个包可以按照分隔符开区分
String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
//初始化scanner
ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
//执行扫描有bean定义的地方,它会扫描到包下面所有的注册文件
Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
//处理一些后置处理器,并触发通知
registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
return null;
}
复制代码
-
初始化scanner
protected ClassPathBeanDefinitionScanner configureScanner(ParserContext parserContext, Element element) { boolean useDefaultFilters = true; //使用默认scanner要扫描的注解 if (element.hasAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE)) { //节点上可以配置是否使用 useDefaultFilters = Boolean.valueOf(element.getAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE)); } //初始化 ClassPathBeanDefinitionScanner scanner = createScanner(parserContext.getReaderContext(), useDefaultFilters); ... } //scanner构造函数 public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters, Environment environment, @Nullable ResourceLoader resourceLoader) { …. if (useDefaultFilters) { //注册默认要使用的注解 registerDefaultFilters(); } ... } protected void registerDefaultFilters() { //使用包含了Commponent的 this.includeFilters.add(new AnnotationTypeFilter(Component.class)); ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader(); 。。。 //包含了注解 javax.annotation.ManagedBean this.includeFilters.add(new AnnotationTypeFilter( ((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false)); 。。。 //包含了注解 javax.inject.Named this.includeFilters.add(new AnnotationTypeFilter( ((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false)); 。。。 } 复制代码
对应从源码上可以看到Component注解存在一下几个别名
- Controller:它是一种特殊的Component,使得用了这个注解的类能够被自动的通过路径扫描扫描到,经常与RequestMapping一起使用
- Repository:本身是起源与DDD设计模式,当然对于传统的Java的DAO层也是适用的。
- Service:本身起源与DDD,同样适用于业务服务层 -configuration:他表示当前的类会有多个Bean注解的方法,Spring容器会来自动产生它bean的定义,服务在运行时会需要用到这些bean 使用时建议按照自身的语义来分别使用对应的注解
-
扫描
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
...
for (String basePackage : basePackages) {
//根据初始化的过滤器,获取整个包下面的有对应注解的类,作为bean的定义返回
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
。。。
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
...
//注册bean
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
...
}
复制代码
注册是通过BeanDefinitionReaderUtils.registerBeanDefinition
工具实现,核心方法为
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
...
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
...
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
if (hasBeanCreationStarted()) {
synchronized (this.beanDefinitionMap) {
//将bean放入到beanDefinitionMap中,它实际就是一个ConcurrentHashMap
this.beanDefinitionMap.put(beanName, beanDefinition);
...
}
}
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
...
}
this.frozenBeanDefinitionNames = null;
}
...
}
复制代码
至此bean注册到beanFactory结束
prepareBeanFactory
配置一个beanFactory的标准特征,比如类加载器,后置处理器等,这些都是bean声明周期中必须存在的
...
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
...
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
...
复制代码
postProcessBeanFactory
设置beanFactory的后置处理器。对于xmlwebapplicationcontext,会继续加载Servlet相关,以及web请求的作用域(request/session)等等
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
...
beanFactory.ignoreDependencyInterface(ServletContextAware.class);
beanFactory.ignoreDependencyInterface(ServletConfigAware.class);
...
}
复制代码
bean声明周期的全部初始化方法和标准顺序如下,执行到对应的位置,会调用对应的方法
- BeanNameAware's {@code setBeanName}
- BeanClassLoaderAware's {@code setBeanClassLoader}
- BeanFactoryAware's {@code setBeanFactory}
- EnvironmentAware's {@code setEnvironment}
- EmbeddedValueResolverAware's {@code setEmbeddedValueResolver}
- ResourceLoaderAware's {@code setResourceLoader}(only applicable when running in an application context)
- ApplicationEventPublisherAware's {@code setApplicationEventPublisher}(only applicable when running in an application context)
- MessageSourceAware's {@code setMessageSource}(only applicable when running in an application context)
- ApplicationContextAware's {@code setApplicationContext}(only applicable when running in an application context)
- ServletContextAware's {@code setServletContext}(only applicable when running in a web application context)
- {@code postProcessBeforeInitialization} methods of BeanPostProcessors
- InitializingBean's {@code afterPropertiesSet}
- a custom init-method definition
- {@code postProcessAfterInitialization} methods of BeanPostProcessors
finishBeanFactoryInitialization
初始化所有剩下的非懒加载的bean
String FACTORY_BEAN_PREFIX = "&”;
…
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
//对于有懒加载标记的,都不初始化
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
//单独处理FactoryBean,工厂bean的会自动添加一个前缀 &
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
...
//需要初始化,则执行初始化
getBean(beanName);
...
}
}
else {
//非工厂bean的初始化
getBean(beanName);
}
}
}
...
复制代码
getBean实现在AbstractBeanFactory的doGetBean方法
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
final String beanName = transformedBeanName(name);
//这个bean本身
Object bean;
//bean工厂
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
//bean工厂存在。
...
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
if (isPrototypeCurrentlyInCreation(beanName)) {
//有个相同名字的bean正在创建,这里就可以看到循环引用的一个提示了~ `Requested bean is currently in creation: Is there an unresolvable circular reference?`
throw new BeanCurrentlyInCreationException(beanName);
}
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
//存在父工厂,就从它这儿获取bean
}
if (!typeCheckOnly) {
//标记开始创建bean了
markBeanAsCreated(beanName);
}
...
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
//获取这个bean依赖的bean
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
//如果正在创建的bean和它依赖的bean存在依赖关系,说明有循环引用
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
try {
//获取依赖的bean
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
//如果依赖的bean不存在,那么就会抛出bean依赖不存在的异常
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
//最后创建bean本身,根据bean的作用域的不同,创建方式各异
if (mbd.isSingleton()) {
//对于单例,使用synchronized 方法锁定真个方法,使它同步,然后从缓存中查看bean是否存在,不存在通过传入的工厂函数获取能够产生bean的对应的工厂,这里的函数式就是工厂,产生bean的工厂方法就是createBean
sharedInstance = getSingleton(beanName, () -> {
。。。
return createBean(beanName, mbd, args);
。。。
});
//从工厂中获取bean
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
//如果是prototype则每次创建一个新的bean
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
//如果配置的bean的作用域有问题,则抛出异常,无法识别的bean scop
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
//执行对应scope的初始化
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
...
}
}
...
}
...
}
return (T) bean;
}
复制代码
FactoryBean
对于实现它的类,都是作为一个工厂来使用。它的实例包括 ProxyFactoryBean,用来作为AOP的代理bean生产者 在bean的创建过程中,方法 getObjectForBeanInstance
这是bean与bean工厂在IoC启动容器的过程中产生交汇
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
//beanINstance表示bean的实例,name可能包含原始的工厂前缀,beanName纯粹bean的名字
。。。
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
//如果name表明,它本身是一个工厂,那么这个工厂本身就是需要创建的bean
return beanInstance;
}
//走到这里,说明要创建的bean不是一个工厂,从工厂中创建
Object object = null;
if (mbd == null) {
//从缓存中获取工厂bean
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
//缓存中没有,将工厂向上转型
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
//从FactoryBean中获取bean
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
复制代码
从FactoryBean中获取bean,它的核心实现就是执行 object = factory.getObject();
,比如在上面初始化过程中,就是调用匿名工厂bean的方法,里面就是调用了creatBean方法,对应的代理类,则执行代理类的getObject方法
创建bean
创建bean过程实现在它的子类AbstractAutowireCapableBeanFactory中
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
。。。
//先尝试从初始化之前的处理器获得bean
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
…
//创建实例,如果有工厂就从创建,否则使用构造函数,autowire等等方式构建
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
...
}
复制代码
至此bean的初始化完毕
整个启动过程结束。