Spring IOC

1. 什么是spring框架

Spring 是一款开源的轻量级 Java 开发框架,旨在提高开发人员的开发效率以及系统的可维护性。

Spring 翻译过来就是春天的意思,可见其目标和使命就是为 Java 程序员带来春天啊!感动!

题外话 : 语言的流行通常需要一个杀手级的应用,Spring 就是 Java 生态的一个杀手级的应用框架。

我们一般说 Spring 框架指的都是 Spring Framework,它是很多模块的集合,使用这些模块可以很方便地协助我们进行开发。

比如说 Spring 自带 IoC(Inverse of Control:控制反转) 和 AOP(Aspect-Oriented Programming:面向切面编程)、可以很方便地对数据库进行访问、可以很方便地集成第三方组件(电子邮件,任务,调度,缓存等等)、对单元测试支持比较好、支持 RESTful Java 应用程序的开发。

在这里插入图片描述
Spring 最核心的思想就是不重新造轮子,开箱即用!

Spring 提供的核心功能主要是 IoC 和 AOP。学习 Spring ,一定要把 IoC 和 AOP 的核心思想搞懂!

2. 列举一些重要的 Spring 模块?

在这里插入图片描述

Spring Core

核心模块, Spring 其他所有的功能基本都需要依赖于该类库,主要提供 IoC 依赖注入功能的支持。

Spring Aspects

该模块为与 AspectJ 的集成提供支持。

Spring AOP

提供了面向切面的编程实现。

Spring Data Access/Integration :

Spring Data Access/Integration 由 5 个模块组成:

  1. spring-jdbc : 提供了对数据库访问的抽象 JDBC。不同的数据库都有自己独立的 API 用于操作数据库,而 Java 程序只需要和 JDBC API 交互,这样就屏蔽了数据库的影响。
  2. spring-tx : 提供对事务的支持。
  3. spring-orm : 提供对 Hibernate 等 ORM 框架的支持。
  4. spring-oxm : 提供对 Castor 等 OXM 框架的支持。
  5. spring-jms : Java 消息服务。

Spring Web 由 4 个模块组成:

  1. spring-web :对 Web 功能的实现提供一些最基础的支持。
  2. spring-webmvc : 提供对 Spring MVC 的实现。
  3. spring-websocket : 提供了对 WebSocket 的支持,WebSocket 可以让客户端和服务端进行双向通信。
  4. spring-webflux :提供对 WebFlux 的支持。WebFlux 是 Spring Framework 5.0 中引入的新的响应式框架。与 Spring MVC 不同,它不需要 Servlet API,是完全异步.

Spring Test

Spring 团队提倡测试驱动开发(TDD)。有了控制反转 (IoC)的帮助,单元测试和集成测试变得更简单。

Spring 的测试模块对 JUnit(单元测试框架)、TestNG(类似 JUnit)、Mockito(主要用来 Mock 对象)、PowerMock(解决 Mockito 的问题比如无法模拟 final, static, private 方法)等等常用的测试框架支持的都比较好。

2.Spring IOC & AOP

IoC(Inverse of Control:控制反转) 是一种设计思想,而不是一个具体的技术实现。IoC 的思想就是将原本在程序中手动创建对象的控制权,交由 Spring 框架来管理。不过, IoC 并非 Spirng 特有,在其他语言中也有应用。
在这里插入图片描述

为什么叫控制反转?

  • 控制 :指的是对象创建(实例化、管理)的权力
  • 反转 :控制权交给外部环境(Spring 框架、IoC 容器)

将对象之间的相互依赖关系交给 IoC 容器来管理,并由 IoC 容器完成对象的注入。这样可以很大程度上简化应用的开发,把应用从复杂的依赖关系中解放出来。 IoC 容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。

在实际项目中一个 Service 类可能依赖了很多其他的类,假如我们需要实例化这个 Service,你可能要每次都要搞清这个 Service 所有底层类的构造函数,这可能会把人逼疯。如果利用 IoC 的话,你只需要配置好,然后在需要的地方引用就行了,这大大增加了项目的可维护性且降低了开发难度。

在 Spring 中, IoC 容器是 Spring 用来实现 IoC 的载体, IoC 容器实际上就是个 Map(key,value),Map 中存放的是各种对象。

Spring 时代我们一般通过 XML 文件来配置 Bean,后来开发人员觉得 XML 文件来配置不太好,于是 SpringBoot 注解配置就慢慢开始流行起来。

IoC 源码阅读
面试被问了几百遍的 IoC 和 AOP ,还在傻傻搞不清楚?

2. Spring bean

什么是 bean?
简单来说,bean 代指的就是那些被 IoC 容器所管理的对象。

我们需要告诉 IoC 容器帮助我们管理哪些对象,这个是通过配置元数据来定义的。

