JavaEE 突击 3 - Spring 创建和使用

大家好 , 这个专栏给大家介绍一下 Java 家族的核心产品 - SSM 框架

Java 语言能走到现在 , 仍然屹立不衰的原因 , 有一部分就是因为 SSM 框架的存在

接下来 , 博主会带大家了解一下 Spring、Spring Boot、Spring MVC、MyBatis 相关知识点

并且带领大家进行环境的配置 , 让大家真正用好框架、学懂框架

在这里插入图片描述

目标 :

  1. Spring (Core) 项目创建
  2. 将对象存储到 Spring 中
  3. 将对象从 Spring 里面取出

在 Spring 里面 , 把对象叫做 Bean

一 . 创建 Spring 项目

我们接下来用 Maven 创建一个 Spring 项目

  1. 创建一个 Maven 项目
  2. 添加 Spring 框架支持 (spring-context : 上下文 spring-beans : 对象)
  3. 添加启动类

我们这里使用的环境是 IDEA 2021.2 社区版 , JDK 1.8

1.1 创建一个 Maven 项目




1.2 添加 Spring 框架依赖

添加两个引用 :

  1. spring - content : spring 上下文
  2. spring - beans : spring 对象

这一步很简单 , 我们只需要把下面这段代码复制到 pom.xml 里面
当然也可以去中央仓库里面找

<dependencies>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.3.RELEASE</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
    <version>5.2.3.RELEASE</version>
  </dependency>
</dependencies>

在这一步 , 我们一定要保证修改镜像源为国内的 , 要不然 超级大概率 会失败

我们还可以通过左侧来检验下载是否成功

我们点击上面的刷新按钮


但是我们下载的依赖只有 spring - content 和 spring - beans 啊 ? 这怎么多出来几个 ?

是这样的 , 我们的 spring - content 和 spring - beans 也是需要额外的依赖包的 , 如果单纯使用 spring - content 和 spring - beans , 也需要把它的几个依赖包导入进来 , 其实就相当于结婚的嫁妆

1.3 添加启动类

实际上就是添加 main 方法
那我们之前写 Servlet 程序 , 也没有 main 方法啊 ?

实际上 , Servlet 是隐藏 main 方法的 , 是不展示给用户的

我们这里的 Spring 程序就是一个最简单的程序 , 还是需要 main 方法的
在 java 目录底下新建一个类


二 . 将 Bean 对象存储到 Spring

存储 Bean 对象需要两步 :

  1. 存储 Bean 之前 , 先得有 Bean , 所以先创建一个 Bean 对象
  2. 将创建的 Bean 注册到 Spring 容器中

2.1 创建 Bean 对象


public class User {
    // 普通的类,普通的方法
    public void sayHi() {
        System.out.println("say hi!");
    }
}


2.2 将 Bean 存储到 Spring

在 Spring 里面 , 并不是所有的 Bean 都会被存储到 Spring 里面 , 只有需要的才会存储到 Spring 里面
而这个存储 , 也不是真正意义上的存储 , 只是告诉 Spring , 这个 Bean 需要托管给 Spring
那么我们接下来需要在 resources 里面新建一个文件 , 叫做 spring-config.xml (这个名字大家也可以起别的 , 这里推荐大家起这个就行)


然后把这段代码复制进去

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

</beans>


目前的只是准备工作 , 我们接下来才是将 Bean 存储到 Spring 的核心操作

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--  注册一个对象到 Spring-->
    <!--  先写一个 bean 标签  -->
    <bean id="user" class="User"></bean>

</beans>


里面的 class 也是需要写包名的 , 但是因为我们没创建包 , 所以就没写
那么我们可以改一下 , 把代码放到包里面

目前为止 , 我们只是声明存储对象到 Spring 里面了 , 并不是真正存储到 Spring 里面了 , 正常情况下 , 我们的 Spring 是懒加载 , 在启动 Spring 的时候 , 他并不会立即存储 Spring 对象 , 但是从广义上来理解 , 我们的 Spring 已经存储这个对象了

2.3 从 Spring 中取出 Bean 对象

