Spring容器原理及源码学习

Spring容器原理及源码学习

一、基本原理

在我看来,Spring的IOC容器,可以看作是一个Map,我们把我们的bean实例交给他管理,同时由它来管理各个实例的引用关系。需要使用的客户端直接获取实例就行。

二、IOC容器启动时的加载过程

明白了它的原理之后,我们来看看容器启动时是如何进行初始化的。

1. org.springframework.web.context.ContextLoaderListener
  • 首先我们都会在项目中的web.xml配置一个监听器(ServletContextListener的实现),这个监听器将会在web容器启动时启动。
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
  • ContextLoaderListener除了是监听器外,继承了ContextLoader,所以监听器启动时调用ContextLoader的initWebApplicationContext方法进行Spring的WebApplicationContext上的初始化工作。
// 继承了ContextLoader
public class ContextLoaderListener extends ContextLoader implements ServletContextListener

//启动时调用
public void contextInitialized(ServletContextEvent event) {
        this.contextLoader = createContextLoader();
        if (this.contextLoader == null) {
            this.contextLoader = this;
        }
        this.contextLoader.initWebApplicationContext(event.getServletContext());
}
  • initWebApplicationContext方法
//初始化后的Context放在这个成员域。这里可能会说到单例问题,后面会讲到refresh方法加了同步锁。
private WebApplicationContext context;

//校验是否已经存在,如果不存在实例化一个Context
if (this.context == null) {
    this.context = createWebApplicationContext(servletContext);
}
//实例化具体哪个实现类,在determineContextClass方法中进行决定。可以通过在web.xml中指定<context-param>的param指定contextClass。实际有默认策略,配置在spring-web-4.3.10.RELEASE.jar!\org\springframework\web\context\ContextLoader.properties文件内。
contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());

//得到的类名为 org.springframework.web.context.support.XmlWebApplicationContext
Class<?> contextClass = determineContextClass(sc);

//初始化Context的主要入口
configureAndRefreshWebApplicationContext(cwac, servletContext);

//将初始化后的值放回servletContext org.springframework.web.context.support.XmlWebApplicationContext.ROOT
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
  • configureAndRefreshWebApplicationContext
    配置文件的解析和容器的初始化
    1. 通过Environment初始化properties
    2. 实例化 ApplicationContextInitializer
    3. 调用refresh
org.springframework.web.context.ContextLoader#configureAndRefreshWebApplicationContext
//1. 读取properties文件
ConfigurableEnvironment env = wac.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
    ((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
}
//2. 实例化 ApplicationContextInitializer
customizeContext(sc, wac);
//3. 主要下面要讲的容器初始化
wac.refresh();
2. 初始化容器refresh()
  • 主要流程基本在这个方法,所以这里也是着重要介绍的。
  • 整个过程是加锁的
org.springframework.context.support.AbstractApplicationContext#refresh

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);

            //Register bean processors that intercept bean creation.
            registerBeanPostProcessors(beanFactory);

            //Initialize message source for this context.
            initMessageSource();

            //Initialize event multicaster for this context.
            initApplicationEventMulticaster();

            //Initialize other special beans in specific context subclasses.
            onRefresh();

            //Check for listener beans and register them.
            registerListeners();

            //Instantiate all remaining (non-lazy-init) singletons.
            finishBeanFactoryInitialization(beanFactory);

            //Last step: publish corresponding event.
            finishRefresh();
        } catch (BeansException ex) {
        }
    }
}
① prepareRefresh()

这是第一步为初始化做准备,记录启动时间、active标记、init和验证properties(上面也提到过,区别是什么这一次传入了servletConifig只是替换与之相关的一些默认值)

org.springframework.context.support.AbstractApplicationContext#prepareRefresh

protected void prepareRefresh() {
    this.startupDate = System.currentTimeMillis();
    this.closed.set(false);
    this.active.set(true);

    if (logger.isInfoEnabled()) {
        logger.info("Refreshing " + this);
    }

    // Initialize any placeholder property sources in the context environment
    initPropertySources();

    // Validate that all properties marked as required are resolvable
    // see ConfigurablePropertyResolver#setRequiredProperties
    getEnvironment().validateRequiredProperties();

    // Allow for the collection of early ApplicationEvents,
    // to be published once the multicaster is available...
    this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}

这里写图片描述

② obtainFreshBeanFactory()

获得一个BeanFactory,这里是真正的对所有配置文件中的及其他一些配置的加载。BeanFactory真正存放着所有的bean定义信息及单示例。
1. 刷新BeanFactoery读取配置的bean:refreshBeanFactory

org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory

