0


Spring

一.Spring简介

1.什么是Spring

Spring 指的是 Spring Framework(Spring 框架)
它可以让 Java 企业级 的应用程序开发起来更简单。

⽤⼀句话概括 Spring:Spring 是包含了众多工具方法的 IOC 容器

2.什么是容器

容器是用来容纳某种物品的(基本)装置。

比如水杯,杯子就是容纳水的容器.

3.IOC

IoC = Inversion of Control 翻译成中文是“控制反转”的意思,也就是说 Spring 是⼀个“控制反转”的容器,具体这里指对于依赖对象控制器的反转.

通常一个类

class A{
B b=new B();
}

这个B对象的生命周期是由A类来管理的,现在Spring将B的生命周期交给Spring来统一管理.这样就发生了控制权的反转.接下来你就会有疑问了,这样做有什么好处吗?为什么这样做呢?

当我们创建一个车的时候,要先创建车身,车身又需要底盘,底盘又依赖于轮胎,这样一层一层的依赖,使代码的耦合度很高,怎么样可以降低耦合度呢?我们现在只需要将各个部件都先创建好,然后当创建底盘的时候将轮胎注入,创建车身的时候将底盘注入,创建车的时候将车身注入,此时他们之间就没有很强的耦合性,而IOC容器就是做的注入和取出的功能,因此

IOC的主要优势就是
程序解耦,耦合度降低

Spring 是一个 IoC(控制反转)容器,重点还在“容器”二字上,那么它就具备两个最基础的功

能:

  • **将对象存入到容器; **
  • **从容器中取出对象。 **

Spring 是一个 IoC 容器,说的是对象的创建和销毁的权利都交给 Spring 来管理了,它本身又具备了存储对象和获取对象的能力

4.DI

DI 是 Dependency Injection 的缩写,翻译成中文是“依赖注入”的意思。

所谓依赖注入,就是由 IoC 容器在运行期间,动态地将某种依赖关系注入到对象之中。所以,依

赖注入(DI)和控制反转(IoC)是从不同的角度的描述的同一件事情,就是指通过引入 IoC 容

器,利用依赖关系注入的方式,实现对象之间的解耦。

IoC 是“目标”也是一种思想,而目标和思想只是一种指导原则,最终还是要有可行的落地方案,而 DI 就属于具体的实现。

二.创建Spring项目

1.创建一个普通的maven项目

2.引入maven依赖

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

    </dependencies>

3.添加启动类

也就是一个main方法

public class App {
    public static void main(String[] args) {

    }
}

三.Spring的创建和使用

1.创建Bean

Bean就是Java中一个普通的对象

public class Student {
    public void sayHi(){
        System.out.println("hi!!!!");
    }
}

2.将Bean放入到容器中

在创建好的项目中添加 Spring 配置文件 spring-config.xml,将此⽂件放到 resources 的根目录下, 如下图所示

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">

</beans>

接下来我么只需要将student对象注册到spring容器中即可

    <beans>
        <bean id="student" class="com.javastudy.springdemo1.entities.Student"></bean>
    </beans>

id为唯一标识这个student对象的.class为Student对象的位置

3.获取Bean对象

获取并使用 Bean 对象,分为以下 3 步:

     1. 得到 Spring 上下文对象,因为对象都交给 Spring 管理了,所以获取对象要从 Spring 中获           取,那么就得先得到 Spring 的上下文。 

     2. 通过 Spring 上下文,获取某一个指定的 Bean 对象。 

     3. 使用 Bean 对象。 

4.创建 Spring 上下文

public class App {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext(" spring-config.xml");

    }
}

除了 ApplicationContext 之外,我们还可以使用 BeanFactory 来作为 Spring 的上下文,如下代码所示:

BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("springconfig.xml"));

ApplicationContext 和 BeanFactory 效果是一样的,ApplicationContext 属于 BeanFactory 的子

类,它们的区别如下。

