当前位置: 首页 > news >正文

Spring(JavaEE进阶系列1)

目录

前言:

1.Servlet与Spring对比

2.什么是Spring

2.1什么是容器

2.2什么是IoC

2.3SpringIoC容器的理解

2.4DI依赖注入

2.5IoC与DI的区别

3.Spring项目的创建和使用

3.1正确配置Maven国内源

3.2Spring的项目创建

3.3将Bean对象存储到Spring(IoC容器)

3.4获取并使用Bean

3.4.1使用ApplicationContext获取上下文

3.4.2使用BeanFactory获取上下文

3.4.3ApplicationContext与BeanFactory的区别

3.5getBean方法的使用

3.5.1根据名称获取Bean对象

3.5.2根据类型获取Bean对象

3.5.3根据名称 + 类型来获取

3.6更加简单的存储Bean对象

3.6.1配置

3.6.2注解

3.6.2.1@Controller注解

3.6.2.2@Service注解

3.6.2.3@Repository注解

3.6.2.4@Component注解

3.6.2.5@Configuration注解

 3.6.3类注解存储Bean命名问题(默认命名规则)

3.6.4为什么要这么多注解

3.6.5五大类注解之间的关系

3.6.6方法注解@Bean

3.6.7@Bean的几种重命名方式

3.6.8获取Bean对象(对象装配)

3.6.8.1属性注入

3.6.8.2Setter注入

3.6.8.3构造方法注入

3.6.8.4@Autowired VS @Resource区别

3.6.9同一类型多个Bean报错

3.6.10Bean的作用域

3.6.11设置Bean的作用域

3.6.12Spring的生命周期

3.6.13Bean的生命周期

结束语:


前言:

这节中小编主要是介绍一下有关于Spring框架,以及框架的具体搭建。那么我们为什么要学习框架呢?我们学习框架相当于从“小作坊”到“工厂”的升级,小作坊就是需要我们自己来做,从最底层做起,工厂就是组件式装配,特点就是便捷更加易用、简单高效。

1.Servlet与Spring对比

在我们之前使用了Servlet来实现了博客系统,在之前的学习中我们也深刻的体会到了使用Servlet的时候带来的一些痛点,如下所示:

  • 添加外部jar包不方便,容易出错,比如添加了一个不匹配的外部jar版本。
  • 运行和调试的时候需要配置Tomcat不方便。
  • 发布不方便,Servlet项目必须依靠外置的Tomcat(外置的web容器)运行。
  • 路由配置不方便,一个访问地址对应一个Servlet类。

那么如果我们使用的是Spring框架相比于Servlet就会有以下的好处:

  • 无需配置Tomcat,点击“运行”按钮就可以运行项目,Spring Boot内置了Web容器(可直接运行)。
  • 快速添加外部jar包。
  • 快速发布项目(使用java-jar方式就可以发布)。
  • 对象会自动装配。

2.什么是Spring

我们通常说的Spring指的是Spring Framework(Spring 框架),它是一个开源的框架,它支持广泛的应用场景,可以让Java企业级的应用程序开发起来更加的简单。总的来说Spring是包含了众多工具方法IoC容器。

2.1什么是容器

那么在上述的Spring概念的介绍中我们提及到了容器的概念,那么什么是容器呢?

容器就是用来容纳某种物品的装置。在我们之前的学习中我也接触到了一些容器,比如List和Map数据存储容器,以及我们上次学习的Tomcat是Web容器。

2.2什么是IoC

Spring也是一个容器,那么Spring是什么容器呢?在上述中我们从Spring的概念中得知它是一个IoC容器。

那么究竟什么是IoC容器呢?

IoC = Inversion of Control 翻译过来就是“控制返转”的意思。也就是说Spring是一个“控制返转”的容器,怎么理解这句话呢?准确来说应该是一个“控制(权)返转”的一个容器,针对这个权,在我之前的学习中我创建一个对象都是通过new来创建出来的,它的生命周期是由当前代码(程序猿)控制的。但是这里我们学习的对象的生命周期不是由程序猿来控制了而是由当前代码片段来控制,即是由Spring(Spring容器/IoC容器)来进行控制,即我们这里说的控制权反转,就是对象创建的生命周期进行了反转。下面我们就来举一个具体点的例子说明。

代码展示:

1.Car代码展示