2.3.1 先得到 Spring 对象(Spring 上下文对象)

对象都交给 Spring 管理了,所以获取对象要从 Spring 中获取,那么就得先得到 Spring 的上下文。
Spring 上下文对象可使用 ApplicationContext



import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
        // 1. 得到 Spring 上下文对象
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");
    }
}

2.3.2 从 Spring 上下文当中取出对象


先不管选哪个 , 我们注意 : getBean 返回值是 Object , 但是我们的对象是 User 类型 , 所以我们需要强转一下



import com.ethan.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
        // 1. 得到 Spring 上下文对象
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");

        // 2. 从 Spring 里面获取对象
        // User user = new User();//在当前类当中创建 User 对象,原始方式不推荐[存在代码耦合]
        User user = (User)context.getBean("user");//只有第一次执行,才会创建.因为是单例模式,创建过后会一直留着,下次用直接拿走
    }
}

2.3.3 使用 bean (非必须)

之前怎么使用 , 现在就怎么使用

import com.ethan.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
        // 1. 得到 Spring 上下文对象
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");

        // 2. 从 Spring 里面获取对象
        // User user = new User();//在当前类当中创建 User 对象,原始方式不推荐[存在代码耦合]
        User user = (User)context.getBean("user");//只有第一次执行,才会创建.因为是单例模式,创建过后会一直留着,下次用直接拿走

        // 3. 使用 bean
        user.sayHi();//跟以前一样
    }
}

运行一下 :

2.4 特殊情况

2.4.1 xml 配置文件一定要写正确

我们之前说 resources 目录底下的配置文件推荐大家使用 spring-config.xml
那么这个名字其实叫什么都行

那我们改成 spring 看看还能不能成功

成功了

但是这种虽然合法但是不规范
那我们试一下这种情况 :
配置文件名称叫 spring-config.xml , 我们的代码里面写成了 spring.xml

那么运行一下 , 看看会不会运行起来

那么我们帮大家排查一下错误


那么就是 spring.xml 没有找到
因为我们的配置文件叫 spring-config.xml , 不是 spring.xml , 所以就会报错
而且下面还有行数提醒

2.4.2 bean 标识一定要写正确


我们运行一下
image.png

2.5 getBean 方法的更多用法

2.5.1 getBean(String s)

我们之前介绍的方法 :
getBean(String s) : 根据名称来获取 bean 对象
这种方法需要进行强转 , 但是他有一个好处 : 我们注册多个 bean , 他会精准定位
比如 :

那么我们的这种方法能正常识别吗 ?

那么这种情况还是挺常见的 : 在公司协同开发 , 张三使用了 user , 李四不知道 , 李四也使用了 user , 这样就产生了重复
原则上来说 , 一个 key 只能出现一次 , 我们就可以把这个第二个 user 改成 user2


那有的人就问了 , 怎么证明 User 和 User2 是不一样的呢 ? 因为他们打印的结果相同啊 , 就会有人以为他们是不是一个东西起了两个名字啊 , 那很好证明

那么我们还可以去证明 user 是不是单例模式

为 true 就代表是单例模式 , 因为 Spring 中创建出一个对象就会一直存储到 Spring 中 , 方便后续使用 , 就不用再去重新创建了

2.5.2 getBean(class<T> aclass)

getBean(class<T> aclass) : 根据类型获取 bean 对象

import com.ethan.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
        // 1. 得到 Spring 上下文对象
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");

        // 2. 从 Spring 里面获取对象
        // 2.1 根据一个 String 参数获取 bean
        //User user = (User)context.getBean("user");//只有第一次执行,才会创建.因为是单例模式,创建过后会一直留着,下次用直接拿走

        // 2.2 根据一个 Class 参数获取 bean
        User user = context.getBean(User.class);//这种方法不用强转了

        // 3. 使用 bean
        user.sayHi();//跟以前一样
    }
}


这种情况是 spring-config.xml 里面只有一个 bean 对象
那么有两个呢 ?

再运行一下 :

看一下异常


我们再看一下 spring-config.xml
image.png