protected final void refreshBeanFactory() throws BeansException {
    //1.如果已经存在销毁
    if (hasBeanFactory()) {
        destroyBeans();
        closeBeanFactory();
    }
    try {
        //2.直接new一个DefaultListableBeanFactory实例
        DefaultListableBeanFactory beanFactory = createBeanFactory();
        beanFactory.setSerializationId(getId());
        //3.设置两个属性:allowBeanDefinitionOverriding,allowCircularReferences
        //spring 3.29中多了这一行beanFactory.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
        customizeBeanFactory(beanFactory);
        //4. 从xml配置文件中加载bean的定义信息BeanDefinitions放到beanFactory。实际每个bean有一个对应的beanDfinitions,里面存放了bean的属性,比如是否单例等等。
        loadBeanDefinitions(beanFactory);
        synchronized (this.beanFactoryMonitor) {
            this.beanFactory = beanFactory;
        }
    }
    catch (IOException ex) {
    }
}
  1. loadBeanDefinitions(beanDefinitionReader);
    读取configLocations中配置的applicationContext配置文件
org.springframework.web.context.support.XmlWebApplicationContext#loadBeanDefinitions(org.springframework.beans.factory.xml.XmlBeanDefinitionReader)

//还记得在web.xml中配置的configLocations,就是在这遍历调用。
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
    String[] configLocations = getConfigLocations();
    if (configLocations != null) {
        for (String configLocation : configLocations) {
            reader.loadBeanDefinitions(configLocation);
        }
    }
}
  1. doLoadBeanDefinitions(InputSource inputSource, Resource resource)
    后面调用此方法实际对xml文件进行读取和和注册到beanFactory
org.springframework.beans.factory.xml.XmlBeanDefinitionReader#doLoadBeanDefinitions

    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
            throws BeanDefinitionStoreException {
        try {
            Document doc = doLoadDocument(inputSource, resource);
            return registerBeanDefinitions(doc, resource);
        }
        catch (BeanDefinitionStoreException ex) {
        }
    }
  1. doRegisterBeanDefinitions(Element root)
    从根元素开始解析,就是beans节点
org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions

protected void doRegisterBeanDefinitions(Element root) {
    preProcessXml(root);
    //遍历解析文件内的各种子节点
    parseBeanDefinitions(root, this.delegate);
    postProcessXml(root);

    this.delegate = parent;
}
  1. parseBeanDefinitions遍历解析文件内的各种子节点
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    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;
                //通过nameSpace判断是由谁来解析。
                if (delegate.isDefaultNamespace(ele)) {
                    //默认的为xmlns="http://www.springframework.org/schema/beans"
                    //解析spring默认的4种节点
                    parseDefaultElement(ele, delegate);
                }
                else {
                    //扩展的,比如:aop、dubbo的都走这里进行加载,各自自定义的解析方法META-INF\spring.handlers配置文件中指定了
                    delegate.parseCustomElement(ele);
                }
            }
        }
    }
    else {
        delegate.parseCustomElement(root);
    }
}
  1. parseDefaultElement默认的spring的4种节点各自处理
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
    //import节点直接递归加载一个新的xml文件
    if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
        importBeanDefinitionResource(ele);
    }
    else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
        //alias 别名节点,直接加载到beanFactory
        processAliasRegistration(ele);
    }
    else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
        //bean节点,BeanDefinition注册到beanFactory中。
        processBeanDefinition(ele, delegate);
    }
    else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
        // beans 是一个root节点,递归解析
        doRegisterBeanDefinitions(ele);
    }
}

以上就是读取bean配置信息的一个完整过程

③ prepareBeanFactory(beanFactory);
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    // Tell the internal bean factory to use the context's class loader etc.
    beanFactory.setBeanClassLoader(getClassLoader());
    beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
    beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

    // 配置Aware处理器,Aware接口提供给使用方实现,容器通过这个处理器调用
    //这些Aware就是下面被ignore的几种,具体调用怎么调用ApplicationContextAwareProcessor里查看
    beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
    // 将以下接口添加到一个Set集合,默认时只有BeanFactory在这个集合,集合内的接口对应的bean将忽略依赖校验以及自动装配。(ApplicationContextAware是不是很熟悉哈)
    //private final Set<Class<?>> ignoredDependencyInterfaces = new HashSet<Class<?>>();
    beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
    beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
    beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
    beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

    // 将以下类对应的装配实例,put到一个Map中resolvableDependencies
    /** Map from dependency type to corresponding autowired value */
    // private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap<Class<?>, Object>(16);
    beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
    beanFactory.registerResolvableDependency(ResourceLoader.class, this);
    beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
    beanFactory.registerResolvableDependency(ApplicationContext.class, this);

    //  /** BeanPostProcessors to apply in createBean */
    // 添加到private final List<BeanPostProcessor> beanPostProcessors = new ArrayList<BeanPostProcessor>();
    beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

    // Detect a LoadTimeWeaver and prepare for weaving, if found.
    if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
        beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
        // Set a temporary ClassLoader for type matching.
        beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }

    /** Cache of singleton objects: bean name --> bean instance */
    // private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
    //注册环境相关的单例到singletonObjects
    if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
        beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
    }
    if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
        beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
    }
    if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
        beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
    }
}
④ postProcessBeanFactory(beanFactory);

