Spring 初始化过程跟踪

1,在web.xml中有

    <listener>
        <description>spring监听器</description>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

   在这里配置了,spring的监听器

2,查看ContextLoaderListener 会发现 他继承了ContextLoader 实现了ServletContextListener接口

   因此在该类的中有contextInitialized(ServletContextEvent event)方法,该方法调用了initWebApplicationContext(event.getServletContext())

3,initWebApplicationContext方法在ContextLoader类中,该方法中主要代码如下:

try {
            // Store context in local instance variable, to guarantee that
            // it is available on ServletContext shutdown.
            if (this.context == null) {
                this.context = createWebApplicationContext(servletContext);
            }
            if (this.context instanceof ConfigurableWebApplicationContext) {
                ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
                if (!cwac.isActive()) {
                    // The context has not yet been refreshed -> provide services such as
                    // setting the parent context, setting the application context id, etc
                    if (cwac.getParent() == null) {
                        // The context instance was injected without an explicit parent ->
                        // determine parent for root web application context, if any.
                        ApplicationContext parent = loadParentContext(servletContext);
                        cwac.setParent(parent);
                    }
                    configureAndRefreshWebApplicationContext(cwac, servletContext);
                }
            }
            servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

            ClassLoader ccl = Thread.currentThread().getContextClassLoader();
            if (ccl == ContextLoader.class.getClassLoader()) {
                currentContext = this.context;
            }
            else if (ccl != null) {
                currentContextPerThread.put(ccl, this.context);
            }

再来看上面这段代码:首先,判断该类中的context属性是否为空,如果为空创建context,使用createWebApplicationContext(servletContext);这个方法。

然后再看this.context 是不是ConfigurableWebApplicationContext 的子类,如果是则强制转换为ConfigurableWebApplicationContext,然后判断该对象是不是可用的,这个可用,源代码中的注释里有这样的解释:Determine whether this application context is active, that is, whether it has been refreshed at least once and has not been closed yet.

由此可以看出当最近刷新过或者没有bean被回收等的时候,该对象应该才是被激活的或者说可用的。这里理解的不是太准确还请大神指点。

如果不是可用的则进入if语句,判断Context的上级context 是不是为空,如果为空则加载上级Context使用loadParentContext(servletContext) 方法,然后设置上级Context,做完这些之后,再执行configureAndRefreshWebApplicationContext(cwac, servletContext); 该方法是初始化中主要的方法,bean的加载等都建在该类中进行,暂且不说。

然后将WebApplicationContext设置到servletContext中,这样就做到了,Spring 中的Context与Servlet中的Context的交互,再接着下来就是设置当前Context,将类加载器和当前WebApplicationContext对应的放在Map中。

再回头来看configureAndRefreshWebApplicationContext(cwac, servletContext);方法:还是在ContextLoader类中,在这个方法中,首先servletContext会初始化一个contextid,set给ConfigurableWebApplicationContext ,在这个方法中最重要的内容是下面的这段代码:

     1   wac.setServletContext(sc);
     2   String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
     3   if (configLocationParam != null) {
     4      wac.setConfigLocation(configLocationParam);
     5   }

        // The wac environment's #initPropertySources will be called in any case when the context
        // is refreshed; do it eagerly here to ensure servlet property sources are in place for
        // use in any post-processing or initialization that occurs below prior to #refresh
     6   ConfigurableEnvironment env = wac.getEnvironment();
     7   if (env instanceof ConfigurableWebEnvironment) {
     8       ((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
           }

     9   customizeContext(sc, wac);
    10  wac.refresh();

在第2行 有CONFIG_LOCATION_PARAM 常量org.springframework.web.context.ContextLoader.CONFIG_LOCATION_PARAM = "contextConfigLocation"

从这里可以知道下面将开始加载Spring的配置文件了(Spring-Context.xml 或者别的名称)再往下看,到第9行这里,当webApplication中的属性参数都设置完成之后,

执行customizeContext这个方法,在该方法中有这样的代码:

       for (Class<ApplicationContextInitializer<ConfigurableApplicationContext>> initializerClass : initializerClasses) {
            Class<?> initializerContextClass =
                    GenericTypeResolver.resolveTypeArgument(initializerClass, ApplicationContextInitializer.class);
            if (initializerContextClass != null) {
                Assert.isAssignable(initializerContextClass, wac.getClass(), String.format(
                        "Could not add context initializer [%s] since its generic parameter [%s] " +
                        "is not assignable from the type of application context used by this " +
                        "context loader [%s]: ", initializerClass.getName(), initializerContextClass.getName(),
                        wac.getClass().getName()));
            }
            this.contextInitializers.add(BeanUtils.instantiateClass(initializerClass));
        }

        AnnotationAwareOrderComparator.sort(this.contextInitializers);
        for (ApplicationContextInitializer<ConfigurableApplicationContext> initializer : this.contextInitializers) {
            initializer.initialize(wac);
        }

由此可以看到,在这里扫描了spring的配置文件,并且创建了配置文件中的bean和注解标注的Java bean,如果再跟进去就是BeanUtil中的内容,

是通过反射创建java bean的过程了,到此Spring的IOC的加载过程告一段落!!

如有错误的地方希望大神指出来!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring 框架是一个开源的Java应用框架,其核心思想是IoC(控制反转)和AOP(面向切面编程)。Spring 框架源码非常庞大,涵盖了各个模块和功能的实现,其中核心模块是 Spring Framework。我可以为您提供一些关于 Spring 源码分析的指导: 1. 理解整体结构:首先,您需要了解 Spring 框架的整体结构,从高层次了解各个模块之间的关系,包括核心容器、数据访问、Web、AOP 等模块。 2. 阅读源码:建议从 Spring Framework 的核心模块开始,阅读核心容器的源码。可以选择使用 Eclipse、IntelliJ IDEA 等集成开发环境来浏览源码,这样可以更方便地跳转到相关代码和查看方法的实现。 3. 深入理解 IoC 容器:IoC 是 Spring 框架的核心思想之一。通过阅读源码,深入理解 IoC 容器的实现原理,包括 Bean 的加载、初始化、依赖注入等过程。关注 ApplicationContext 接口及其实现类的源码。 4. 学习 AOP 的实现:AOP 是 Spring 框架另一个重要的特性。了解 AOP 的实现原理,学习关于代理模式、切面、连接点等概念。阅读 Spring AOP 模块的源码,并了解如何使用 AspectJ 注解或 XML 配置来定义切面。 5. 调试和实践:在阅读源码时,可以结合调试功能,跟踪代码的执行流程,观察对象的创建和依赖注入过程。通过实际编写一些简单的 Spring 应用程序,加深对源码的理解。 请注意,由于 Spring 源码庞大且复杂,阅读源码需要有一定的 Java 和框架知识基础,并具备耐心和时间。建议在学习过程中结合官方文档、参考书籍和社区资源,也可以参考一些开源项目中对 Spring 的使用。祝您学习愉快!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值