Spring IOC与DI
spring的两大思想:IOC与AOP
一、ioc的概念
什么叫控制翻转?
之前:
对象的使用方,创建对象,对象的控制权,在对象的使用方手中.
spring:
对象的控制权交给了spring.
举个例子:智能驾驶,之前车的使用权在人手中,而现在在ai手中,这就是控制反转.
什么叫ioc:
之前车企生产车需要做整个车,费事费力无法定制化,而现在车企将轮胎轮毂车底等外包给别人做,自己制作组装:
二、DI
本质上就是想在不new的基础上完成对象引入,目的是解耦.
依赖注入分为三种:
1.属性注入
@Autowiredprivate StudentController studentController;public void say(){System.out.println("helloworld");studentController.say();}
@Autowired就是属性注入的注释\
正常来说应该是
这样,但是加了属性注入注释就将这个注入到这个对象中了.
// 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() {// 直接使用注入的对象,不用自己newuserService.doService(); }
}
@Autowired会根据名称进行注入,如果服务类中有多个名字对不上的该怎么办呢?有三种方法:
@Autowired与@Resource的区别:
1.注入顺序
@Autowired
:默认按类型(Type)匹配注入。
- 先根据字段 / 参数的类型在 Spring 容器中查找匹配的 Bean。
- 如果存在多个同类型的 Bean,需要配合
@Qualifier
注解按名称(Name)筛选,否则会报错。
示例:@Autowired @Qualifier("userServiceA") // 指定名称为userServiceA的Bean private UserService userService;
@Resource
:默认按名称(Name)匹配注入,名称可以通过name
属性指定。 - 若未指定
name
,则默认使用字段名或 setter 方法名作为 Bean 名称。 - 若按名称找不到匹配的 Bean,会 fallback 到按类型匹配。
示例:@Resource(name = "userServiceA") // 直接指定Bean名称 private UserService userService;// 未指定name时,默认按字段名"userService"查找 @Resource private UserService userService;
2.来源
@Autowired是spring提供的注释,@Resource是JDK提供的注释.
2.构造方法注入
通过构造方法进行注入
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哪个是我们想要的:
@Controller
public class UserController {private final UserService userService;// 无参构造方法(手动定义)public UserController() {// 注意:如果用无参构造创建对象,userService会为nullthis.userService = null;}// 有参构造方法(用于注入依赖)@Autowired // 必须添加,否则Spring会优先用无参构造public UserController(UserService userService) {this.userService = userService;}public void doSomething() {userService.doService(); // 只有通过有参构造创建的对象才能正常调用}
}
3.setter方法注入
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进行管理可以使用下面的这些注释:
类注解:
用代码来讲解:
@Controller
public class UserController {public void say(){System.out.println("hello world");}
}
创建一个UserController类,如果要使用其中的对象就得new UserController(),来实例化对象,而此处我们加上@Controller后就是将对象托管给spring,而我们只需要从Spring中取对象即可,下面讲解一下取对象的具体步骤:
@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.想使用多个对象时
代码解释:如此时有个无法修改的第三方类
@AllArgsConstructor//添加一个全参数的构造函数
@NoArgsConstructor//添加一个无参数的构造函数
@Data
public class Student {private String name;private int age;
}
想使用它只能外置一个类:
@Component
public class StudentController {@Beanpublic Student userInfo(){return new Student("zhansan",15);}
}
注意此处的方法注释@Bean必须和任意一个类注释一起使用,要先让spring知道你需要托管.
另外也可以new多个对象,但这里就不能通过类型去取了:
@Component
public class StudentController {@Beanpublic Student userInfo(){return new Student("zhangsan", 20);}@Beanpublic Student userInfo1(){return new Student("lisi", 22);}
}
也可以修改默认名字或者添加复数个名字:
指定扫描路径
在spring搜索bean位置的时候会根据包的存储位置存储
也就是这个,有可能你分的包比较多,让spring无法搜索到你指定的bean,是可以进行修改的:
@ComponentScan("com.example.dome")