前言

最新想学习一下Spring源码,开篇博客记录下学习过程,欢迎一块交流学习。

作为预备篇,主要演示搭建一个最简单的Spring项目样例,对Spring进行最基本梳理。

构建一个最简单的spring项目

Spring中最核心的Jar包有四个:spring-beans、spring-context、spring-core、spring-expression。

以前做spring项目有个误区,什么包都一个个导入进来,其实一个最最简单的Spring项目,理论上就需要引入一个jar包spring-context就够了,靠它的依赖关系,其他核心包都会自动导入进来(只是核心包,实际真实项目需要其他功能再额外导入)。

1、在一个空项目里 添加Spring项目模块       Maven->jdk1.8>webapp 模板

2、这里在pom中只额外添加 spring-context依赖(它依赖其他几个核心jar包 会自动导入依赖)

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>

    <spring.version>5.1.3.RELEASE</spring.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>LATEST</version>
    </dependency>

  </dependencies>

实际引入的包及依赖关系:

这样,一个最简单的spring项目就搭建好了,我们测试一下:
定义一个实体类:
 package cn.eport.jason.bean;

 @Component
 public class Student {

     private String username = "WPC";

     private String password;

     public String getUsername() {
         return username;
     }

     public void setUsername(String username) {
         this.username = username;
     }

     public String getPassword() {
         return password;
     }

     public void setPassword(String password) {
         this.password = password;
     }
 }

写一个测试方法,(因为本例中是在源代码下编写的单元测试,所以需要先在pom中去掉Junit 作用域为test的限制,不然在业务代码区使用@Test注解时会提示找不到)

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <!--<scope>test</scope>-->
    </dependency>

MyTest.java 测试类

package cn.eport.jason.test;

import cn.eport.jason.bean.Student;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MyTest {

    @Test
    public void Test1(){
        //基于注解的方式加载Spring容器
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext("cn.eport");

        Student student =(Student) applicationContext.getBean("student");
        System.out.println(student.getUsername());
    }
}

运行单元测试方法Test1 控制台输出结果:

D:\DevTool\Java\jdk1.8.0_101\bin\java.exe ... cn.eport.jason.test.MyTest,Test1
WPC

Process finished with exit code 0

说明Spring ioc容器功能已生效,已属于spring项目。

spring容器启动的4种方式

上例中使用的是使用注解的方式加载的Spring容器,其实spring还有其他几种加载容器的方式:
  • 1、类路径获取配置文件加载容器

  ApplicationContext applicationContext= new ClassPathXmlApplicationContext("spring.xml");

  • 2、文件系统路径获取配置文件【绝对路径】不常用

  ApplicationContext applicationContext = new FileSystemXmlApplicationContext("E:\\idea\\public\\springdemo\\src\\main\\resources\\spring.xml");

  • 3、无配置文件加载容器(注解方式) 单元测试中常用

  ApplicationContext applicationContext = new AnnotationConfigApplicationContext("cn.eport");

  • 4、springboot加载容器

  ApplicationContext applicationContext = new EmbeddedWebApplicationContext();

 spring容器启动可以作为spring的源码分析的入口,上述四种方式中,除了基于注解的方式外,之前比较常用的就是读取类路径下配置文件加载容器了(SpringBoot出现之后,这种方式慢慢过时),我们来使用这种方式做下测试:
 1、新建配置文件:idea下 在resources目录下右击new->XML Configuration File->springconfig 创建Spring.xml 配置文件,并添加注册bean配置(两种方式 包扫描或者bean定义注册):
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans           http://www.springframework.org/schema/beans/spring-beans.xsd           http://www.springframework.org/schema/context           http://www.springframework.org/schema/context/spring-context.xsd">
    <!-- 方式1、批量注册  包扫描+注解  -->
    <context:component-scan base-package="cn.eport"/>
    <!-- 方式2、手动注册bean 。 id不写 默认为类全限定名-->     <bean class="cn.eport.jason.bean.Student"> </bean> </beans>

这里通过两种方式注册了Student实例:

  • 一个ComonentScan扫描+注解的方式(BeanName默认类名小写)
  • 一个配置注册bean的方式(默认BeanName为类全限定名)

ps:<context:component-scan>这种带有前缀的标签 为自定义标签,spring原始组件只有 spring-core和spring-bean ,常用的context、aop、tx组件其实都是扩展组件,Spring靠的就是自定义标签在核心组件上扩展使得spring更加强大,在配置文件中使用扩展标签需要引入相应的xsd;在标签对应的jar包下面找到对应的spring.schemas,在这个文件中就会有对应的XSD路径和命名空间xmlns(xml namespaceUri) (类似于java中的Import)

2、编写对应的测试方法 使用 ClassPathXmlApplicationContext 读取配置文件加载容器获取bean对象 进行测试:

    @Test
    public void Test2(){
        //读取类路径下xml配置文件的方式加载spring容器
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("Spring.xml");

        Student student1 =(Student) applicationContext.getBean("student");//取得为包扫描+注解 方式注册的 beanId是类名小写
        Student student2 =(Student) applicationContext.getBean("cn.eport.jason.bean.Student");//取得为配置文件中缺省id 的那个bean
        System.out.println(student1.getUsername());//WPC
        System.out.println(student2.getUsername());//WPC

        System.out.println(student1==student2);//false   不同的注册方式注册的两个不同的实例对象
    }

结果:

WPC
WPC
false

Process finished with exit code 0

Spring容器一样也加载成功了,由此可以看出项目中只添加Spring-context 的依赖,一个最基础的Spring的项目即可搭建好(这里说的不是SpringMVC工程)

根据测试打印结果可以发现个问题,程序并没有打印出Spring的日志,原因为pom中未添加spring日志依赖logback:

    <!--一个空的spring工程是不能打印日志的,要导入spring依赖的日志jar-->
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>LATEST</version>
    </dependency>

再次执行下测试方法,控制台打印出Spring的日志:

 由此,构建一个带日志的最基础Spring项目,只需要在pom中添加context、logback两个依赖即可

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <!--一个空的spring工程是不能打印日志的,要导入spring依赖的日志jar-->
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>LATEST</version>
    </dependency>

但是实际上由于jar包相互依赖,项目中maven会自动导入其他依赖,实际导入的包远远不止这两个:

实际导入的包及依赖关系如下:

结语

作为开篇内容相对简单些,经过演示我们看到了pom中只添加context、logback两个依赖就可以搭建一个带日志最基本的spring项目,以及我们知道了spring源码的入口类,后续我们进行源码分析~

 

