Spring IoC & DI(笔记)

 一.了解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不再直接依赖于SedanSUV类,而是依赖于IoCContainer接口。这降低了客户端代码与具体实现之间的耦合度。如果需要更换车辆类型或添加新的车辆类型,我们只需要修改IoCContainer的实现,而不需要修改客户端代码。

1.1.3IoC的优势

IoC的好处包括:

  1. 降低耦合度:由于对象之间的依赖关系是通过IoC容器来管理的,因此对象之间的耦合度大大降低。这使得代码更加模块化,易于维护和扩展。

  2. 提高可测试性:在IoC的帮助下,可以更容易地模拟和替换依赖项,从而更容易地进行单元测试。

  3. 提高灵活性: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层的解耦。

步骤:

  1. Service层及Dao层的实现类,交给Spring管理:使⽤注解:@Component
  2. 在Controller层和Service层注⼊运⾏时依赖的对象:使⽤注解实现:@Autowired
  3. 把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;
	}
}
3. 删除创建BookDao的代码, 从Spring中获取对象
@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;
	}
}
4. 删除创建BookService的代码, 从Spring中获取对象

@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的存储

前⾯我们提到IoC控制反转,就是将对象的控制权交给Spring的IOC容器,由IOC容器创建及管理对
象。 也就是bean的存储.
共有两类注解类型可以实现:
1. 类注解:@Controller、@Service、@Repository、@Component、@Configuration.
2. ⽅法注解:@Bean.

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地址,如果有的话。
  • licensesdevelopersscm: 这些元素用于定义项目的许可证、开发者信息和源代码管理信息,但在这个例子中它们都是空的。

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主要用于编译时注解处理,并不包含在最终的打包文件中。这里的配置可能是基于误解或特定需求而添加的。

 

好的,我们可以使用 C# 语言和 ASP.NET MVC 框架来实现一个简单的登录功能,并使用三层架构、IoCDI 进行解耦。 首先,我们需要创建一个 ASP.NET MVC 项目,并添加需要的 NuGet 包,比如 Autofac、Autofac.Mvc5 等。 接下来,我们按照以下步骤进行实现: 1. 创建表示层(Presentation Layer):在 Controllers 文件夹下创建一个 LoginController,编写 Index 和 Login 两个 Action,分别对应登录页面和登录事件。在 Views 文件夹下创建 Login 文件夹,并添加 Index 和 Login 两个视图页面,用于显示登录页面和处理登录事件。 2. 创建业务逻辑层(Business Logic Layer):在 Services 文件夹下创建一个 ILoginService 接口,定义 Login 方法用于验证用户是否登录成功。在实现类 LoginService 中,实现 ILoginService 接口,并添加 UserRepository 属性,用于访问数据访问层(Data Access Layer)。在 Login 方法中,调用 UserRepository 的方法获取用户信息,比对用户名和密码是否正确,如果正确则返回 true,表示登录成功;否则返回 false,表示登录失败。 3. 创建数据访问层(Data Access Layer):在 Repositories 文件夹下创建一个 IUserRepository 接口,定义 GetUserByName 方法用于根据用户名获取用户信息。在实现类 UserRepository 中,实现 IUserRepository 接口,并添加 DbContext 属性,用于访问数据库。在 GetUserByName 方法中,调用 DbContext 的方法查询数据库,获取用户信息。 4. 配置 IoC 容器:在 App_Start 文件夹下创建一个 AutofacConfig 类,添加一个 Register 方法,用于注册 IoC 容器。在 Register 方法中,添加对 LoginService 和 UserRepository 的注册,通过构造函数注入 DbContext。 5. 配置 DI 依赖:在 Global.asax.cs 文件中,添加一个 Application_Start 方法,用于注册 DI 依赖。在 Application_Start 方法中,调用 AutofacConfig 类的 Register 方法,注册 IoC 容器。 6. 运行测试:运行应用程序,访问登录页面,输入用户名和密码,点击登录按钮,程序会调用 LoginController 的 Login 方法,验证用户名和密码是否正确,如果正确则跳转到首页;否则返回登录页面并显示错误信息。 以上就是使用三层架构、IoCDI 实现简单登录的步骤,具体代码实现可以参考以下示例项目: https://github.com/autofac/Examples/tree/master/src/Mvc5Example
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值