import com.ethan.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
        // 1. 得到 Spring 上下文对象
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");

        // 2. 从 Spring 里面获取对象
        // 2.1 根据一个 String 参数获取 bean
        /*User user = (User)context.getBean("user");
        User user1 = (User)context.getBean("user");
        User user2 = (User)context.getBean("user2");

        System.out.println("user:" + user);
        System.out.println("user1:" + user1);
        System.out.println("user2:" + user2);
        System.out.println("user == user1 -> " + (user == user1));
        System.out.println("user == user2 -> " + (user == user2));//为true说明他们地址相同,是一个对象;为false说明地址不同,不是同一个对象*/

        // 2.2 根据一个 Class 参数获取 bean
        User user = context.getBean(User.class);//这种方法不用强转了

        // 3. 使用 bean
        user.sayHi();//跟以前一样
    }
}

2.5.3 getBean(String s , class<T> aclass)

getBean(String s , class<T> aclass) : 这种方法更加稳健 , 虽然他比第一种也没差哪去 , 不过如果是第一种方法 , 万一内容为 null , 对 null 进行强转就会出现问题 , 但是你通过这种方法的话 , 整体就会返回一个 null , 就不存在空指针问题了

import com.ethan.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
        // 1. 得到 Spring 上下文对象
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");

        // 2. 从 Spring 里面获取对象
        // 2.1 根据一个 String 参数获取 bean
        /*User user = (User)context.getBean("user");
        User user1 = (User)context.getBean("user");
        User user2 = (User)context.getBean("user2");

        System.out.println("user:" + user);
        System.out.println("user1:" + user1);
        System.out.println("user2:" + user2);
        System.out.println("user == user1 -> " + (user == user1));
        System.out.println("user == user2 -> " + (user == user2));//为true说明他们地址相同,是一个对象;为false说明地址不同,不是同一个对象*/

        // 2.2 根据一个 Class 参数获取 bean
        //User user = context.getBean(User.class);//这种方法不用强转了

        // 2.3 根据 String(bean id) 和 Class 参数获取 bean
        User user = context.getBean("user",User.class);//更加的稳健
        // 3. 使用 bean
        user.sayHi();//跟以前一样
    }
}


同样的方式 , 我再去读 user2 也是没问题的

2.6 面试题 : ApplicationContext VS BeanFactory

Spring 上下文对象可使用 ApplicationContext , 我们还可以使用 BeanFactory (ApplicationContext的父类) 来作为 Spring 的上下文

不过 IDEA 已经不推荐我们使用这种方法了

import com.ethan.User;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;

public class App {
    public static void main(String[] args) {
        // 1. 获取上下文对象
        BeanFactory context = new XmlBeanFactory(new ClassPathResource("spring-config.xml"));
        // 2. 从 Spring 里面获取对象
        User user = context.getBean("user2", User.class);
        // 3. 使用方法
        user.sayHi();
    }
}

运行一下 :

那么既然他们都能运行成功 , 那有什么区别呢 ?

  1. 共同点 : 都是用来获取 Spring 的上下文对象
  2. 不同点 :
  3. 继承关系和功能 : ApplicationContext 属于 BeanFactory 的子类 , ApplicationContext 具备了 BeanFactory 所有的功能 , 而 BeanFactory 只具备最基础访问 Bean 的功能 . Application 还具备了更多的能力 , 比如 : 国际化支持 资源访问支持 事件传播 …
  4. 从性能方面来说 , ApplicationContext 是一次性加载并初始化所有的 Bean 对象 , 而 BeanFactory 是按需加载 , 需要使用 Bean 的时候才去加载

三 . 总结

  1. 操作容器之前,先要有容器,所以先要得到容器 , 就需要我们创建 Spring 项目
  2. 存对象
    1. 创建 Bean(普通类)。
    2. 将 Bean 注册(配置)到 spring-confing.xml 中。
  3. 取对象
    1. 得到 Spring 上下文,并读取到 Spring 的配置文件。
    2. 获取某⼀个 Bean 对象。
    3. 使用 Bean 对象。

  • 24
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 39
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

加勒比海涛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值