后置处理器,添加servletContextAwareProcessor

protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    //ServletContextAware,ServletConfigAware处理器
    beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
    beanFactory.ignoreDependencyInterface(ServletContextAware.class);
    beanFactory.ignoreDependencyInterface(ServletConfigAware.class);
    //request,response,session等Scope对象注册到
    //private final Map<String, Scope> scopes = new LinkedHashMap<String, Scope>(8);
    // 同时注册ServletRequest,ServletResponse,HttpSession,WebRequest等的实例到resolvableDependencies
    WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
    //注册"contextParameters", "contextAttributes"等web环境的beanFactory
    WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
}
⑤ invokeBeanFactoryPostProcessors(beanFactory);

执行已经注册的后置处理器

⑥ registerBeanPostProcessors(beanFactory);

注册一些后置处理器

⑦ initMessageSource();

MessageSource我也不知道是什么

⑧ initApplicationEventMulticaster();
⑨ onRefresh();

初始化一些特殊的bean实例

⑩ registerListeners();

注册监听器的bean

(11) finishBeanFactoryInitialization(beanFactory);

初始化所有的单例bean实例,除了设置了懒加载的。通过getBean(beanName);

(12) finishRefresh();
protected void finishRefresh() {
    // lifecycleProcessor 实例初始化
    initLifecycleProcessor();

    // 
    getLifecycleProcessor().onRefresh();

    // 发布context刷新事件
    publishEvent(new ContextRefreshedEvent(this));

    // Participate in LiveBeansView MBean, if active.
    LiveBeansView.registerApplicationContext(this);
}

三、获取bean实例:getBean

获取bean实例

org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean

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;
    // 1. 首先从Map<String, Object> earlySingletonObjects获取缓存的早期的实例
    // Eagerly check singleton cache for manually registered singletons.
    Object sharedInstance = getSingleton(beanName);
    //找到bean的话,获取实例。(标记1)这里下面单独讲
    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);

    //2. 如果失败,检查是否已经在当前线程创建实例,是的话异常。(可能是循环引用)
    //private final ThreadLocal<Object> prototypesCurrentlyInCreation   
    if (isPrototypeCurrentlyInCreation(beanName)) {
        throw new BeanCurrentlyInCreationException(beanName);
    }

    //3. 如果类在当前beanFactory中找不到Definition尝试从父BeanFactory找
    BeanFactory parentBeanFactory = getParentBeanFactory();
    if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
        // Not found -> check parent.
        String nameToLookup = originalBeanName(name);
        if (args != null) {
            // Delegation to parent with explicit args.
            return (T) parentBeanFactory.getBean(nameToLookup, args);
        }
        else {
            // No args -> delegate to standard getBean method.
            return parentBeanFactory.getBean(nameToLookup, requiredType);
        }
    }

    //4. 校验是否已经在Set<String> alreadyCreated有,没有增加
    if (!typeCheckOnly) {
        markBeanAsCreated(beanName);
    }
    //5. 下面要开始创建实例了,首先获取RootBeanDefinition
    final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);

    //6. 获取依赖的bean对应的实例,如果互相引用用,将抛异常。
    String[] dependsOn = mbd.getDependsOn();
    if (dependsOn != null) {
        for (String dep : dependsOn) {
            if (isDependent(beanName, dep)) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
            }
            //Map<String, Set<String>> dependentBeanMap 在被依赖bean的set集合新增当前bean
            //这样,就可以知道同一个bean被其他的什么bean依赖了
            registerDependentBean(dep, beanName);
            //获取被依赖的bean的实例
            getBean(dep);
        }
    }
    //7. 如果被创建bean是一个单例,创建当前实例并返回
    if (mbd.isSingleton()) {
        sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
            @Override
            public Object getObject() throws BeansException {
                try {
                    //创建实例,这里有调用一些后置程序,下面单独拉出来讲 (标记2)
                    return createBean(beanName, mbd, args);
                }
                catch (BeansException ex) {
                    destroySingleton(beanName);
                    throw ex;
                }
            }
        });
        //(标记1)获取实例
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
    }
    else if (mbd.isPrototype()) {
        //8. 如果是非单例(prototype)创建一个实例
        // It's a prototype -> create a new instance.
        Object prototypeInstance = null;
        try {
            //ThreadLocal<Object> prototypesCurrentlyInCreation校验在当前线程是否正在创建实例中
            beforePrototypeCreation(beanName);
            //创建实例。(标记2)
            prototypeInstance = createBean(beanName, mbd, args);
        }
        finally {
            //与beforePrototypeCreation相对应,从prototypesCurrentlyInCreation移除
            afterPrototypeCreation(beanName);
        }
        //(标记1)
        bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
    } else {
        //9. 以上都不是,那么检查是否在request,session等scope中有,没有则创建。(较少用)
        String scopeName = mbd.getScope();
        final Scope scope = this.scopes.get(scopeName);
        if (scope == null) {
            throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
        }
        try {
            Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
                @Override
                public Object getObject() throws BeansException {
                    beforePrototypeCreation(beanName);
                    try {
                        //标记2
                        return createBean(beanName, mbd, args);
                    }
                    finally {
                        afterPrototypeCreation(beanName);
                    }
                }
            });
            //标记1
            bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
        }
    }
    return (T) bean;
}

