最近在使用Spring MVC过程当中遇到了一些问题,网上搜索很多帖子后虽然找到了答案和解决方法,但这些答案大部分都只是给告终论,并无说明具体缘由,感受老是有点不太满意。html
更重要的是这些所谓的结论大可能是抄来抄去,基本源自一家,真实性也有待考证。java
要成为一名优秀的码农,不只能熟练的复制粘贴,更要有打破砂锅问到底的精神,达到知其然也知其因此然的境界。node
那做为程序员怎么能知其因此然呢?git
答案就是阅读源代码!程序员
此处请你们心里默读三遍。github
用过Spring 的人都知道其核心就是IOC和AOP,所以要想了解Spring机制就得先从这两点入手,本文主要经过对IOC部分的机制进行介绍。web
在开始阅读以前,先准备好如下实验材料。spring
Spring 5.0源码(github.com/spring-proj…)api
IDE:Intellij IDEAbash
IDEA 是一个优秀的开发工具,若是还在用Eclipse的建议切换到此工具进行。
IDEA有不少的快捷键,在分析过程当中建议你们多用Ctrl+Alt+B快捷键,能够快速定位到实现函数。
Spring bean的加载主要分为如下6步:
查看源码第一步是找到程序入口,再以入口为突破口,一步步进行源码跟踪。
Java Web应用中的入口就是web.xml。
在web.xml找到ContextLoaderListener ,此Listener负责初始化Spring IOC。
contextConfigLocation参数设置了bean定义文件地址。
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:spring.xml</param-value>
</context-param>
复制代码
下面是ContextLoaderListener的官方定义:
public class ContextLoaderListener extends ContextLoader implements ServletContextListener
Bootstrap listener to start up and shut down Spring's root WebApplicationContext. Simply delegates to ContextLoader as well as to ContextCleanupListener.
翻译过来ContextLoaderListener做用就是负责启动和关闭Spring root WebApplicationContext。
具体WebApplicationContext是什么?开始看源码。
package org.springframework.web.context;
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
public ContextLoaderListener() {
}
public ContextLoaderListener(WebApplicationContext context) {
super(context);
}
//servletContext初始化时候调用
public void contextInitialized(ServletContextEvent event) {
this.initWebApplicationContext(event.getServletContext();
}
//servletContext销毁时候调用
public void contextDestroyed(ServletContextEvent event) {
this.closeWebApplicationContext(event.getServletContext());
}
}
复制代码
从源码看出此Listener主要有两个函数,一个负责初始化WebApplicationContext,一个负责销毁。
继续看initWebApplicationContext函数。
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
//初始化Spring容器时若是发现servlet 容器中已存在根Spring容根器则抛出异常,证实rootWebApplicationContext只能有一个。
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!");
}
if (this.context == null) {
//1.建立webApplicationContext实例
this.context = createWebApplicationContext(servletContext);
}
if (this.context instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
//2.配置WebApplicationContext
configureAndRefreshWebApplicationContext(cwac, servletContext);
}
//3.把生成的webApplicationContext 设置为root webApplicationContext。
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
return this.context;
}
复制代码
在上面的代码中主要有两个功能:
进入CreateWebAPPlicationContext函数
protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
//获得ContextClass类,默认实例化的是XmlWebApplicationContext类
Class<?> contextClass = determineContextClass(sc);
//实例化Context类
return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
}
复制代码
进入determineContextClass函数。
protected Class<?> determineContextClass(ServletContext servletContext) {
// 此处CONTEXT_CLASS_PARAM = "contextClass"String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
if (contextClassName != null) {
//若设置了contextClass则使用定义好的ContextClass。
return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
}
else {
//此处获取的是在Spring源码中ContextLoader.properties中配置的org.springframework.web.context.support.XmlWebApplicationContext类。
contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
}
复制代码
进入configureAndReFreshWebApplicaitonContext函数。
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
//webapplicationContext设置servletContext.
wac.setServletContext(sc);
// 此处CONFIG_LOCATION_PARAM = "contextConfigLocation",即读即取web.xm中配设置的contextConfigLocation参数值,得到spring bean的配置文件.
String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
if (configLocationParam != null) {
//webApplicationContext设置配置文件路径设。
wac.setConfigLocation(configLocationParam);
}
//开始处理bean
wac.refresh();
}
复制代码
上面wac变量声明为ConfigurableWebApplicationContext类型,ConfigurableWebApplicationContext又继承了WebApplicationContext。
WebApplication Context有不少实现类。 但从上面determineContextClass得知此处wac其实是XmlWebApplicationContext类,所以进入XmlWebApplication类查看其继承的refresh()方法。
沿方法调用栈一层层看下去。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
//获取beanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 实例化全部声明为非懒加载的单例bean
finishBeanFactoryInitialization(beanFactory);
}
}
复制代码
获取beanFactory。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//初始化beanFactory
refreshBeanFactory();
return beanFactory;
}
复制代码
beanFactory初始化。
@Override
protected final void refreshBeanFactory() throws BeansException {
DefaultListableBeanFactory beanFactory = createBeanFactory();
//加载bean定义
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
复制代码
加载bean。
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
//建立XmlBeanDefinitionReader实例来解析XML配置文件
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
initBeanDefinitionReader(beanDefinitionReader);
//解析XML配置文件中的bean。
loadBeanDefinitions(beanDefinitionReader);
}
复制代码
读取XML配置文件。
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
//此处读取的就是以前设置好的web.xml中配置文件地址
String[] configLocations = getConfigLocations();
if (configLocations != null) {
for (String configLocation : configLocations) {
//调用XmlBeanDefinitionReader读取XML配置文件
reader.loadBeanDefinitions(configLocation);
}
}
}
复制代码
XmlBeanDefinitionReader读取XML文件中的bean定义。
public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
ResourceLoader resourceLoader = getResourceLoader();
Resource resource = resourceLoader.getResource(location);
//加载bean
int loadCount = loadBeanDefinitions(resource);
return loadCount;
}
}
复制代码
继续查看loadBeanDefinitons函数调用栈,进入到XmlBeanDefinitioReader类的loadBeanDefinitions方法。
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
//获取文件流
InputStream inputStream = encodedResource.getResource().getInputStream();
InputSource inputSource = new InputSource(inputStream);
//从文件流中加载定义好的bean。
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
}
复制代码
最终将XML文件解析成Document文档对象。
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
//XML配置文件解析到Document实例中
Document doc = doLoadDocument(inputSource, resource);
//注册bean
return registerBeanDefinitions(doc, resource);
}
复制代码
上一步完成了XML文件的解析工做,接下来将XML中定义的bean注册到webApplicationContext,继续跟踪函数。
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
//使用documentRedder实例读取bean定义
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
}
复制代码
用BeanDefinitionDocumentReader对象来注册bean。
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
//读取document元素
Element root = doc.getDocumentElement();
//真正开始注册bean
doRegisterBeanDefinitions(root);
}
复制代码
解析XML文档。
protected void doRegisterBeanDefinitions(Element root) {
//预处理XML
preProcessXml(root);
//解析注册bean
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
}
复制代码
循环解析XML文档中的每一个元素。
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
//若是该元素属于默认命名空间走此逻辑。Spring的默认namespace为:http://www.springframework.org/schema/beans“
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
//对document中的每一个元素都判断其所属命名空间,而后走相应的解析逻辑
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
//若是该元素属于自定义namespace走此逻辑 ,好比AOP,MVC等。
delegate.parseCustomElement(root);
}
}
复制代码
下面是默认命名空间的解析逻辑。
不明白Spring的命名空间的能够网上查一下,其实相似于package,用来区分变量来源,防止变量重名。
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
//解析import元素
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
//解析alias元素
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
//解析bean元素
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
//解析beans元素
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
复制代码
这里咱们就不一一跟踪,以解析bean元素为例继续展开。
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//解析bean
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
// 注册bean
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
}
复制代码
解析bean元素,最后把每一个bean解析为一个包含bean全部信息的BeanDefinitionHolder对象。
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
String id = ele.getAttribute(ID_ATTRIBUTE);
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
复制代码
接下来将解析到的bean注册到webApplicationContext中。接下继续跟踪registerBeanDefinition函数。
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// 获取beanname
String beanName = definitionHolder.getBeanName();
//注册bean
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// 注册bean的别名
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
复制代码
跟踪registerBeanDefinition函数,此函数将bean信息保存到到webApplicationContext的beanDefinitionMap变量中,该变量为map类型,保存Spring 容器中全部的bean定义。
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
//把bean信息保存到beanDefinitionMap中
this.beanDefinitionMap.put(beanName, beanDefinition);
//把beanName 保存到List 类型的beanDefinitionNames属性中
this.beanDefinitionNames.add(beanName);
}
复制代码
Spring 实例化bean的时机有两个。
一个是容器启动时候,另外一个是真正调用的时候。
若是bean声明为scope=singleton且lazy-init=false,则容器启动时候就实例化该bean(Spring 默认就是此行为)。不然在调用时候再进行实例化。
相信用过Spring的同窗们都知道以上概念,可是为何呢?
继续从源码角度进行分析,回到以前XmlWebApplication的refresh()方法。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
//生成beanFactory,
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 实例化全部声明为非懒加载的单例bean
finishBeanFactoryInitialization(beanFactory);
}
复制代码
能够看到得到beanFactory后调用了 finishBeanFactoryInitialization()方法,继续跟踪此方法。
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// 初始化非懒加载的单例bean
beanFactory.preInstantiateSingletons();
}
复制代码
预先实例化单例类逻辑。
public void preInstantiateSingletons() throws BeansException {
// 获取全部注册的bean
List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);
// 遍历bean
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
//若是bean是单例且非懒加载,则获取实例
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
getBean(beanName);
}
}
}
复制代码
获取bean。
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
复制代码
doGetBean中处理的逻辑不少,为了减小干扰,下面只显示了建立bean的函数调用栈。
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
//建立bean
createBean(beanName, mbd, args);
}
复制代码
建立bean。
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
return beanInstance;
}
复制代码
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {
// 实例化bean
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
复制代码
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
//实例化bean
return instantiateBean(beanName, mbd);
}
复制代码
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
//调用实例化策略进行实例化
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName,
}
复制代码
判断哪一种动态代理方式实例化bean。
public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {
//使用JDK动态代理
if (bd.getMethodOverrides().isEmpty()) {
return BeanUtils.instantiateClass(constructorToUse);
}
else {
//使用CGLIB动态代理
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
复制代码
无论哪一种方式最终都是经过反射的形式完成了bean的实例化。
public static <T> T instantiateClass(Constructor<T> ctor, Object... args)
ReflectionUtils.makeAccessible(ctor);
return ctor.newInstance(args);
}
复制代码
咱们继续回到doGetBean函数,分析获取bean的逻辑。
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
//获取beanName
final String beanName = transformedBeanName(name);
Object bean
// 先检查该bean是否为单例且容器中是否已经存在例化的单例类
Object sharedInstance = getSingleton(beanName);
//若是已存在该bean的单例类
if (sharedInstance != null && args == null) {
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else{
// 获取父BeanFactory
BeanFactory parentBeanFactory = getParentBeanFactory();
//先判断该容器中是否注册了此bean,若是有则在该容器实例化bean,不然再到父容器实例化bean
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
String nameToLookup = originalBeanName(name);
// 若是父容器有该bean,则调用父beanFactory的方法得到该bean
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
//若是该bean有依赖bean,先实递归例化依赖bean。
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
registerDependentBean(dep, beanName);
getBean(dep);
}
}
//若是scope为Singleton执行此逻辑
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
//调用建立bean方法
return createBean(beanName, mbd, args);
}
}
});
}
//若是scope为Prototype执行此逻辑,每次获取时候都实例化一个bean
else if (mbd.isPrototype()) {
Object prototypeInstance = null;
prototypeInstance = createBean(beanName, mbd, args);
}
//若是scope为Request,Session,GolbalSession执行此逻辑
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
return createBean(beanName, mbd, args);
}
});
}
}
}
return (T) bean;
}
复制代码
上面方法中首先调用getSingleton(beanName)方法来获取单例bean,若是获取到则直接返回该bean。方法调用栈以下:
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
复制代码
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//从singletonObjects中获取bean。
Object singletonObject = this.singletonObjects.get(beanName);
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
复制代码
getSingleton方法先从singletonObjects属性中获取bean 对象,若是不为空则返回该对象,不然返回null。
那 singletonObjects保存的是什么?何时保存的呢?
回到doGetBean()函数继续分析。若是singletonObjects没有该bean的对象,进入到建立bean的逻辑。处理逻辑以下:
//获取父beanFactory
BeanFactory parentBeanFactory = getParentBeanFactory();
//若是该容器中没有注册该bean,且父容器不为空,则去父容器中获取bean后返回
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
复制代码
下面是判断容器中有没有注册bean的逻辑,此处beanDefinitionMap相信你们都不陌生,在注册bean的流程里已经说过全部的bean信息都会保存到该变量中。
public boolean containsBeanDefinition(String beanName) {
Assert.notNull(beanName, "Bean name must not be null");
return this.beanDefinitionMap.containsKey(beanName);
}
复制代码
若是该容器中已经注册过bean,继续往下走。先获取该bean的依赖bean,若是镩子依赖bean,则先递归获取相应的依赖bean。
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
registerDependentBean(dep, beanName);
getBean(dep);
}
}
复制代码
依赖bean建立完成后,接下来就是建立自身bean实例了。
获取bean实例的处理逻辑有三种,即Singleton、Prototype、其它(request、session、global session),下面一一说明。
若是bean是单例模式,执行此逻辑。
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
//建立bean回调
return createBean(beanName, mbd, args);
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
复制代码
获取单例bean,若是已经有该bean的对象直接返回。若是没有则建立单例bean对象,并添加到容器的singletonObjects Map中,之后直接从singletonObjects直接获取bean。
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
//若是singletonObjects中没有该bean
if (singletonObject == null) {
//回调参数传进来的ObjectFactory的getObject方法,即调用createBean方法建立bean实例
singletonObject = singletonFactory.getObject();
//置新建立单例bean标志位为true。
newSingleton = true;
if (newSingleton) {
//若是是新建立bean,注册新生成bean对象
addSingleton(beanName, singletonObject);
}
}
//返回获取的单例bean
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
}
复制代码
把新生成的单例bean加入到类型为MAP 的singletonObjects属性中,这也就是前面singletonObjects()方法中获取单例bean时今后Map中获取的缘由。
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
//把新生成bean对象加入到singletonObjects属性中。
this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
this.registeredSingletons.add(beanName);
}
}
复制代码
Prototype是每次获取该bean时候都新建一个bean,所以逻辑比较简单,直接建立一个bean后返回。
else if (mbd.isPrototype()) {
Object prototypeInstance = null;
//建立bean
prototypeInstance = createBean(beanName, mbd, args);
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
复制代码
else {
//获取该bean的scope
String scopeName = mbd.getScope();
//获取相应scope
final Scope scope = this.scopes.get(scopeName);
//获取相应scope的实例化对象
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
return createBean(beanName, mbd, args);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
复制代码
从相应scope获取对象实例。
public Object get(String name, ObjectFactory<?> objectFactory) {
RequestAttributes attributes = RequestContextHolder.currentRequestAttributes();
//先从指定scope中获取bean实例,若是没有则新建,若是已经有直接返回
Object scopedObject = attributes.getAttribute(name, getScope());
if (scopedObject == null) {
//回调函数调用createBean建立实例
scopedObject = objectFactory.getObject();
//建立实例后保存到相应scope中
attributes.setAttribute(name, scopedObject, getScope());
}
}
return scopedObject;
}
复制代码
判断scope,获取实例函数逻辑。
public Object getAttribute(String name, int scope) {
//scope是request时
if (scope == SCOPE_REQUEST) {
//从request中获取实例
return this.request.getAttribute(name);
}
else {
PortletSession session = getSession(false);
if (session != null) {
//scope是globalSession时,从application中获取实例
if (scope == SCOPE_GLOBAL_SESSION) {
//从globalSession中获取实例
Object value = session.getAttribute(name, PortletSession.APPLICATION_SCOPE);
return value;
}
else {
//从session中获取实例
Object value = session.getAttribute(name);
return value;
}
}
return null;
}
}
复制代码
在相应scope中设置实例函数逻辑。
public void setAttribute(String name, Object value, int scope) {
if (scope == SCOPE_REQUEST) {
this.request.setAttribute(name, value);
}
else {
PortletSession session = getSession(true);
if (scope == SCOPE_GLOBAL_SESSION) {
session.setAttribute(name, value, PortletSession.APPLICATION_SCOPE);
}
else {
session.setAttribute(name, value);
}
}
}
复制代码
以上就是Spring bean从无到有的整个逻辑。
从源码角度分析 bean的实例化流程到此基本接近尾声了。
回到开头的问题,ContextLoaderListener中初始化的WebApplicationContext究竟是什么呢?
经过源码的分析咱们知道WebApplicationContext负责了bean的建立、保存、获取。其实也就是咱们平时所说的IOC容器,只不过名字表述不一样而已。
本文主要是讲解了XML配置文件中bean的解析、注册、实例化。对于其它命名空间的解析尚未讲到,后续的文章中会一一介绍。
但愿经过本文让你们在之后使用Spring的过程当中有“一切尽在掌控之中”的感受,而不只仅是稀里糊涂的使用。
想要了解更多,关注公众号:七分熟pizza