一.了解SpringIoC&DI
1.1IoC
通过前面的学习,我们知道了Spring是一个开源框架,他让我们的开发更加简单.他支持广泛的应用场
景,有着活跃而庞大的社区,这也是Spring能够长久不衰的原因,但是这个概念相对来说,还是比较抽象,我们用一句更具体的话来概括Spring,那就是:Spring 是包含了众多工具方法的loC容器
那问题来了,什么是容器? 什么是loC 容器? 接下来我们一起来看。
1.1.1 什么是Ioc容器(面试点)
什么是容器?
生活中的水杯,垃圾桶,冰箱等等这些都是容器,我们接触的容器有哪些?
List/Map->数据存储容器
Tomcat-> Web 容器。
什么是IoC?
IoC是Spring的核⼼思想,其实IoC我们在前⾯已经使⽤了,我们在前⾯讲到,在类上⾯添加@RestController和@Controller 注解。就是把这个对象交给Spring管理,Spring框架启动时就会加载该类.把对象交给Spring管理,就是IoC思想.
IoC:InversionofControl(控制反转),也就是说Spring是⼀个"控制反转"的容器。
什么是控制反转呢?
也就是控制权反转.什么的控制权发⽣了反转?获得依赖对象的过程被反转了
也就是说,当需要某个对象时,传统开发模式中需要⾃⼰通过new创建对象,现在不需要再进⾏创建,把创建对象的任务交给容器,程序中只需要依赖注⼊(DependencyInjection,DI)就可以了.这个容器称为:IoC容器.Spring是⼀个IoC容器,所以有时Spring也称为Spring容器.
控制反转是⼀种思想,在⽣活中也是处处体现.
⽐如⾃动驾驶,传统驾驶⽅式,⻋辆的横向和纵向驾驶控制权由驾驶员来控制,现在交给了驾驶⾃动化系统来控制,这也是控制反转思想在⽣活中的实现.
举个栗子~
首先,想象一下你正在做一顿丰盛的晚餐,你需要准备多种食材和调料,并且按照特定的步骤来烹饪。在这个过程中,你(作为厨师)是控制一切的人,你决定什么时候加什么食材,用什么火候,等等。这就是“传统的控制流程”。
现在,让我们把场景切换到IoC的世界。想象一下,你不再是一个单打独斗的厨师,而是变成了一家餐厅的主厨。你不再亲自去菜市场挑选食材,也不再亲自去厨房的每一个角落准备调料。相反,你有一个专门的团队来为你做这些事情:采购员负责购买食材,切配师负责将食材切好并准备好,调料师则负责准备各种调料。而你,作为主厨,只需要告诉团队你想要做什么菜,然后他们会把所有准备好的东西送到你面前,你只需要按照食谱进行烹饪即可。
在这个过程中,控制权发生了“反转”。原本你需要亲自去控制每一个细节(挑选食材、准备调料、切配等),但现在这些工作都被团队承担了,你只需要专注于最核心的任务——烹饪。这就是IoC的核心理念:将控制权从你自己(应用程序中的代码)转移到外部的一个容器或框架(IoC容器)中。
1.1.2使用IoC代码
1.没有IoC的情况
// Car接口
interface Car {
void drive();
}
// Sedan类,实现Car接口
class Sedan implements Car {
public void drive() {
System.out.println("Driving a Sedan");
}
}
// SUV类,实现Car接口
class SUV implements Car {
public void drive() {
System.out.println("Driving an SUV");
}
}
// CarFactory类,负责创建Car实例
class CarFactory {
public static Car createCar(String type) {
if ("sedan".equalsIgnoreCase(type)) {
return new Sedan();
} else if ("suv".equalsIgnoreCase(type)) {
return new SUV();
}
return null;
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Car myCar = CarFactory.createCar("sedan");
myCar.drive();
// 如果需要更换车辆类型,需要修改这里
Car anotherCar = CarFactory.createCar("suv");
anotherCar.drive();
}
}
代码解读:
在这个例子中,虽然CarFactory
类在一定程度上封装了Car
对象的创建逻辑,但客户端代码仍然需要直接调用CarFactory
来创建Car
对象。这意味着客户端代码与具体的Car
实现之间存在耦合。
2.使用IoC代码
在IoC的情况下,我们通常会使用一个IoC容器来管理对象的生命周期和依赖关系。以下代码,它展示了如何解耦客户端代码和具体的Car
实现。
// 假设的IoC容器接口
interface IoCContainer {
Car getCar(String type);
}
// IoC容器的实现
class SimpleIoCContainer implements IoCContainer {
@Override
public Car getCar(String type) {
if ("sedan".equalsIgnoreCase(type)) {
return new Sedan();
} else if ("suv".equalsIgnoreCase(type)) {
return new SUV();
}
return null;
}
}
// 客户端代码,现在与IoC容器交互
public class ClientWithIoC {
public static void main(String[] args) {
IoCContainer container = new SimpleIoCContainer();
Car myCar = container.getCar("sedan");
myCar.drive();
// 更换车辆类型时,不需要修改客户端代码
Car anotherCar = container.getCar("suv");
anotherCar.drive();
}
}
代码解读:
客户端代码ClientWithIoC
不再直接依赖于Sedan
或SUV
类,而是依赖于IoCContainer
接口。这降低了客户端代码与具体实现之间的耦合度。如果需要更换车辆类型或添加新的车辆类型,我们只需要修改IoCContainer
的实现,而不需要修改客户端代码。
1.1.3IoC的优势
IoC的好处包括:
-
降低耦合度:由于对象之间的依赖关系是通过IoC容器来管理的,因此对象之间的耦合度大大降低。这使得代码更加模块化,易于维护和扩展。
-
提高可测试性:在IoC的帮助下,可以更容易地模拟和替换依赖项,从而更容易地进行单元测试。
-
提高灵活性:IoC容器允许在运行时动态地替换和修改对象,这为应用程序带来了更高的灵活性。
1.2DI
概念:DI(Dependency Injection,依赖注入)是一种软件设计模式,用于管理对象之间的依赖关系。其核心思想是将对象之间的依赖关系从对象内部移到外部,由外部容器(DI容器)负责管理和注入依赖。
举个例子~
如果我们采用DI的方式,你可以有一个“电脑组装工厂”(DI容器)。你只需要告诉它你想要一台什么样的电脑(比如配置要求),它就会自动为你准备好所有需要的部件,并将它们组装成一台完整的电脑。这样,你就不需要亲自去购买和组装每一个部件了,而是由“电脑组装工厂”来帮你注入这些依赖。
二.IoC&DI使用
2.IoC&DI使⽤
对IoC和DI有了初步的了解,我们接下来具体学习SpringIoC和DI的代码实现.依然是先使⽤,再学习
既然Spring是⼀个IoC(控制反转)容器,作为容器,那么它就具备两个最基础的功能:
存和取
Spring容器管理的主要是对象,这些对象,我们称之为"Bean".我们把这些对象交由Spring管理,由Spring来负责对象的创建和销毁.我们程序只需要告诉Spring,哪些需要存,以及如何从Spring中取出对象。
⽬标:把BookDao,BookService交给Spring管理,完成Controller层,Service层,Dao层的解耦。
步骤:
- Service层及Dao层的实现类,交给Spring管理:使⽤注解:@Component
- 在Controller层和Service层注⼊运⾏时依赖的对象:使⽤注解实现:@Autowired
- 把BookDao交给Spring管理,由Spring来管理对象
1.把BookDao交给Spring管理,由Spring来管理对象
@Component
public class BookDao {
/**
* 数据Mock 获取图书信息
*
* @return
*/
public List<BookInfo> mockData() {
List<BookInfo> books = new ArrayList<>();
for (int i = 0; i < 5; i++) {
BookInfo book = new BookInfo();
book.setId(i);
book.setBookName("书籍" + i);
book.setAuthor("作者" + i);
book.setCount(i * 5 + 3);
book.setPrice(new BigDecimal(new Random().nextInt(100)));
book.setPublish("出版社" + i);
book.setStatus(1);
books.add(book);
}
return books;
}
}
2.把BookService 交给Spring管理, 由Spring来管理对象
@Component
public class BookService {
private BookDao bookDao = new BookDao();
public List<BookInfo> getBookList() {
List<BookInfo> books = bookDao.mockData();
for (BookInfo book : books) {
if (book.getStatus() == 1) {
book.setStatusCN("可借阅");
}
else {
book.setStatusCN("不可借阅");
}
}
return books;
}
}
@Component
public class BookService {
@Autowired
private BookDao bookDao;
public List<BookInfo> getBookList() {
List<BookInfo> books = bookDao.mockData();
for (BookInfo book : books) {
if (book.getStatus() == 1) {
book.setStatusCN("可借阅");
}
else {
book.setStatusCN("不可借阅");
}
}
return books;
}
}
@RequestMapping("/book")
@RestController
public class BookController {
@Autowired
private BookService bookService;
@RequestMapping("/getList")
public List<BookInfo> getList() {
//获取数据
List<BookInfo> books = bookService.getBookList();
return books;
}
}
5.运行程序
2.1Bean的存储
2.1.1类注解(五大注解)
@Component
package com.example.demo.component;
import org.springframework.stereotype.Component;
@Component
public class UserComponent {
public void doComponent(){
System.out.println("do component...");
}
}
@Configuration
package com.example.demo.config;
import org.springframework.context.annotation.Configuration;
@Configuration
public class UserConfig {
public void doConfig(){
System.out.println("do config...");
}
}
@Controller
package com.example.demo.controller;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
public void sayHi(){
System.out.println("do controller...");
}
}
@Repository
package com.example.demo.reop;
import org.springframework.stereotype.Repository;
@Repository
public class UserReop {
public void doRepo(){
System.out.println("do repo");
}
}
@Service
package com.example.demo.service;
import org.springframework.stereotype.Service;
@Service
public class UserService {
public void doService(){
System.out.println("do service...");
}
}
1. 在启动类导入正确的接口。
2.使⽤ @Controller 存储 bean 的代码
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
private UserService userService;
public void sayHi(){
userService.doService();
System.out.println("do controller...");
}
}
3.从Spring容器中获取对象。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext; // 导入正确的ApplicationContext
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
// 通过类型获取Bean
UserController bean = context.getBean(UserController.class);
bean.sayHi();
}
}
4.运行程序
这就是简单的Bean对象的存储和使用。
ApplicationContext(应用上下文):你可以把ApplicationContext
看作是一个“超级容器”。在这个容器里,你存放了Spring应用程序中的所有“组件”(这些组件在Spring中被称为Bean,比如服务类、数据访问对象、控制器等)。这个超级容器不仅负责存放这些组件,还知道它们之间的依赖关系,并能够在需要时自动地将它们组装起来。当你启动Spring应用程序时,ApplicationContext
就像是一个装满了你所需一切物品的行李箱,它为你准备好了所有必要的资源,以便你能够轻松地开始你的旅程。
1.类注解
以上三个对象是同一个。(单例模式的体现)。
特殊情况一:
如果创建UController类名(首两个字母都是大写)那在通过名称获取Bean时,写"uController"
如下:
UController beanByName = (UController) context.getBean("uController");
beanByName.sayHi();
则会报错(显示找不到Bean对象)。
通过在类路径中扫描组件,Spring将按照描述的规则为未命名的组件生成Bean名称
(Spring在这里使用)定义的规则相同e
早些时候,通常情况下小采用简单的类名并将其首字母转换为小写。然而,在(不同寻常的)特殊演员当有多个字符并且第一个和第二个字符都是大写时,保留原始大小写。
。
五大注解:
使用这些注解的对象都能交给Spring管理
如果没有使用注解,就会报错。
2,方法注解(第三方类/库交给Spring管理)
比如现在创建一个第三方类
用课件(IDEA报错,草)
不能单独使用@Bean,搭配五大注解
告诉Spring管理的时是哪些范围
传多个
添加两个
报异常,大意是找到两个Bean,不知用哪个,此时我们就要使用(方法)名称来获取了。
1.
2.
3.
三种注入方式优缺点(八股文)
....
1 (面试题)
2.
1. Spring(高铁系统)
Spring 可以被看作是整个高铁系统。它提供了一套全面的编程和配置模型,用于现代基于Java的企业级应用程序。Spring旨在通过简化开发过程来加速和简化企业级应用的开发。它就像高铁系统一样,是一个庞大而复杂的系统,包含多个子系统和组件,如轨道、车辆、信号系统、电力供应等,共同协作以确保高效、安全、快速的运输服务。Spring框架同样包含多个模块,如Spring Core(核心容器)、Spring AOP(面向切面编程)、Spring ORM(对象关系映射)、Spring Web等,这些模块共同为开发者提供了一套全面的解决方案。
2. Spring MVC(高铁站)
Spring MVC 类似于高铁站。在高铁系统中,高铁站是乘客上下车、购票、换乘的集散地,提供了各种服务以确保乘客能够顺利出行。同样地,Spring MVC是一个用于构建Web应用程序的框架,它基于MVC(模型-视图-控制器)设计模式。在Spring MVC中,控制器(Controller)负责处理用户请求,模型(Model)封装了应用程序的数据,视图(View)则负责展示数据给用户。Spring MVC为开发者提供了一个清晰的结构,使得开发Web应用变得更加容易和高效。
3. Spring Boot(12306)
Spring Boot 可以看作是12306网站。12306是中国铁路客户服务中心的官方售票网站,它为用户提供了一个便捷、快速的购票平台。用户无需深入了解复杂的后台系统,只需通过简单的操作即可完成购票。Spring Boot正是基于这样的理念,它旨在简化Spring应用的初始搭建以及开发过程。通过自动配置、起步依赖等特性,Spring Boot帮助开发者快速搭建Spring应用,无需进行大量的配置工作。就像12306网站一样,Spring Boot让开发者能够更专注于业务逻辑的实现,而不是被繁琐的配置所困扰。
综上所述,Spring是高铁系统,提供了全面的企业级应用开发框架;Spring MVC是高铁站,专注于Web应用的MVC架构实现;而Spring Boot则是12306网站,通过简化配置和自动配置等特性,帮助开发者快速搭建Spring应用。这三者共同构成了Spring生态系统,为开发者提供了强大的支持和便利。
微服务类似京东的秒杀,推荐,精选,团购,百亿补贴的项目,SpringCloud是解决微服务问题的,这样理解对吗。
是的,您的理解是正确的。在类似京东这样的大型电商系统中,秒杀、推荐、精选、团购、百亿补贴等功能模块通常都是作为独立的微服务来设计和实现的。微服务架构通过将大型应用拆分成一组小的服务,每个服务运行在其独立的进程中,服务与服务之间采用轻量级的通信机制(如HTTP REST API)相互协作。这种架构模式有助于提升系统的可扩展性、可用性和可维护性。
Spring Cloud正是一套用于构建微服务的框架集合,它基于Spring Boot,为开发者提供了在分布式系统中快速构建微服务所需的一系列模式和工具。Spring Cloud集成了服务发现(如Eureka)、配置管理(如Spring Cloud Config)、智能路由(如Zuul或Spring Cloud Gateway)、断路器(如Hystrix)、监控(如Spring Boot Admin)、分布式追踪(如Sleuth和Zipkin)等关键组件,以支持微服务架构中的常见需求和挑战。
因此,当您提到微服务类似京东的秒杀、推荐、精选、团购、百亿补贴的项目时,使用Spring Cloud作为解决方案是非常合适的。Spring Cloud能够帮助您构建和管理这些微服务,确保它们能够高效地协作,同时提供必要的工具和框架来支持服务的注册与发现、配置管理、负载均衡、容错处理、监控和追踪等功能。这样,您可以更专注于业务逻辑的实现,而不是被分布式系统的复杂性所困扰。
这个pom.xml
文件是Maven项目的核心配置文件,用于定义项目的构建、依赖、插件等。下面是对该文件中每个主要区域的作用的详细解释:
1. 项目元数据
- project: 这是根元素,包含了POM文件的所有内容。
- modelVersion: 指定了POM模型的版本,对于Maven 2和Maven 3,这个值通常是
4.0.0
。 - groupId: 定义了项目属于哪个组或组织,通常与公司的域名反向有关,例如
com.example
。 - artifactId: 定义了项目在组中的唯一ID,例如
demo
。 - version: 定义了项目的当前版本,例如
0.0.1-SNAPSHOT
,其中SNAPSHOT
表示这是一个快照版本,用于开发过程中。 - name: 项目的显示名称,通常用于Maven生成的文档中。
- description: 项目的简短描述。
- url: 项目的URL地址,如果有的话。
- licenses, developers, scm: 这些元素用于定义项目的许可证、开发者信息和源代码管理信息,但在这个例子中它们都是空的。
2. 属性
- properties: 定义了一系列可以在POM中其他地方引用的属性。在这个例子中,只定义了
java.version
属性,指定了项目使用的Java版本为17。
3. 依赖
- dependencies: 列出了项目所需的依赖项。Maven会解析这些依赖项,并从配置的远程仓库中下载它们。
- spring-boot-starter-web: Spring Boot的Web启动器,包含了构建Web应用程序所需的所有Spring和相关的第三方库。
- lombok: 一个Java库,用于通过注解自动化生成getter/setter等方法,减少样板代码。
- spring-boot-starter-test: Spring Boot的测试启动器,包含了常用的测试库,如JUnit、Mockito等。
4. 构建配置
- build: 包含了与项目构建相关的配置。
- plugins: 定义了构建过程中使用的插件。
- spring-boot-maven-plugin: Spring Boot的Maven插件,提供了多种与Spring Boot应用程序打包和运行相关的功能。
- configuration: 插件的配置部分。
- excludes: 在这个例子中,尝试排除
lombok
依赖项从打包过程中,但实际上这通常是不必要的,因为lombok
主要用于编译时注解处理,并不包含在最终的打包文件中。这里的配置可能是基于误解或特定需求而添加的。
- excludes: 在这个例子中,尝试排除
- configuration: 插件的配置部分。
- spring-boot-maven-plugin: Spring Boot的Maven插件,提供了多种与Spring Boot应用程序打包和运行相关的功能。
- plugins: 定义了构建过程中使用的插件。