标记2:createBean(beanName, mbd, args)

这里其实就是根据一个RootBeanDefinition去创建一个bean的实例。

protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {

    RootBeanDefinition mbdToUse = mbd;

    // 对于一些特殊的动态的beanDefinition可能需要拷贝一份再使用
    Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
    if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
        mbdToUse = new RootBeanDefinition(mbd);
        mbdToUse.setBeanClass(resolvedClass);
    }

    // 为需要IOC重写的方法
    try {
        mbdToUse.prepareMethodOverrides();
    } catch (BeanDefinitionValidationException ex) {
    }

    try {
        //可以从BeanPostProcessors提供一个代理实现类。执行InstantiationAwareBeanPostProcessor。【1】
        Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
        if (bean != null) {
            return bean;
        }
    }
    catch (Throwable ex) {
    }
    // 创建实例
    Object beanInstance = doCreateBean(beanName, mbdToUse, args);
    return beanInstance;
}

------doCreateBean
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
    throws BeanCreationException {

// 创建bean实例
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
    instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
    instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
mbd.resolvedTargetType = beanType;


// 如果是一个很急切需要的实例,先添加到单例的容器里singletonFactories
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
        isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
    addSingletonFactory(beanName, new ObjectFactory<Object>() {
        @Override
        public Object getObject() throws BeansException {
            return getEarlyBeanReference(beanName, mbd, bean);
        }
    });
}

// 填充bean属性,并自动装配bean的属性。
Object exposedObject = bean;
try {
    populateBean(beanName, mbd, instanceWrapper);
    if (exposedObject != null) {
        exposedObject = initializeBean(beanName, exposedObject, mbd);
    }
}
catch (Throwable ex) {
}

// Register bean as disposable.
try {
    // Map<String, Object> disposableBeans
    registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
}

return exposedObject;
}

标记1:getObjectForBeanInstance(scopedInstance, name, beanName, mbd)

由createBean后得到了bean的实例。但其实有些实例是工厂类,所以getBean真正需要返回的是工厂类生成的一个真正的实例。这个工厂就是FactoryBean的实现类。

org.springframework.beans.factory.support.AbstractBeanFactory#getObjectForBeanInstance

1. 不是FactoryBean的实现类,也不是&开头的beanName之前返回bean实例。
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
    return beanInstance;
}
2. 如果是工厂bean,通过工厂bean的getObject方法获取实例
object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
    @Override
    public Object run() throws Exception {
            //获取实例
            return factory.getObject();
        }
    }, acc);

BeanFactory和FactoryBean

BeanFactory :实际就是SpringIOC的容器,存放这bean的定义信息,实例等
FactoryBean:一种特殊的bean,存放于BeanFactory,通过它获取某类实例。

四、总结

通过上面的代码阅读,基本了解IOC器的一个加载过程和bean实例初始化和获取。当然这只是一个主要流程的学习,如果想要理解具体的实现细节,可以再分析一些重要的接口设计等。比如:BeanFactory、ApplicationContext等。
可以参考:http://blog.csdn.net/lisongjia123/article/details/52129340

写得有点粗糙,可能有很多问题,希望理解和指正!

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值