下图简单地展示了 IoC 容器如何使用配置元数据来管理对象。
在这里插入图片描述

2.1 bean 的作用域有哪些?

Spring 中 Bean 的作用域通常有下面几种:

  • singleton : 唯一 bean 实例,Spring 中的 bean 默认都是单例的,对单例设计模式的应用。
  • prototype : 每次请求都会创建一个新的 bean 实例。
  • request : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP request 内有效。、
  • session : 每一次来自新 session 的 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP session 内有效。
  • global-session : 全局 session 作用域,仅仅在基于 portlet 的 web 应用中才有意义,Spring5 已经没有了。Portlet 是能够生成语义代码(例如:HTML)片段的小型 Java Web 插件。它们基于 portlet 容器,可以像 servlet 一样处理 HTTP 请求。但是,与 servlet 不同,每个 portlet 都有不同的会话。

2.1.1 如何配置 bean 的作用域呢?

  1. 注解方式:
@Bean
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Person personPrototype() {
    return new Person();
}
  1. xml 方式:
<bean id="..." class="..." scope="singleton"></bean>

2.2 单例 bean 的线程安全问题了解吗?

单例 bean 的线程安全问题了解吗?
大部分时候我们并没有在项目中使用多线程,所以很少有人会关注这个问题。单例 bean 存在线程问题,主要是因为当多个线程操作同一个对象的时候是存在资源竞争的。

常见的有两种解决办法:

在 bean 中尽量避免定义可变的成员变量。
在类中定义一个 ThreadLocal 成员变量,将需要的可变成员变量保存在ThreadLocal中(推荐的一种方式)。
不过,大部分 bean 实际都是无状态(没有实例变量)的(比如 Dao、Service),这种情况下, bean 是线程安全的。

2.2.1 @Component 和 @Bean 的区别是什么?

  1. @Component 注解作用于类,而@Bean注解作用于方法。
  2. @Component通常是通过类路径扫描来自动侦测以及自动装配到 Spring 容器中(我们可以使用 @ComponentScan 注解定义要扫描的路径从中找出标识了需要装配的类自动装配到 Spring 的 bean 容器中)。@Bean 注解通常是我们在标有该注解的方法中定义产生这个 bean,@Bean告诉了 Spring 这是某个类的实例,当我需要用它的时候还给我。
  3. @Bean 注解比 @Component 注解的自定义性更强,而且很多地方我们只能通过 @Bean 注解来注册 bean。比如当我们引用第三方库中的类需要装配到 Spring容器时,则只能通过 @Bean来实现。

3.【demo】Spring下使用bean

创建一项目
pom.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion><groupId>org.example</groupId>
    <artifactId>SpringDay01</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <!-- 设置 JDK 版本为 1.8 -->
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.source>1.8</maven.compiler.source>
        <!-- 设置编码为 UTF-8 -->
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
    </properties>
    <dependencies>
        <!-- Spring Context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>javax.annotation</groupId>
            <artifactId>javax.annotation-api</artifactId>
            <version>1.3.2</version>
        </dependency>
    </dependencies></project>

新建一个类(简单的就行)

public class Stu {
    
    private String name;
    private int age;public String getName() {
        return name;
    }public void setName(String name) {
        this.name = name;
    }public int getAge() {
        return age;
    }public void setAge(int age) {
        this.age = age;
    }@Override
    public String toString() {
        return "Stu{" +
                "name='" + name + ''' +
                ", age=" + age +
                '}';
    }
}

使用Spring的第一个步骤

新建一个类,我们暂时名称为Config

//Spring框架的配置类
public class Config {/**
     * @Bean 注解的方法:
     * 表示这个方法的返回值会注入到Spring容器中
     * 注入的对象,可以在该方法中创建并赋值
     * 这个方法的方法名默认情况下是这个对象的ID(名字)
     * @return
     */
    @Bean
    public Stu student(){
        Stu stu=new Stu();
        stu.setName("曹操");
        stu.setAge(60);
        return stu;
    }}

第二个步骤

新建一个测试类,从Spring容器中获得这个对象

public class SpringTest {public static void main(String[] args) {
        //想启用Spring还需要依据我们编写的Spring配置类来创建对象
        AnnotationConfigApplicationContext ctx=
                new AnnotationConfigApplicationContext(Config.class);
        //实例化上面对象参数是配置类的反射
        //原因是反射中包含这个类中所有内容的信息,方便Spring处理//将对象从Spring容器中获取
        //现在用两个参数,第一个参数是获取对象的id
        //第二个参数是获取对象的类型
        Stu caocao=ctx.getBean("student",Stu.class);
        //输出这个对象
        System.out.println(caocao);
        ctx.close();
    }
}

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>