package old;/*** 传统开发* 汽车*/
public class Car {private Framework framework;public Car() {this.framework = new Framework();}public void init() {//需要依赖车身System.out.println("执行了 Car的init 方法");framework.init();}
}

2.Framework代码展示

package old;
/*** 传统开发* 车身*/
public class Framework {private Bottom bottom;public Framework() {this.bottom = new Bottom();}public void init() {System.out.println("执行了 Framework的init 方法");bottom.init();}
}

3.Bottom代码展示

package old;
/*** 传统开发* 底盘*/
public class Bottom {private Tire tire;public Bottom() {this.tire = new Tire();}public void init() {System.out.println("执行了 Bottom的init 方法");tire.init();}
}

4.Tire代码展示

package old;
/*** 传统开发* 轮胎*/
public class Tire {private int size = 20;public void init() {System.out.println("执行了 Tire的inti 方法" + "轮胎的大小是:" + size);}
}

5.主函数展示

package old;
/*** 传统开发*/
public class Test {public static void main(String[] args) {Car car = new Car();car.init();}
}

结果展示:

经过上述代码的编写大家会发现每一层都需要依赖上一层才可以,这样就会高度耦合,那么接下来我们这里来使用Spring来进行一个编写。那么经过解耦合的一个过程就达到了以下的效果。

代码展示:

1.Car代码展示

package IoC;public class Car {private Framework framework;public Car(Framework framework){this.framework = framework;}public void init() {System.out.println("Car init");framework.init();}
}

2.Framework代码展示

package IoC;public class Framework {private Bottom bottom;public Framework(Bottom bottom) {this.bottom = bottom;}public void init() {System.out.println("Bottom init");bottom.init();}
}

3.Bottom代码展示

package IoC;public class Bottom {private Tire tire;public Bottom(Tire tire) {this.tire = tire;}public void init() {System.out.println("Bottom init");tire.init();}
}

4.Tire代码展示

package IoC;public class Tire {private int size = 15;public Tire(int size) {this.size = size;}public void init() {System.out.println("Tire init, size:" + size);}
}

5.Test代码展示

package IoC;/*** 模拟IoC容器*/
public class Test {private Tire tire;private Bottom bottom;private Framework framework;private Car car;public Test() {this.tire = new Tire(15);this.bottom = new Bottom(this.tire);this.framework = new Framework(this.bottom);this.car = new Car(this.framework);}public static void main(String[] args) {Test test = new Test();test.car.init();}
}

结果展示:

注意:这里我们是模拟一个IoC容器,所以在IoC容器中会存在new对象的操作,我们关注的只是除了IOC容器以外的代码。

故通过上述的代码案例当我你在修改案例需求的时候就不会牵一发而动全身了,所以IoC容器就达到了一个很好的一个解耦合的效果。

在传统的代码开发中对象创建顺序是:Car -> Framework ->Bottom ->Tire 

改进之后解耦合的代码的对象的创建对象顺序是:Tire -> Bottom -> Framework -> Car

2.3SpringIoC容器的理解

Spring(IoC)容器管理的资源,管理的就是对象,这里的对象就是Bean。

既然Spring是一个IoC容器,重点还在于容器二字上,那么它就具备两个最基本的功能:

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

也就是说学Spring最核心的就是学会如何将对象存储到Spring中,再从Spring中获取对象的过程。

那么将对象存储到容器中的好处就是将对象存储在IoC容器中相当于将以后可能用到的所有工具制作好都放到仓库中,需要的时候就直接取就好了,用完之后在把它放回到仓库中,而new对象的方式相当于,每次需要工具的时候才会去做,用完之后就直接扔掉了也不会保存,下次再次使用的时候还得重新再做,这就是IoC容器和普通程序开发的区别。

2.4DI依赖注入

DI依赖注入:指的是在运行期间,动态的将依赖对象获取到的过程就叫依赖注入。也就是如果在启动A类的时候需要将B类动态的获取到的一个过程。

2.5IoC与DI的区别

IoC和DI都是Spring框架中的核心概念,他们的区别在于:

IoC(Inverse of Control,控制返转):他是一种思想,主要解决程序设计中的对象依赖关系管理问题。在IoC思想中,对象的创建权反转给第三方容器,由容器进行对象的创建及依赖关系的管理。

DI(Dependency Injection,依赖注入):它是IoC思想的具体实现方式之一,用于实现IoC。在Spring中,依赖注入时指在对象创建时,由容器自动将依赖对象注入到需要依赖的对象中。

简单来说,他们的关系是:

  • IoC是一种思想、理念、定义了对象创建和依赖关系处理的方式。
  • DI是IoC思想的具体实现方式之一,实际提供对象依赖关系的注入功能。

3.Spring项目的创建和使用

3.1正确配置Maven国内源

为什么我们需要先来配置国内源呢?如果不配就会导致创建Spring/Spring Boot失败,或者是在maven项目中引入jar失败。致使项目运行不了。

所以我们需要进行以下配置:

如果没有settings.xml文件的可以在小编的Gitee中直接下载获取☞https://gitee.com/YAUGAOLELE/configuration-filehttps://gitee.com/YAUGAOLELE/configuration-file/blob/master/settings.xmlhttps://gitee.com/YAUGAOLELE/configuration-file

如果有settings.xml文件的请打开该文件,找到下面对应的位置将下面的代码复制进去。

 <mirror>

        <id>alimaven</id>

        <name>aliyun maven</name>

        <url>http://maven.aliyun.com/nexus/content/groups/public/</url>

        <mirrorOf>central</mirrorOf>        