ApplicationContext VS BeanFactory(常见面试题)
  • 继承关系和功能方面来说:Spring 容器有两个顶级的接口:BeanFactory 和ApplicationContext。其中 BeanFactory 提供了基础的访问容器的能力,而 ApplicationContext属于 BeanFactory 的子类,它除了继承了 BeanFactory 的所有功能之外,它还拥有独特的特性,还添加了对国际化支持、资源访问支持、以及事件传播等方面的支持。
  • 从性能方面来说:ApplicationContext 是一次性加载并初始化所有的 Bean 对象(预加载),而BeanFactory 是需要那个才去加载那个(懒加载),因此更加轻量。

5.获取指定的 Bean 对象

public class App {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext(" spring-config.xml");
        Student student = (Student) context.getBean("student");
        student.sayHi();
    }
}

通过在xml文件里定义的bean的id可以获取到相应的对象.

getBean 方法的更多用法

id+类型(不用类型转换了),可以确保到拿到唯一的对象

        Student student2 = context.getBean("student", Student.class);

当xml文件中只注册了一个Student类型的对象,这种方法可以拿到这个对象,当注册了多个,会报错

        Student student1 = context.getBean(Student.class);
    <beans>
        <bean id="student" class="com.javastudy.springdemo1.entities.Student"></bean>
        <bean id="student2" class="com.javastudy.springdemo1.entities.Student"></bean>
    </beans>

**基本流程图 **

四.Spring Bean的存

1.基于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">

    <bean id="student" class="com.javastudy.springdemo1.entities.Student"></bean>
</beans>

上面演示的就是基于这种方式的

2.基于注解

<?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:content="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 https://www.springframework.org/schema/context/spring-context.xsd">

    <content:component-scan base-package="com.javastudy.springdemo2"></content:component-scan>

</beans>

content:component-scan的base-package即spring扫描的包,在这些包下有spring的五大注解的类可以被加载到spring中.

1.类注解

五大注解@Controller @Service @Repository @Component @Configuration

观察这五大注解源码可以发现

每一个注解上面都有@Component,说明这几个注解都是 @Component注解的子类,所以他们实现的功能都是一样的,那为什么还要有这么多不同的注解呢?

让程序员看到类注解之后,就能直接了解当前类的用途,比如:

  • @Controller:表示的是业务逻辑层;
  • @Servie:服务层;
  • @Repository:持久层;
  • @Configuration:配置层。
  • @Compoent:其他层

命名规范:

注解生成bean的id为类的名称的首字母小写.当首字母和第二个字母都为大写字母的时候,直接返回原名字.

因为这些注解的作用都显示,我们这里只演示一个

@Controller
public class UserController {
    public void sayHi() {
        System.out.println("UserController");
    }
}
public class App {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        UserController userController = context.getBean("userController", UserController.class);
        userController.sayHi();

    }
}

这五大注解中可以重命名bean的名字.比如

@Controller("uController")

这样就需要用uContoller来从spring容器中拿到UserController对象.

2.方法注解

现在定义一个User类

@Data
public class User {
    private Integer id;
    private String name;
}

@Bean注解

注意:@Bean注解必须配合五大注解一起使用

@Component
public class Users {
    @Bean
    public User user1() {
        User user = new User();
        user.setId(1);
        user.setName("zhangsan");
        return user;
    }
}
public class App {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        User user = context.getBean("user1",User.class);
        System.out.println(user);

    }
}

同样的,@Bean注解也可以重命名

@Bean("aaa")

//含有两个id,分别为aaa和bbb

@Bean(name = {"aaa","bbb"})

** @Bean注解命名规则就是方法名**

还有一种参数的注入

    @Bean
    public String name() {
        return "lisi";
    }

    @Bean
    public User user2(String name) {
        User user = new User();
        user.setId(1);
        user.setName(name);
        return user;
    }

五.Spring Bean的取

1.对象装配

1.属性注入

1.@Autowired注解

现在要求将UserService注入到UserController类中

先来创建service类

@Service
public class UserService {

    public User getUser(Integer id) {
        User user = new User();
        user.setId(id);
        user.setName("Java-" + id);
        return user;
    }

}

再来创建controller类

@Controller
public class UserController {
    @Autowired
    UserService userService;
    
    public User getUser(Integer id) {
        return userService.getUser(id);
    }

}

测试:

public class App {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        UserController userController = context.getBean("userController", UserController.class);
        System.out.println(userController.getUser(5));

    }
}