【Spring源码分析】预备篇的更多相关文章

  1. spring源码分析---事务篇

    上一篇我介绍了spring事务的传播特性和隔离级别,以及事务定义的先关接口和类的关系.我们知晓了用TransactionTemplate(或者直接用底层P的latformTransactionMana ...

  2. Spring 源码分析 spring-core 篇

    先来看下 spring-core 的包结构 总共有6个模块,分别是 asm.cglib.core.lang.objenesis.util asm包: 用来操作字节码,动态生成类或者增强既有类的功能.主 ...

  3. spring源码分析之spring-core总结篇

    1.spring-core概览 spring-core是spring框架的基石,它为spring框架提供了基础的支持. spring-core从源码上看,分为6个package,分别是asm,cgli ...

  4. Spring源码分析——BeanFactory体系之抽象类、类分析(二)

    上一篇分析了BeanFactory体系的2个类,SimpleAliasRegistry和DefaultSingletonBeanRegistry——Spring源码分析——BeanFactory体系之 ...

  5. Spring源码分析——BeanFactory体系之抽象类、类分析(一)

    上一篇介绍了BeanFactory体系的所有接口——Spring源码分析——BeanFactory体系之接口详细分析,本篇就接着介绍BeanFactory体系的抽象类和接口. 一.BeanFactor ...

  6. Spring源码分析——资源访问利器Resource之实现类分析

    今天来分析Spring的资源接口Resource的各个实现类.关于它的接口和抽象类,参见上一篇博文——Spring源码分析——资源访问利器Resource之接口和抽象类分析 一.文件系统资源 File ...

  7. spring源码分析(二)Aop

    创建日期:2016.08.19 修改日期:2016.08.20-2016.08.21 交流QQ:992591601 参考资料:<spring源码深度解析>.<spring技术内幕&g ...

  8. 【Spring源码分析】非懒加载的单例Bean初始化前后的一些操作

    前言 之前两篇文章[Spring源码分析]非懒加载的单例Bean初始化过程(上篇)和[Spring源码分析]非懒加载的单例Bean初始化过程(下篇)比较详细地分析了非懒加载的单例Bean的初始化过程, ...

  9. 【spring源码分析】IOC容器初始化(总结)

    前言:在经过前面十二篇文章的分析,对bean的加载流程大致梳理清楚了.因为内容过多,因此需要进行一个小总结. 经过前面十二篇文章的漫长分析,终于将xml配置文件中的bean,转换成我们实际所需要的真正 ...

  10. 【spring源码分析】IOC容器初始化(七)

    前言:在[spring源码分析]IOC容器初始化(六)中分析了从单例缓存中加载bean对象,由于篇幅原因其核心函数 FactoryBeanRegistrySupport#getObjectFromFa ...

随机推荐

  1. Tensorboard 详解(上篇)

    花间提壶华小厨 1. Tensorboard简介 对大部分人而言,深度神经网络就像一个黑盒子,其内部的组织.结构.以及其训练过程很难理清楚,这给深度神经网络原理的理解和工程化带来了很大的挑战.为了解决 ...

  2. Consul+upsync+Nginx 动态负载均衡

    1,动态负载均衡 传统的负载均衡,如果修改了nginx.conf 的配置,必须需要重启nginx 服务,效率不高.动态负载均衡,就是可配置化,动态化的去配置负载均衡. 2,实现方案 1. Consul ...

  3. python字典(dict)

    1.字典dict定义 初始化 key-value键值对的数据的集合,可变.无序.key不重复(哈希.唯一) 1> d = dict() 或者 d = {} # -*- coding:utf-8 ...

  4. [JZOJ5343]健美猫<模拟>

    [思路] 这个是一个非常容易看出来的模拟,但是模拟也是有技巧的 一般人的模拟思路一般就是移动元素或者下标 然后我就看到了一个有趣的思路 建立坐标轴 以i坐标为横坐标,以si为纵坐标,然后画一条斜率为1 ...

  5. 关于js在一个固定的盒子里面拖拽的问题(包含临界值)

    回武汉打卡第三天,武汉加油,逆战必胜!今天我们一起分享一下js拖拽的问题. 当然实现拖拽方法是有很多的,下面简单讲一种方法,大致思路如下: 首先需要用到的事件主要有  onmousedown,onmo ...

  6. Fetch+SpringBoot跨域请求设置

    两种方法从SpringBoot的方向解决跨域问题 今天搭建博客的时候,尝试性的传递数据,发现浏览器报了这个错误 -blocked by CORS policy: No 'Access-Control- ...

  7. 数据挖掘 决策树 Decision tree

    数据挖掘-决策树 Decision tree 目录 数据挖掘-决策树 Decision tree 1. 决策树概述 1.1 决策树介绍 1.1.1 决策树定义 1.1.2 本质 1.1.3 决策树的组 ...

  8. Java static修饰符

    Java static修饰符 static修饰符是静态修饰符,大家写Java第一次接触static就是主函数中的pubic static void main的声明了. 那么static有什么用?本文来 ...

  9. Jenkins中管道案例脚本(生命式语法)

    pipeline { agent any parameters { choice( choices: 'feature\nmaster\npercent10', description: '选择要发布 ...

  10. pm2 开机启动egg项目

    1.在服务器上安装PM2 npm install pm2 -g 2.对PM2进行更新 pm2 update 3.进入服务器中egg项目更目录,并新建server.js文件,并在其中写入以下代码 con ...