目录
IoC&DI是Spring的两个核心思想,Spring是一个包含了众多工具的IoC容器
一,IoC控制反转
IoC(inversion of Control)控制反转,也就是说spring是一个"控制反转"的容器,这里的控制权指的是bean的控制权,Spring管理的对象称之为bean,之前对象的使用方,创建对象.对象的控制权在对象的使用方手里.控制反转是指对象的控制权交给了Spring
1,Bean的存储:
有两类方法:
(1),类注解:
@Controller,@Service,@Responsitory,@Component,@Configuratic
(2),方法注解:
@Bean
--------------------------------------------
2,@Controller
程序开发⼈员不需要为bean指定名称(BeanId),如果没有显式的提供名称(BeanId),Spring容器将为该 bean⽣成唯⼀的名称. 命名约定使⽤Java标准约定作为实例字段名.也就是说,bean名称以⼩写字⺟开头,然后使⽤驼峰式 ⼤⼩写.也有⼀些特殊情况,当有多个字符并且第⼀个和第⼆个字符都是⼤写时,将保留原始的⼤⼩写.这些规则 与java.beans.Introspector.decapitalize (Spring在这⾥使⽤的)定义的规则相同
//法一:
ConfigurableApplicationContext context= SpringApplication.run(SpringIocApplication.class, args);
#context可以理解成Spring容器(Spring应用的上下文)
UserController bean = context.getBean(UserController.class);
bean.say();
//法二:
UserController userController = (UserController) context.getBean("userController");
userController.say();
//法三:
UserController userController1 = context.getBean("userController", UserController.class);
userController1.say();
System.out.println(bean);
System.out.println(userController);
System.out.println(userController1);
地址一样说明对象是同一个(单例模式)
@Service,@Responsitory,@Component,@Configuratic与@Controller的用法类似,这些注解和应用层是呼应的,例如:控制层使用的就是@Controller,业务逻辑层@Service,数据访问层为@Responsitory,配置层为@Configuratic,不同的层次对应不同的注解,由此程序员看到不同的注解就可以了解当前类的用途.
3,@Bean
作用:
(1)一个类需要多个对象
(2)使用外部类,没有办法对类进行注解
注:Bean的指定名称就是方法名.
外部类:
//外部类
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserInfo {
private String name;
private Integer age;
}
创建一个对象并交给Spring
在Spring框架的设计中,⽅法注解 @Bean 要配合类注解才能将对象正常的存储到Spring容器中
@Component
public class UserInfoComponent {
@Bean
public UserInfo userInfo(){
return new UserInfo("zhangsan",12);
}
}
用Bean创建多个对象
@Component
public class UserInfoComponent {
@Bean
public UserInfo userInfo(){
return new UserInfo("zhangsan",12);
}
@Bean
public UserInfo userInfo1(){
return new UserInfo("lisi",17);
}
}
@Bean重命名
@Bean(name = {"zhangsan","userInfo"})
public UserInfo userInfo(){
return new UserInfo("zhangsan",12);
}
综合上述代码使用:
public static void main(String[] args) {
ConfigurableApplicationContext context= SpringApplication.run(SpringIocApplication.class, args);
Object userInfo = context.getBean("userInfo");
System.out.println(userInfo);
Object userInfo1 = context.getBean("zhangsan");
System.out.println(userInfo);
Object userInfo2 = context.getBean("userInfo1");
System.out.println(userInfo2);
}
4,路径扫描:
想要让Bean生效,还要配置扫描路径,让Spring扫描到,让Spring扫描到这些就需要通过注解@ComponentScan来配置扫描路径.上述代码错误的原因就是当前只扫描了(com.ABdolphin.ioc是Spring默认的扫描类,我们创建的类都要放到这个路径底下)com.ABdolphin.ioc.Contraller;下方的代码,但是但是Bean在com.ABdolphin.ioc.component,所以扫描不到:
那为什么前⾯没有配置@ComponentScan注解也可以呢? @ComponentScan 注解虽然没有显式配置,但是实际上已经包含在了启动类声明注解 @SpringBootApplication 中了
二,DI依赖注入
有三种方式:
(1)属性注入
属性注⼊是使⽤ @Autowired 实现的,将Service类注⼊到Controller类中
@Controller
public class UserController {
@Autowired
private UserService userService;
public void say(){
userService.say();
System.out.println("UserController say...");
}
}
(2)构造方法注入
@Controller
public class UserController {
private UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
public void say(){
userService.say();
System.out.println("UserController say...");
}
}
如果有多个构造参数,这时会默认使用无参数的构造函数,所以就需要我们将默认使用的构造函数设置为有参数的构造函数,需要使用注解 @Autowired
@Controller
public class UserController {
private UserService userService;
public UserController() {
}
@Autowired #底层使用的反射,当调用构造方法时,发现没有给值,就自己从Spring容器中获取
public UserController(UserService userService) {
this.userService = userService;
}
public void say(){
userService.say();
System.out.println("UserController say...");
}
}
交给Spring管理的对象,如果有参数,这个参数可以自己指定,如果没有指定,Spring会根据名称或者类型,从容器中查找,并注入进来
(3)Set方法注入
@Controller
public class UserController {
private UserService userService;
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
public void say(){
userService.say();
System.out.println("UserController say...");
}
}
(4)三种方法的优缺点:
属性注入:
优点:简单
缺点只能用于IoC容器,不能注入一个final修饰的属性
构造函数注入(Spring4.X推荐):
Spring Boot 3.X对应的是Spring 6.X
优点:可以注入final修饰的属性,注入的对象不会被修改,通用性好,构造方法是JDK支持的,所以任何框架都是支持的
缺点:注入多个对象的时候,代码会比较繁琐
setter注入(Spring3.X推荐):
优点,缺点:可以调用setter方法,因此注入的对象是可以被修改的
(5)@Autowired存在的问题
同样类型有多个对象时,按对象名称来匹配.当一种类型只有一个对象时,不管名称,直接注入进来
当有多个同样类型有多个对象,且调用的名称与对象的名称均不相同,这时可以使用以下几种方案:
@Primary(Spring提供)
@Primary
@Bean
public UserInfo userInfo1(){
return new UserInfo("lisi",17);
}
@Qualifier(Spring提供)
写法一:
@Component
public class UserComponent {
@Qualifier("userInfo2")
@Autowired
private UserInfo ui;
public void say(){
System.out.println("UserComponent say...");
System.out.println(ui);
}
}
写法二:
@Bean
public String name(){
return "test";
}
/*@Primary*/
@Bean
public String name2(){
return "test2";
}
@Bean
public UserInfo userInfo2(@Qualifier("name2")String name3){
return new UserInfo(name3,17);
}
@Resource(JDK解决方案)
@Component
public class UserComponent {
@Resource(name = "userInfo2")
private UserInfo ui;
public void say(){
System.out.println("UserComponent say...");
System.out.println(ui);
}
}
(6)@Autowired和@Resource的区别:
1,@Autowired是根据类型进行匹配的,@Resource是根据名称进行匹配的[并不准确](@Autowired优先按照类型匹配,如果有相同类型的多个对象,就会根据名称匹配.@Resource前提也是按照类型匹配的)
2,@Autowired是spring框架提供的注解,⽽@Resource是JDK提供的注解
(7)Autowired的装配顺序:
Spring framework,SpringMVC,SpringBoot的联系和区别:
Spring framework:管理对象,以及对象之间的依赖关系,面向切面编程,数据库事务管理...
SpringMVC是一个Spring子框架,是一个web框架
SpringBoot:springBoot是对Spring的一个封装,为了简化Spring应用开发而出现的