可以观察到UserService被成功注入到UserController类中.

@Autowired和@Qualifier搭配使用

** ** @Autowired
@Qualifier("aaa") //注入名字为aaa的对象
UserService userService;

2.@Resource注解

在进行类注入时,除了可以使用 @Autowired 关键字之外,我们还可以使⽤ @Resource 进行注入,如下代码所示:

@Controller
public class UserController {
    @Resource
    UserService userService;

    public User getUser(Integer id) {
        return userService.getUser(id);
    }

}

同时 @Resource注解可以注入指定名字的对象

@Resource(name = "aaa") / /代表注入name=aaa的对象
 UserService userService;

区别

  • 出身不同:@Autowired 来自于 Spring,而 @Resource 来自于 JDK 的注解;
  • 使用时设置的参数不同:相比于 @Autowired 来说,@Resource 支持更多的参数设置,例如name 设置,根据名称获取 Bean。
  • @Autowired 可用于 Setter 注入、构造函数注入和属性注入,而 @Resource 只能用于 Setter 注入和属性注入,不能用于构造函数注入。

2.Setter方法注入

通过set方法,上面需要加上@Autowired注解(不可省略)

@Controller
public class UserController3 {
    // 注⼊⽅法3:Setter注⼊
    private UserService userService;

    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    public User getUser(Integer id) {
        return userService.getUser(id);
    }
}

3.构造函数注入

通过构造函数注入,只有一个构造函数,可以省略@Autowired注解,如果存在多个构造函数,需要在使用的那个构造函数上面加@Autowired注解,否则就会报如下错误

一个类默认有一个无参的构造函数
当我们写了有参的构造函数的时候,就没有这个默认无参构造函数了创建对象,需要调用构造函数
当前存在多个构造函数, Spring就不知道使用哪个了,所以会报错我们需要告诉Spring,使用哪个构造函数

注意:如果只有一个构造方法,那么 @Autowired 注解可以省略

@Controller
public class UserController2 {
    // 注⼊⽅法2:构造⽅法注⼊
    private UserService userService;

    @Autowired  //此时注解可省略,因为只有一个构造函数
    public UserController2(UserService userService) {
        this.userService = userService;
    }

    public User getUser(Integer id) {
        return userService.getUser(id);
    }
}

2.三种方法的优缺点

1.属性注入

优点:

  1. 简洁,使用方便;

缺点:

  1. 只能用于lOC容器,如果是非IOC容器不可用,并且只有在使用的时候才会出现NPE(空指针异常)。
  2. 不能注入一个final修饰的属性

2.Setter注入(Spring 3.X推荐)

优点:

  1. 方便在类实例之后,重新对该对象进行配置或者注入

缺点:

  1. 不能注入一个final修饰的属性
  2. 注入对象可能会被改变,因为setter方法可能会被多次调用,就有被修改的风险.

3.构造函数注入(Spring 4.X推荐)

优点:

  1. 可以注入final修饰的属性
  2. 注入的对象不会被修改
  3. 依赖对象在使用前一定会被完全初始化,因为依赖是在类的构造方法中执行的,而构造方法是在类加载阶段就会执行的方法。
  4. 通用性好,构造方法是JDK支持的,所以更换任何框架,他都是适用的。

缺点:

  1. 注入多个对象时,代码会比较繁琐

六.Bean的作用域

1.六种作用域

限定程序中变量的可用范围叫做作用域,或者说在源代码中定义变量的某个区域就叫做作用域。 而 Bean 的作用域是指 Bean 在 Spring 整个框架中的某种行为模式,比如 singleton 单例作用域,就 表示 Bean 在整个 Spring 中只有一份,它是全局共享的,那么当其他人修改了这个值之后,那么另一个人读取到的就是被修改的值。

  1. singleton:单例作用域(默认)
  2. prototype:原型作用域(多例作用域)
  3. request:请求作用域
  4. session:会话作用域
  5. application:全局作用域
  6. websocket:HTTP WebSocket 作用域

注意后 4 种状态是 Spring MVC 中的值,在普通的 Spring 项目中只有前两种

2.singleton

  • 官方说明:(Default) Scopes a single bean definition to a single object instance for each Spring IoC container.
  • 描述:该作用域下的Bean在IoC容器中只存在一个实例:获取Bean(即通过applicationContext.getBean等方法获取)及装配Bean(即通过@Autowired注入)都是同一个对象。
  • 场景:通常无状态的Bean使用该作用域。无状态表示Bean对象的属性状态不需要更新
  • 备注:Spring默认选择该作用域

3.prototype

  • 官方说明:Scopes a single bean definition to any number of object instances.
  • 描述:每次对该作用域下的Bean的请求都会创建新的实例:获取Bean(即通过applicationContext.getBean等方法获取)及装配Bean(即通过@Autowired注入)都是新的对象实例。
  • 场景:通常有状态的Bean使用该作用域

4. request

  • 官方说明:Scopes a single bean definition to the lifecycle of a single HTTP request. That is,each HTTP request has its own instance of a bean created off the back of a single beandefinition. Only valid in the context of a web-aware Spring ApplicationContext.
  • 描述:每次http请求会创建新的Bean实例,类似于prototype
  • 场景:一次http的请求和响应的共享Bean
  • 备注:限定SpringMVC中使用

5. session

  • 官方说明:Scopes a single bean definition to the lifecycle of an HTTP Session. Only valid inthe context of a web-aware Spring ApplicationContext.
  • 描述:在一个http session中,定义一个Bean实例
  • 场景:用户回话的共享Bean, 比如:记录一个用户的登陆信息
  • 备注:限定SpringMVC中使用

6. application

  • 官方说明:Scopes a single bean definition to the lifecycle of a ServletContext. Only valid in the context of a web-aware Spring ApplicationContext.
  • 描述:在一个http servlet Context中,定义一个Bean实例
  • 场景:Web应用的上下文信息,比如:记录一个应用的共享信息
  • 备注:限定SpringMVC中使用

7. websocket:

  • 官方说明:Scopes a single bean definition to the lifecycle of a WebSocket. Only valid in thecontext of a web-aware Spring ApplicationContext.
  • 描述:在一个HTTP WebSocket的生命周期中,定义一个Bean实例
  • 场景:WebSocket的每次会话中,保存了一个Map结构的头信息,将用来包裹客户端消息头。第一次初始化后,直到WebSocket结束都是同一个Bean。
  • 备注:限定Spring WebSocket中使用

8.设置作用域

使用 @Scope 标签就可以用来声明 Bean 的作用域,比如设置 Bean 的作用域,如下代码所示:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
public class Users {
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    @Bean(name = "u1")
    public User user1() {
        User user = new User();
        user.setId(1);
        user.setName("Java"); // 【重点:名称是 Java】
        return user;
    }
}

@Scope 标签既可以修饰方法也可以修饰类,@Scope 有两种设置方式:

  1. 直接设置值:@Scope("prototype")

  2. 使用枚举设置:@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)

七.Spring的启动流程

  1. 启动容器
  2. 解析配置文件的内容,并创建bean
  3. 把对象放在容器中
  4. bean依赖对象的装配

Bean 执行流程(Spring 执行流程):启动 Spring 容器 -> 实例化 Bean(分配内存空间,从无到

有) -> Bean 注册到 Spring 中(存操作) -> 将 Bean 装配到需要的类中(取操作)。

八.Bean的生命周期

bean的生命周期即对象从诞生到销毁的整个过程,我们把这个过程叫做一个对象的生命周期

1.实例化bean

(为bean分配内存空间,相当于new出来一个对象,执行构造方法)

注意:不等同于初始化.

2.设置属性

3.Bean初始化

  • 执行各种通知,如 BeanNameAware、BeanFactoryAware、ApplicationContextAware的接口方法;

  • 执行初始化前置方法 xml定义init-method使用注解的方式**@PostConstruct**执行初始化方法

  • 执行初始化后置方法( BeanPostProcessor )

4.使用Bean

5.销毁Bean

销毁容器的各种方法,如 @PreDestroy、DisposableBean 接口方法、destroy-method。

标签: spring java

本文转载自: https://blog.csdn.net/qq_64580912/article/details/131855526
版权归原作者 允歆辰丶 所有, 如有侵权,请联系我们删除。

“Spring”的评论:

还没有评论