    </mirror>

对应的位置如下所示:

注意这里需要进行两步配置,步骤和上述一样。

配置好之后就可以对jar包进行重新下载了。 

3.2Spring的项目创建

①创建一个maven项目。

②创建文件的名字,然后选择路径。

③pom.xml中添加依赖。

配置Gitee地址:https://gitee.com/YAUGAOLELE/configuration-file/blob/master/pom.xml

④创建一个启动测试类

3.3将Bean对象存储到Spring(IoC容器)

①创建一个Bean对象

②将Bean存储到Spring中

我们需要先来在resource里面创建一个spring-config.xml文件,然后将下面的这段放置在里面。

或者可以直接从小编的Gitee中获取配置:https://gitee.com/YAUGAOLELE/configuration-file/blob/master/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"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">
</beans>

接下来就可以直接存储bean对象了。如下所示:

3.4获取并使用Bean

3.4.1使用ApplicationContext获取上下文

①得到Spring上下文对象,获取Bean对象。

②代码展示:

import com.spring.demo.UserService;
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.得到Bean【依赖查找 -> IoC的一种实现】UserService userService = (UserService) context.getBean("user");//3.使用Bean对象userService.SayHi();}
}

③运行结果展示:

3.4.2使用BeanFactory获取上下文

代码展示:

import com.spring.demo.UserService;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;public class BeanFactory {//1.获取spring上下文对象BeanFactory context = new BeanFactory(new ClassPathResource("spring-config.xml"));//2.获取BeanUserService userService = (UserService)context.getBean("user");//3.使用BeanuserService.SayHi();
}

结果展示:

3.4.3ApplicationContext与BeanFactory的区别

我们可以看到使用两者都可以获取到Bean对象,但是它两有什么区别呢?

相同点:

都是容器管理对象,都可以获取Bean对象。

区别:

  • ApplicationContext属于BeanFactory的子类,ApplicationContext拥有更多的功能(国际化支持、资源访问支持、以及事件传播等方面的支持)。
  • 加载Bean机制不同:BeanFactory懒加载,按需加载(使用一个Bean加载一个Bean),ApplicationContext一次性加载所有Bean对象。所以ApplicationContext启动的时候非常慢,但是在启动之后在获取对象的时候就会非常快,而BeanFactory在启动的时候就会非常快,但是在获取对象的时候机会非常慢。

3.5getBean方法的使用

3.5.1根据名称获取Bean对象

需要进行强制转换。

代码展示:

import com.spring.demo.UserService;
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.得到Bean【依赖查找 -> IoC的一种实现】UserService userService = (UserService) context.getBean("user");//3.使用Bean对象userService.SayHi();}
}

结果展示:

注意:上述的这种方法虽然可以不用进行强制类型转换,但是如果存储多个的话可以就会出现错误,会导致分不清到底是谁。

如下所示:

如下存储了多个user,此时就会出现问题。

 

3.5.2根据类型获取Bean对象

不需要进行强制类型转换。

代码展示:

package com.spring.demo;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class App2 {public static void main(String[] args) {//1.先得到spring上下文对象ApplicationContext context =new ClassPathXmlApplicationContext("spring-config.xml");//2.得到Bean【依赖查找 -> IoC的一种实现】UserService userService = context.getBean(UserService.class);//3.使用Bean对象userService.SayHi();}
}


结果展示:

3.5.3根据名称 + 类型来获取

不需要进行强制类型转换,也不会出现上述两个对象的分不清楚的问题。

代码展示:

package com.spring.demo;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class App3 {public static void main(String[] args) {//1.先得到spring上下文对象ApplicationContext context =new ClassPathXmlApplicationContext("spring-config.xml");//2.得到Bean【依赖查找 -> IoC的一种实现】UserService userService = context.getBean("user",UserService.class);//3.使用Bean对象userService.SayHi();}
}


结果展示:

3.6更加简单的存储Bean对象

3.6.1配置

3.6.2注解

更加简单的添加存储Bean对象有以下两种实现方式。

①通过类注解来实现Bean对象的存储。(@Controller、@Service、@Repository、@Component、@Configuration)

②通过方法注解实现Bean对象的存储。(@Bean)

我们常见的五大类注解有以下几个:

  • @Controller【控制器】校验参数的合法性(相当于是安检系统)。
  • @Service【服务】业务组装(相当于是客服中心)。
  • @Repository【数据持久层】实际业务处理(相当于是实际办理的业务)。
  • @Component【组件】工具类实现(相当于是基础的工具)。
  • @Configuration【配置层】配置。

注意:当我们使用注解存储Bean和使用xml存储Bean是可以混合使用的。

3.6.2.1@Controller注解

3.6.2.2@Service注解

3.6.2.3@Repository注解

3.6.2.4@Component注解

3.6.2.5@Configuration注解

 3.6.3类注解存储Bean命名问题(默认命名规则)

①默认类名首字母小写就可以获取到Bean对象。

代码展示:

Teacher代码展示:

package com.spring.demo;import org.springframework.context.annotation.Configuration;@Configuration
public class Teacher {public void SayHi() {System.out.println("Hi Teacher");}
}

App_Teacher代码展示:

package com.spring.demo;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class App_Teacher {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");Teacher teacher = context.getBean("teacher", Teacher.class);teacher.SayHi();}
}


结果展示:

②使用原类名可以获取到对象。

 

代码展示:

UConfig代码展示:

package com.spring.demo;import org.springframework.stereotype.Repository;@Repository
public class UConfig {public void sayHi() {System.out.println("Hi,UConfig");}
}


App_UConfig代码展示

package com.spring.demo;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class App_UConfig {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");UConfig uConfig = context.getBean("UConfig",UConfig.class);uConfig.sayHi();}
}

结果展示: 

注意:如果我们这里也使用的是首字母小写的话就会获取不到对象了,如下所示:

总结:

如果首字母是大写,第二个字母时小写,那么Bean的名称就是列名小写,如果不满足首字母大写和第二个字母小写,那么Bean的名称就为原类名。

3.6.4为什么要这么多注解

既然功能都是一样的 ,为什么需要这么多注解呢?

这和为什么每个省份都有自己的车牌号一样,比如陕西的是陕XXX,北京的是京XXX一样,这样就可以更加直观的标识出一辆车的归属地。那么这里的注解也是一样的道理,就是让程序员看到的时候就能直接了解当前类的用途,比如@Controller是业务逻辑层的,@Service是服务层的,@Repository是持久层的,@Configuration是配置层的。他们的程序的工程分层,调用流程如下所示:

3.6.5五大类注解之间的关系

当我们查看@Controller、@Service、@Repository、@Configuration的原码时就会发现这些注解里面都有一个注解是@Component,说明他本身就是属于@Component的“子类”

3.6.6方法注解@Bean

@Bean注解必须配合五大类注解一起使用。

文章实体类代码:

package com.spring.demo.model;import java.time.LocalDateTime;/*** 普通文章实体类*/
public class ArticleInfo {private int aid;private String title;private String content;private LocalDateTime createtime;@Overridepublic String toString() {return "ArticleInfo{" +"aid=" + aid +", title='" + title + '\'' +", content='" + content + '\'' +", createtime=" + createtime +'}';}public int getAid() {return aid;}public void setAid(int aid) {this.aid = aid;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}public LocalDateTime getCreatetime() {return createtime;}public void setCreatetime(LocalDateTime createtime) {this.createtime = createtime;}
}

注解代码展示:

package com.spring.demo.Controller;import com.spring.demo.model.ArticleInfo;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;import java.time.LocalDateTime;@Controller
public class Articles {@Bean //将当前方法返回的对象存储到IoC容器中public ArticleInfo articleInfo() {//伪代码ArticleInfo articleInfo = new ArticleInfo();articleInfo.setAid(1);articleInfo.setTitle("文章标题");articleInfo.setContent("文章正文");articleInfo.setCreatetime(LocalDateTime.now());return articleInfo;}
}

测试代码展示:

package com.spring.demo.Controller;import com.spring.demo.model.ArticleInfo;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;class ArticlesTest {@Testvoid articleInfo() {ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");ArticleInfo articleInfo = context.getBean("articleInfo", ArticleInfo.class);System.out.println(articleInfo.toString());}
}

结果展示:

注意:@Bean获取时默认命名是方法名。

3.6.7@Bean的几种重命名方式

在上面的时候我们是直接通过方法名来获取的,那么我们还可通过给Bean进行重命名的方式来进行获取。

①可以通过设置 name 属性给 Bean 对象进⾏重命名操作但是不写name关键字,如下代码所示:

②可以通过设置 name 属性给 Bean 对象进⾏重命名操作,如下代码所示:

③可以通过设置 value 属性给 Bean 对象进⾏重命名操作,如下代码所示:

④重命名扩展:@Bean支持指定多个名称,如下代码所示:

默认命名注意事项:当@Bean重命名之后,那么默认的使用方法命名获取Bean对象的方式就不能使用了。

3.6.8获取Bean对象(对象装配)

在上述过程中我们学会了如何通过五大类注解以及方法注解的方式将对象存储到IoC容器中,接下来我们就来学习一下如何将Bean对象取出来。

 获取Bean对象也叫做对象装配,是把对象取出来放到某个类中,有时候也叫对象注入。

对象装配(对象注入)的实现方法有以下三种:

  • 属性注入。
  • Setter注入。
  • 构造方法注入。

接下来我们就来分别看一下吧。

3.6.8.1属性注入

属性注入时使用@Autowired实现的,将Service类注入到Controller类中。

使用代码:

以前获取对象的写法:

package com.spring.demo.service;import com.spring.demo.dao.UserRepository;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Service;@Service
public class UserService1 {public int add() {System.out.println("Do UserService1 add method");//传统获取的写法
//        UserRepository userRepository = new UserRepository();
//        return userRepository.add();//Spring  v1.0版本的写法ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");UserRepository userRepository = context.getBean("userRepository", UserRepository.class);return userRepository.add();}
}

现在使用属性注入之后代码的写法:

package com.spring.demo.service;import com.spring.demo.dao.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class UserService1 {@Autowiredprivate UserRepository userRepository;public int add() {System.out.println("Do UserService1 add method");//Spring v2.0版本的写法return userRepository.add();}
}

要想对其进行重命名可以使用@Qualifier来进行重命名。

同样也可以将@Autowired注解换成@Resource注解。

测试代码展示:

package com.spring.demo.service;import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;import static org.junit.jupiter.api.Assertions.*;class UserService1Test {@Testvoid add() {ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");UserService1 userService1 = context.getBean("userService1",UserService1.class);userService1.add();}
}

结果展示:

优点:

  • 使用简单。

缺点:

  • 无法注入final修饰的变量。

  • 通用性问题:只适用于IoC容器。
  • 更容易违背单一设计原则,因为使用起来比较简单。

3.6.8.2Setter注入

Setter注入黑盒属性的Setter方法实现类似,只不过在设置set方法的时候需要加上@Autowired注解。

使用代码:

package com.spring.demo.service;import com.spring.demo.dao.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class UserService2 {private UserRepository userRepository;@Autowiredpublic UserService2(UserRepository userRepository) {this.userRepository = userRepository;}public void sayHi() {System.out.println("Do UserService2 sayHi");userRepository.add();}
}

测试代码展示:

package com.spring.demo.service;import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;class UserService2Test {@Testvoid sayHi() {ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");UserService2 userService2 = context.getBean("userService2",UserService2.class);userService2.sayHi();}
}


结果展示:

优点:

  • 通常Setter只Set一个属性,所以Setter注入更加符合单一设计原则。

缺点:

  • 无法注入一个final修饰的变量。
  • setter注入对象的时候可以被修改,setter本来就是一个方法,既然是一个方法就有可能被多次调用和修改。
3.6.8.3构造方法注入

构造方法注入就是在类的构造方法中实现注入。

使用代码:

package com.spring.demo.service;import com.spring.demo.dao.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class UserService3 {private final UserRepository userRepository;@Autowiredpublic UserService3(UserRepository userRepository) {this.userRepository = userRepository;}public void sayHi() {System.out.println("Do UserService1 add method");}
}

测试代码展示:

package com.spring.demo.service;import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;import static org.junit.jupiter.api.Assertions.*;class UserService3Test {@Testvoid sayHi() {ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");UserService3 userService3 = context.getBean("userService3",UserService3.class);userService3.sayHi();}
}


结果展示:

优点:

  • 可以注入一个final修改的变量。
  • 注入的时候对象不会被修改,因为构造方法只会加载一次。
  • 构造方法注入可以保证注入对象完全初始化。
  • 构造方法注通用性更好。

缺点:

  • 写法比属性注入更加复杂。
  • 使用构造注入,无法解决循环依赖的问题。
3.6.8.4@Autowired VS @Resource区别
  • 出身不同:@Resource来自于JDK;@Autowired来自于Spring框架。
  • 支持参数不同:@Resource支持很多参数设置,@Autowired只支持一个参数设置。
  • 使用上的区别:@Resource不支持构造方法注入,而@Autowired支持构造方法注入。
  • idea兼容性支持不同:使用@Autowired在idea专业版下可能会误报;@Resource不存在误报的问题。

3.6.9同一类型多个Bean报错

当出现以下多个Bean,返回同一个对象类型时程序会报错,如下所示:

代码展示:
 

package com.spring.demo.model;import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;@Component
public class Users {@Beanpublic User user1() {User user = new User();user.setId(1);user.setName("Java");return user;}@Beanpublic User user2() {User user = new User();user.setId(2);user.setName("MySQL");return user;}
}

在另一个类中获取User对象,如下所示:

代码展示:

package com.spring.demo.Controller;import com.spring.demo.model.User;
import org.springframework.stereotype.Controller;import javax.annotation.Resource;@Controller //将对象存储到Spring中
public class UserController {//注入@Resourceprivate User user;public User getUser() {return user;}
}

结果展示:

解决方案:

  • 将属性的名字和Bean的名字对应上。
  • @Autowired配合@Qualifier一起使用。

3.6.10Bean的作用域

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

Bean作用域类型:

  • singleton:单例模式(默认的作用域)。
  • prototype:原型模式。
  • request:请求作用域。只适用于Spring MVC项目(Spring Web)。
  • session:会话作用域。一个Http会话共享一个Bean。只适用于Spring MVC项目(Spring Web)。
  • application:应用作用域。表示的是一个Context容器共享一个作用域。只适用于Spring MVC项目(Spring Web)。
  • websocket:websocket作用域。只适用于websocket作用域。

单例作用域(singleton)VS全局作用域(application)

  • singleton是Spring Core的作用域;application是Spring Web中的作用域。
  • singleton作用于IoC容器,而application作用于Servlet容器。

3.6.11设置Bean的作用域

  • @Scope("prototype")
  • @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)

3.6.12Spring的生命周期

  1. 启动容器。
  2. 读取配置进行Bean实例化。
  3. 将Bean加入到容器中。
  4. 装配Bean属性(给当前类的属性DI,进行赋值)。

3.6.13Bean的生命周期

1.实例化(内存空间的分配)。

2.设置Bean属性(进行依赖注入,将依赖的Bean赋值到当前类的属性上)。

3.Bean的初始化。

        3.1执行各种通知。

        3.2初识化的前置方法。

        3.3初始化方法。

        3.4初始化的后置方法。

4.使用Bean

5.销毁Bean。

结束语:

好了这节小编就给大分享到这里啦,希望这节对大家有关于Spring的基础知识的了解有一定帮助,想要学习的同学记得关注小编和小编一起学习吧!如果文章中有任何错误也欢迎各位大佬及时为小编指点迷津(在此小编先谢过各位大佬啦!)

相关文章:

Spring(JavaEE进阶系列1)

目录 前言&#xff1a; 1.Servlet与Spring对比 2.什么是Spring 2.1什么是容器 2.2什么是IoC 2.3SpringIoC容器的理解 2.4DI依赖注入 2.5IoC与DI的区别 3.Spring项目的创建和使用 3.1正确配置Maven国内源 3.2Spring的项目创建 3.3将Bean对象存储到Spring&#xff08…...

Flink状态管理与检查点机制

1.状态分类 相对于其他流计算框架,Flink 一个比较重要的特性就是其支持有状态计算。即你可以将中间的计算结果进行保存,并提供给后续的计算使用: 具体而言,Flink 又将状态 (State) 分为 Keyed State 与 Operator State: 1.1 算子状态 算子状态 (Operator State):顾名思义…...

【threejs】基本编程概念及海岛模型展示逻辑

采用three封装模式完成的海岛动画&#xff08;点击这里查看&#xff09; 直接上代码吧 <template><div class"scene"><video id"videoContainer" style"position:absolute;top:0px;left:0px;z-index:100;visibility: hidden"&g…...

python小技巧:创建单链表及删除元素

目前只有单链表&#xff08;无法查找上一个元素&#xff09;&#xff0c;后面再更新循环链表和双链表。 class SingleLinkedList:def createList(self, raw_list):if len(raw_list) 0:head ListNode()else:head ListNode(raw_list[0])cur headfor i in range(1, len(raw_l…...

ADuM1250 ADuM1251 模块 I2C IIC总线2500V电磁隔离 接口保护

功能说明&#xff1a; 1&#xff0c;2500V电磁隔离&#xff0c;2通道双向I2C&#xff1b; 2&#xff0c;支持电压在3到5.5V&#xff0c;最大时钟频率可达1000KHz&#xff1b; 3&#xff0c;将该隔离模块接入总线&#xff0c;可以保护主MCU引脚&#xff0c;降低I2C总线上的干…...

C# 把多个dll合成一个dll

Nuget 下载ILMerge两个工程 dog为测试工程 TestIlmerge为准备合并的类库 如下图所示&#xff0c; 由于我们引用下面4个库 正常生成后&#xff0c;会有TestIlmerge.dll和下面的这4个dll 只生成TestIlmerge.dll 打开工程文件 在最下方加入以下两段 <Target Name"ILMerge…...

scipy.sparse.coo_matrix.sum()关于axis的用法

以下面的矩阵为例 [1,2,0] [0,3,0] [0,0,0]示例代码 from scipy.sparse import coo_matrix# 创建一个稀疏矩阵 data [1, 2, 3] row [0, 0, 1] col [0, 1, 1] sparse_matrix coo_matrix((data, (row, col)), shape(3,3))# 计算稀疏矩阵中每行非零元素的总和 sum_of_column…...

C++类与对象(下)

文章目录 1.非类型模板2.模板特化2.1.类模板特化2.1.1.全特化2.1.2.偏特化 2.2.函数模板特化 3.函数模板声明定义分离 之前我们学习的模板能达到泛型的原因是&#xff1a;使用了“泛型的类型”&#xff0c;但是如果经过后面的“造轮子”&#xff08;后面会尝试实现一下 STL的一…...

SpringBoot——》引入Redis

推荐链接&#xff1a; 总结——》【Java】 总结——》【Mysql】 总结——》【Redis】 总结——》【Kafka】 总结——》【Spring】 总结——》【SpringBoot】 总结——》【MyBatis、MyBatis-Plus】 总结——》【Linux】 总结——》【MongoD…...

C# newtonsoft序列化将long类型转化为字符串

/// <summary> /// 转化为json的时候long类型转为string /// </summary> public class LongJsonConverter: JsonConverter {public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer){try{return r…...

黑马点评-02使用Redis代替session,Redis + token机制实现

Redis代替session session共享问题 每个Tomcat中都有一份属于自己的session,所以多台Tomcat并不共享session存储空间,当请求切换到不同tomcat服务时可能会导致数据丢失 用户第一次访问1号tomcat并把自己的信息存放session域中, 如果第二次访问到了2号tomcat就无法获取到在1号…...

arm 点灯实验代码以及现象

.text .global _start _start: 1.设置GPIOE寄存器的时钟使能 RCC_MP_AHB4ENSETR[4]->1 0x50000a28 LDR R0,0x50000A28 LDR R1,[R0] ORR R1,R1,#(0x1<<4) 第4位置1 STR R1,[R0] 1.设置GPIOF寄存器的时钟使能 RCC_MP_AHB4ENSETR[4]->1 0x50000a28 LDR R…...

选择适合普通公司的项目管理软件

不管是打工人还是学生党都适合使用Zoho Projects项目管理软件。利用项目概览功能&#xff0c;将整体项目尽收眼底&#xff0c;作为项目管理者&#xff0c;项目日程、进度都可见&#xff0c;Zoho Projects项目管理APP助推项目每一环节的进展&#xff0c;更便于管理者设计项目的下…...

E (1081) : DS堆栈--逆序输出(STL栈使用)

Description C中已经自带堆栈对象stack&#xff0c;无需编写堆栈操作的具体实现代码。 本题目主要帮助大家熟悉stack对象的使用&#xff0c;然后实现字符串的逆序输出 输入一个字符串&#xff0c;按字符按输入顺序压入堆栈&#xff0c;然后根据堆栈后进先出的特点&#xff0…...

访问者模式 行为型设计模式之九

1.定义 在不改变数据结构的前提下&#xff0c;增加作用于一组对象元素的新功能。 2.动机 访问者模式适用于数据结构相对稳定的系统它把数据结构和作用于数据结构之上的操作之间的耦合解脱开&#xff0c;使得操作集合可以相对自由的演化。访问者模式的目的是要把处理从数据结构…...

JVM垃圾回收之JVM GC算法探究

JVM垃圾回收之JVM GC算法探究 在Java虚拟机&#xff08;JVM&#xff09;中&#xff0c;垃圾回收&#xff08;Garbage Collection&#xff0c;GC&#xff09;是自动管理内存的重要机制&#xff0c;它负责回收程序中不再使用的对象所占用的内存。GC算法是垃圾回收的核心&#xf…...

Django 前端模板显示换行符、日期格式

linebreaksbr 显示换行符 <td>{{ data.sku_list|default:"无"|linebreaksbr }}</td> date:"Y年m月d日 H:i" 设置日期格式 <td>{{ data.submit_time|date:"Y年m月d日 H:i" }}</td> 其他语法 forloop 获取循环的索引 …...

Aurora中的策略模式和模板模式

Aurora中的策略模式和模板模式 在aurora中为了方便以后的扩展使用了策略模式和模板模式实现图片上传和搜索功能&#xff0c;能够在配置类中设置使用Oss或者minio上传图片&#xff0c;es或者mysql文章搜索。后续有新的上传方式或者搜索方式只需要编写对应的实现类即可&#xff…...

Ubuntu 22.04 安装系统 手动分区 针对只有一块硬盘 lvm 单独分出/home

自动安装的信息 参考自动安装时产生的分区信息 rootyeqiang-MS-7B23:~# fdisk /dev/sdb -l Disk /dev/sdb&#xff1a;894.25 GiB&#xff0c;960197124096 字节&#xff0c;1875385008 个扇区 Disk model: INTEL SSDSC2KB96 单元&#xff1a;扇区 / 1 * 512 512 字节 扇区大…...

Android系统定制之监听USB键盘来判断是否弹出软键盘

一.项目背景 在设备上弹出软键盘,会将一大部分UI遮挡起来,造成很多图标无法看到和点击,使用起来不方便,因此通过插入usb键盘输入代替软键盘,但是点击输入框默认会弹出软键盘,因此想要插入USB键盘时,默认关闭软键盘,拔出键盘时再弹出,方便用户使用 二.设计思路 2.1…...

LeakyReLU激活函数

nn.LeakyReLU 是PyTorch中的Leaky Rectified Linear Unit&#xff08;ReLU&#xff09;激活函数的实现。Leaky ReLU是一种修正线性单元&#xff0c;它在非负数部分保持线性&#xff0c;而在负数部分引入一个小的斜率&#xff08;通常是一个小的正数&#xff09;&#xff0c;以防…...

Qt单一应用实例判断

原本项目中使用QSharedMemory的方法来判断当前是否已存在运行的实例&#xff0c;但在MacOS上&#xff0c;当程序异常崩溃后&#xff0c;QSharedMemory没有被正常销毁&#xff0c;导致应用程序无法再次被打开。 对此&#xff0c;Qt assistant中有相关说明&#xff1a; 摘抄 qt-s…...

企业AI工程化之路:如何实现高效、低成本、高质量的落地?

MLOps工程实践 概述面临挑战目的内容简介读者对象专家推荐目录 写在末尾&#xff1a; 主页传送门&#xff1a;&#x1f4c0; 传送 概述 作为计算机科学的一个重要领域&#xff0c;机器学习也是目前人工智能领域非常活跃的分支之一。机器学习通过分析海量数据、总结规律&#x…...

最短路径专题8 交通枢纽 (Floyd求最短路 )

题目&#xff1a; 样例&#xff1a; 输入 4 5 2 0 1 1 0 2 5 0 3 3 1 2 2 2 3 4 0 2 输出 0 7 思路&#xff1a; 由题意&#xff0c;绘制了该城市的地图之后&#xff0c;由给出的 k 个编号作为起点&#xff0c;求该点到各个点之间的最短距离之和最小的点是哪个&#xff0c;并…...

文件扫描模块

文章目录 前言文件扫描模块设计初级扫描方案一实现单线程扫描整合扫描步骤 设计初级扫描方案二周期性扫描 总结 前言 我们这个模块考虑的是数据库里面的内容从哪里获取。 获取完成后&#xff0c;这时候,我们就需要把目录里面文件/子文件都获取出来,并存入数据库。 文件扫描模…...

MySQL之主从复制

概述&#xff1a; 将主库的数据 变更同步到从库&#xff0c;从而保证主库和从库数据一致。 它的作用是 数据备份&#xff0c;失败迁移&#xff0c;读写分离&#xff0c;降低单库读写压力 原理&#xff1a; 主服务器上面的任何修改都会保存在二进制日志&#xff08; Bin-log日志…...

[leetcode 单调栈] 901. 股票价格跨度 M

设计一个算法收集某些股票的每日报价&#xff0c;并返回该股票当日价格的 跨度 。 当日股票价格的 跨度 被定义为股票价格小于或等于今天价格的最大连续日数&#xff08;从今天开始往回数&#xff0c;包括今天&#xff09;。 例如&#xff0c;如果未来 7 天股票的价格是 [100…...

Java线程池:并发编程的利器

Java线程池&#xff1a;并发编程的利器 在多任务、高并发的时代&#xff0c;Java并发编程显得尤为重要。其中&#xff0c;Java线程池是一种高效的管理线程的工具&#xff0c;能够提高应用程序的性能和响应速度。本文将深入探讨Java线程池的工作原理、应用场景以及简单示例&…...

ARM硬件断点

hw_breakpoint 是由处理器提供专门断点寄存器来保存一个地址&#xff0c;是需要处理器支持的。处理器在执行过程中会不断去匹配&#xff0c;当匹配上后则会产生中断。 内核自带了硬件断点的样例linux-3.16\samples\hw_breakpoint\data_breakpoint.c static void sample_hbp_h…...

Java使用WebSocket(基础)

准备一个html页面 <!DOCTYPE HTML> <html> <head><meta charset"UTF-8"><title>WebSocket Demo</title> </head> <body><input id"text" type"text" /><button onclick"send()&…...

构建网站的步骤/百度成都总部

InfluxDB 简介与安装 1、InfluxDB 简介 官网&#xff1a;https://www.influxdata.com/ 中文文档&#xff1a;https://jasper-zhang1.gitbooks.io/influxdb/content/ InfluxDB 是用Go语言编写的一个开源分布式时序、事件和指标数据库&#xff0c;无需外部依赖。 类似的数据库有…...

公共交通公司网站建设方案/企业网络推广的方法有哪些

本次读书笔记在于实现书上的从文本解析数据&#xff0c;使用Matplotlib创建散点图&#xff08;散点图使用DataMat矩阵的第二、第三列数据&#xff09;&#xff0c;分类器针对约会网站的测试等 首先介绍几个相关知识点&#xff0c;方便代码浏览。 知识点一&#xff1a; 1.对于高…...

国际网站建设招标/合肥seo建站

JavaScript学习笔记&#xff08;十&#xff09;——学习心得与经验小结 目前我先列好提纲&#xff0c;利用每晚和周末的闲暇时间&#xff0c;将逐步写完 ^_^转载于:https://www.cnblogs.com/springmvc-hibernate/archive/2010/08/06/2484248.html...

云南省建设厅官方网站证书/网络营销策略优化

var value $(‘input[name“sex”]:checked’).val();...

做最好的在线看片网站/东莞做网站seo

庆幸也与你逛过那一段旅程曾是日夜期待你施舍一点同情这算是固执做梦或太热情?在世上没有多少东西会尽如人意多数像讽刺逐年成长必经苦恋故事我爱你你扮作不知完了吧如无意外重今开始该好好恋爱放下从前一段感情才能追求将来你就似没存在完了吧仍能撑起来前进便让自尊心放开告…...

b2c网站多少钱/检测网站是否安全

Infoq已经发表了文章&#xff08;http://www.infoq.com/cn/articles/whole-software-testing-practice-requirements-to-operational&#xff09;&#xff0c;这里把原文公布下&#xff1a; 之前一篇文章《软件测试转型之路》 (http://www.infoq.com/cn/articles/transformatio…...