想要深入的熟悉了解Spring源码,我觉得第一步就是要有一个能跑起来的极尽简单的框架,下面我就教大家搭建一个最简单的Spring框架,而且是基于Java Config形式的零配置Spring框架。

首先第一步创建一个空的maven web项目,这步很简单,自行百度。

在maven项目的pom.xml文件中添加Spring基础依赖:

<properties>
            <spring.version>4.3.7.RELEASE</spring.version>
            <slf4j.version>1.7.21</slf4j.version>
            <log4j.version>2.8.2</log4j.version>
            <logging.version>1.2</logging.version>
        </properties>

        <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-framework-bom</artifactId>
                <version>${spring.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
        </dependency>

        <!-- log配置:Log4j2 + Slf4j -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>${log4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>${log4j.version}</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-web -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-web</artifactId>
            <version>${log4j.version}</version>
        </dependency>
        <dependency> <!-- 桥接:告诉Slf4j使用Log4j2 -->
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j-impl</artifactId>
            <version>${log4j.version}</version>
        </dependency>
        <dependency> <!-- 桥接:告诉commons logging使用Log4j2 -->
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-jcl</artifactId>
            <version>${log4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j.version}</version>
        </dependency>

    </dependencies>

我推荐搭建基于Java Config形式的Spring框架,不需要配置文件,全部使用Java代码形式来定义,简洁明了,对于想要深入了解Spring源码来说这点很重要,否则可能需要看非常多的Spring解析XML配置文件的解析类,对于任何人都不是很容易的功夫。而使用Java Config形式能直接看到配置类的运行流程,对了解Spring源码很有帮助。

要搭建基于Java Config形式的Spring框架,要求Servlet-api版本3.0以上,同时推荐Spring版本4.0以上,日志可以使用我另一篇博客上的log4j2的配置,自己修改下输出日志文件路径就可以了。

public class WebContextInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[] {RootContextConfig.class};
    }
}

@Configuration
@ComponentScan
public class RootContextConfig {
    @Bean
    public Child child() {
        return new Child();
    }
}
public class Child {
}

@Component
public class Mother {
}

把这几个类都放在一个包下,然后启动tomcat,应该就可以启动Spring了,这就是一个最基本的Spring框架,而且包含了Java Config的Bean的定义以及组件扫描,RootContextConfig这个类就是容器的配置类,之后就可以开始跟着Spring框架的启动流程看了,DEBUG跟着一步一步的走。

WebContextInitializer 的父类的将RootContextConfig 当做配置类生成一个AnnotationConfigWebApplicationContext 

类型ApplicationContext容器,注入到ContextLoaderListener中。 

......
    protected WebApplicationContext createRootApplicationContext() {
        Class<?>[] configClasses = getRootConfigClasses();
        if (!ObjectUtils.isEmpty(configClasses)) {
            AnnotationConfigWebApplicationContext rootAppContext = new AnnotationConfigWebApplicationContext();
            rootAppContext.register(configClasses);
            return rootAppContext;
        }
        else {
            return null;
        }
    }
    ......
    protected void registerContextLoaderListener(ServletContext servletContext) {
        WebApplicationContext rootAppContext = createRootApplicationContext();
        if (rootAppContext != null) {
            ContextLoaderListener listener = new ContextLoaderListener(rootAppContext);
            listener.setContextInitializers(getRootApplicationContextInitializers());
            servletContext.addListener(listener);
        }
        else {
            logger.debug("No ContextLoaderListener registered, as " +
                    "createRootApplicationContext() did not return an application context");
        }
    }

不要对Tomcat内的源码花时间,主要是看Spring的源码,之后就可以看ContextLoaderListener的contextInitialized(…)方法了,Spring容器就是在这个方法里初始化生成的。如何初始化,这个太复杂了,需要花非常多的时间去看,去思考的,这里就不讲了,不过我可以说一些我自己总结的小技巧:

 

说是看源码,其实应该叫看和想。Spring源码很复杂,我觉得花在思考上的时间至少要和看的时间对等。看了,如果没有花时间想明白,等于白看。

理解重于记忆。Spring的流程很长,东西很多,如果单纯靠记忆肯定记不过来的,知道每个组件的大体作用以及作用的节点就够了,源码就在那里,又不会跑,记不清了翻翻就看到了,多翻几次就能够慢慢记住了,最开始看的时候不要执着于记忆。

多做笔记。Spring组件很多,在最开始看的时候,推荐做些笔记,将每个重要接口的作用及关键代码记录下,有时间就看看,最先了解的组件是你切入Spring源码的切口,借助他们能关联到其他的组件。

多百度。在看一些关键接口或者类时,如果其代码很复杂,先百度下吧,先对其功能有个了解,然后对照着功能看代码会有很大的帮助。

要多遍地看,反复地看。别想着看一遍就能看明白,在最开始的几次跟着初始化流程看源码时,不要执着于某个细节。先对Spring所有的组件功能有个大体了解,对初始化流程有个大体的了解,这是深入的基础。

多看日志,多DEBUG。多看日志能够提高你对Spring流程的了解程度,而且在排错时能有效提高效率;DEBUG是看源码最好的一种方式,是解疑的最直接途径,对于有些运行时难以触及的代码,需要你手动创造条件让流程走入此处。

多总结,多动手。不要仅局限于看和思考,要动手。源码看的仔细,基本能从源码上看出很多Spring组件的使用方式,总结各种组件的使用方法,然后自己定义相应的组件,将其引入Spring中,查看其作用流程,这是你拓展Spring的第一步,既能增强对Spring的理解,也能提高你对Spring的拓展能力。

不断完善框架。每熟悉一种组件的使用,就添加到自己的 框架中,不断完善自己的框架,到最后你的框架能够整合Spring大部分好用组件,也是你以后回顾Spring框架的最大助力。

多看注释,看方法的名称,参数和返回值。看注释,理解类,属性和方法的作用,着重第一段注释;看方法的名称,参数和返回值能对方法的作用有很明显的说明。

 

以上就是我自己看Spring总结的一些小技巧,希望对你们有些助益。