Spring IOC与DI

spring的两大思想:IOC与AOP

一、ioc的概念

什么叫控制翻转?

之前:

对象的使用方,创建对象,对象的控制权,在对象的使用方手中.

spring:

对象的控制权交给了spring.

举个例子:智能驾驶,之前车的使用权在人手中,而现在在ai手中,这就是控制反转.

什么叫ioc:

之前车企生产车需要做整个车,费事费力无法定制化,而现在车企将轮胎轮毂车底等外包给别人做,自己制作组装:

二、DI

本质上就是想在不new的基础上完成对象引入,目的是解耦.

依赖注入分为三种:

1.属性注入

java 复制代码
    @Autowired
    private  StudentController studentController;
    public void say(){
        System.out.println("helloworld");
        studentController.say();
    }

@Autowired就是属性注入的注释\

正常来说应该是

这样,但是加了属性注入注释就将这个注入到这个对象中了.

java 复制代码
// 1. 定义一个服务类(被依赖的对象)
@Service // 告诉Spring:这是一个服务,需要被容器管理
public class UserService {
    public void doService() {
        System.out.println("执行服务逻辑");
    }
}

// 2. 定义控制器(需要依赖的对象)
@Controller // 告诉Spring:这是一个控制器,需要被容器管理
public class UserController {
    
    // 3. 声明依赖:告诉Spring,我需要一个UserService对象
    @Autowired 
    private UserService userService;

    public void doController() {
        // 直接使用注入的对象,不用自己new
        userService.doService(); 
    }
}

@Autowired会根据名称进行注入,如果服务类中有多个名字对不上的该怎么办呢?有三种方法:

@Autowired与@Resource的区别:

1.注入顺序

@Autowired :默认按类型(Type)匹配注入。

  • 先根据字段 / 参数的类型在 Spring 容器中查找匹配的 Bean。

  • 如果存在多个同类型的 Bean,需要配合 @Qualifier 注解按名称(Name)筛选,否则会报错。
    示例:

    java 复制代码
    @Autowired
    @Qualifier("userServiceA") // 指定名称为userServiceA的Bean
    private UserService userService;

    @Resource :默认按名称(Name)匹配 注入,名称可以通过 name 属性指定。

  • 若未指定 name,则默认使用字段名或 setter 方法名作为 Bean 名称。

  • 若按名称找不到匹配的 Bean,会 fallback 到按类型匹配。
    示例:

    java 复制代码
    @Resource(name = "userServiceA") // 直接指定Bean名称
    private UserService userService;
    
    // 未指定name时,默认按字段名"userService"查找
    @Resource
    private UserService userService;
2.来源

@Autowired是spring提供的注释,@Resource是JDK提供的注释.

2.构造方法注入

通过构造方法进行注入

java 复制代码
package com.example.demo;

import org.springframework.stereotype.Controller;

// 控制器类(需要依赖的对象)
@Controller
public class UserController {
    
    // 依赖的服务对象,使用final修饰确保不可变
    private final UserService userService;
    
    // 构造方法注入:通过构造方法传入依赖
    // Spring会自动找到匹配的UserService对象注入进来
    public UserController(UserService userService) {
        this.userService = userService;
    }
    
    public void showUserName() {
        // 使用注入的依赖对象
        System.out.println("用户名:" + userService.getUserName());
    }
}

总所周知,构造方法可以有无参和有参,这是怎么告诉spring哪个是我们想要的:

java 复制代码
@Controller
public class UserController {
    private final UserService userService;

    // 无参构造方法(手动定义)
    public UserController() {
        // 注意:如果用无参构造创建对象,userService会为null
        this.userService = null;
    }

    // 有参构造方法(用于注入依赖)
    @Autowired // 必须添加,否则Spring会优先用无参构造
    public UserController(UserService userService) {
        this.userService = userService;
    }

    public void doSomething() {
        userService.doService(); // 只有通过有参构造创建的对象才能正常调用
    }
}

3.setter方法注入

java 复制代码
package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class UserController {
    private UserService userService;
    
    // setter方法注入:通过setter方法传入依赖
    @Autowired // 标注在setter方法上
    public void setUserService(UserService userService) {
        this.userService = userService;
    }
    
    public void showUserName() {
        // 使用注入的依赖对象
        System.out.println("用户名:" + userService.getUserName());
    }
}
    

三、bean的存储

将对象交给spring进行管理可以使用下面的这些注释:

类注解:

用代码来讲解:

java 复制代码
@Controller
public class UserController {
    public void say(){
        System.out.println("hello world");
    }
}

创建一个UserController类,如果要使用其中的对象就得new UserController(),来实例化对象,而此处我们加上@Controller后就是将对象托管给spring,而我们只需要从Spring中取对象即可,下面讲解一下取对象的具体步骤:

java 复制代码
@SpringBootApplication
public class DemoApplication {

	public static void main(String[] args) {
		ApplicationContext context=SpringApplication.run(DemoApplication.class, args);
		//1.通过类型取
		UserController controller=context.getBean(UserController.class);
		controller.say();
		//2.通过名字取
		UserController userController1=(UserController) context.getBean("userController");
		userController1.say();
		//3.通过名字和类型双重查找
		UserController userController2=context.getBean("userController",UserController.class);
		userController2.say();
	}

}

之后几个跟controller差不多

方法注解:

使用场景:

1.想修改第三方的无法修改的类

2.想使用多个对象时

代码解释:如此时有个无法修改的第三方类

java 复制代码
@AllArgsConstructor//添加一个全参数的构造函数
@NoArgsConstructor//添加一个无参数的构造函数
@Data
public class Student {
    private String name;
    private int age;
}

想使用它只能外置一个类:

java 复制代码
@Component
public class StudentController {
    @Bean
    public Student userInfo(){
        return new Student("zhansan",15);
    }
}

注意此处的方法注释@Bean必须和任意一个类注释一起使用,要先让spring知道你需要托管.

另外也可以new多个对象,但这里就不能通过类型去取了:

java 复制代码
@Component
public class StudentController {

    @Bean
    public Student userInfo(){
        return new Student("zhangsan", 20);
    }
    @Bean
    public Student userInfo1(){
        return new Student("lisi", 22);
    }
}

也可以修改默认名字或者添加复数个名字:

指定扫描路径

在spring搜索bean位置的时候会根据包的存储位置存储

也就是这个,有可能你分的包比较多,让spring无法搜索到你指定的bean,是可以进行修改的:

java 复制代码
@ComponentScan("com.example.dome")

总结: