(回顾重点)Q:什么是IOC以及DI?
控制反转: Inversion Of Control,简称IOC。对象的创建控制权由程序自身转移到外部(容器),这种思想称为控制反转。
依赖注入: Dependency Injection,简称DI。容器为应用程序提供运行时,所依赖的资源,称之为依赖注入。
Bean对象:IOC容器中创建、管理的对象,称之为Bean。
IOC详解:
回顾一下三层架构:
在之前的入门案例中,要把某个对象交给IOC容器管理,需要在类上添加一个注解:@Component
而Spring框架为了更好的标识web应用程序开发当中,bean对象到底归属于哪一层,又提供了
@Component的衍生注解:
注解
说明
位置
@Component
声明bean的基础注解
不属于以下三类时,用此注解(一般是pojo下的实体类)
@Controller
@Component的衍生注解
标注在控制层类上
@Service
@Component的衍生注解
标注在业务层类上
@Repository
@Component的衍生注解
标注在数据访问层类上(由于与mybatis整合,用的少)
注意1:声明bean的时候,可以通过注解的value属性指定bean的名字,如果没有指定,默认为类名首字母小写。
注意2:使用以上四个注解都可以声明bean,但是在springboot集成web开发中,声明控制器bean只能用@Controller。(规定必须遵守)
补充:@RestController的底层已经封装过了@controller注解,所以不用单独添加注解。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {
/**
* The value may indicate a suggestion for a logical component name,
* to be turned into a Spring bean in case of an autodetected component.
* @return the suggested component name, if any (or empty String otherwise)
* @since 4.0.1
*/
@AliasFor(annotation = Controller.class)
String value() default "";
}
组件扫描:
问题:使用前面学习的四个注解声明的bean,一定会生效吗?
答案:不一定。(原因:bean想要生效,还需要被组件扫描)
-
前面声明bean的四大注解,要想生效,还需要被组件扫描注解
@ComponentScan
扫描。 -
该注解虽然没有显式配置,但是实际上已经包含在了启动类声明注解(细节)
-
@SpringBootApplication
中,默认扫描的范围是启动类所在包及其子包。(重点)超出这个范围的bean都将扫描不到。
所以,在项目开发中,只需要按照如上项目结构,将项目中的所有的业务类,都放在启动类所在包的子包中,就无需考虑组件扫描问题。
DI详解:
依赖注解DI的细节
依赖注入,是指IOC容器要为应用程序去提供运行时所依赖的资源,而资源指的就是对象。
我们可以使用了@Autowired这个注解,完成依赖注入的操作;
而这个Autowired翻译过来叫:自动装配。@Autowired
注解,默认是按照类型进行自动装配的(去IOC容器中找某个类型的对象,然后完成注入操作)
入门程序举例:在EmpController运行的时候,就要到IOC容器当中去查找EmpService这个类型的对象,而我们的IOC容器中刚好有一个EmpService这个类型的对象,所以就找到了这个类型的对象完成注入操作。
@Autowired用法
@Autowired 进行依赖注入,常见的方式,有如下三种:
1). 属性注入
@RestController
public class UserController {
//方式一: 属性注入
@Autowired
private UserService userService;
}
-
优点:代码简洁、方便快速开发。
-
缺点:隐藏了类之间的依赖关系、可能会破坏类的封装性。
2). 构造函数注入
@RestController
public class UserController {
//方式二: 构造器注入
private final UserService userService;
@Autowired //如果当前类中只存在一个构造函数, @Autowired可以省略
public UserController(UserService userService) {
this.userService = userService;
}
}
-
优点:能清晰地看到类的依赖关系、提高了代码的安全性。
-
缺点:代码繁琐、如果构造参数过多,可能会导致构造函数臃肿。
-
注意:如果只有一个构造函数,@Autowired注解可以省略。(通常来说,也只有一个构造函数)
3). setter注入
/**
* 用户信息Controller
*/
@RestController
public class UserController {
//方式三: setter注入
private UserService userService;
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
}
-
优点:保持了类的封装性,依赖关系更清晰。
-
缺点:需要额外编写setter方法,增加了代码量。
小结:在项目开发中,基于@Autowired进行依赖注入时,基本都是第一种和第二种方式。(官方推荐第二种方式,因为会更加规范)但是在企业项目开发中,很多的项目中,也会选择第一种方式因为更加简洁、高效(在规范性方面进行了妥协)。
注意事项
那如果在IOC容器中,存在多个相同类型的bean对象,会出现什么情况呢?
在下面的例子中,我们准备了两个UserService的实现类,并且都交给了IOC容器管理。 代码如下:
此时,我们启动项目会发现,控制台报错了:
出现错误的原因呢,是因为在Spring的容器中,UserService这个类型的bean存在两个,框架不知道具体要注入哪个bean使用,所以就报错了。
如何解决上述问题呢?Spring提供了以下几种解决方案:
-
@Primary
-
@Qualifier
-
@Resource
方案一:使用@Primary注解
当存在多个相同类型的Bean注入时,加上@Primary注解,来确定默认的实现。
@Primary
@Service
public class UserServiceImpl implements UserService {
}
方案二:使用@Qualifier注解
指定当前要注入的bean对象。 在@Qualifier的value属性中,指定注入的bean的名称。 @Qualifier注解不能单独使用,必须配合@Autowired使用。
@RestController
public class UserController {
@Qualifier("userServiceImpl")
@Autowired
private UserService userService;
方案三:使用@Resource注解
是按照bean的名称进行注入。通过name属性指定要注入的bean的名称。
@RestController
public class UserController {
@Resource(name = "userServiceImpl")
private UserService userService;
总结一下:
方案一是直接在类上指明优先级,告诉spring如果出现多个同种类型的bean优先选择哪一个。
方案二三是在为类注入bean的时候具体指明我要注入哪个bean,只不过@Autowired 默认是按照类型注入,而@Resource是按照名称注入
个人理解:
方案二和方案三的解决方法都不上很好,因为之所以使用依赖注入就是为了解决模块之间的耦合问题,实现二三两种方法其实不同模块之间还是会出现耦合的情况。个人感觉方案一会更好。
面试题:@Autowird 与 @Resource的区别
@Autowired 是spring框架提供的注解,而@Resource是JDK提供的注解
@Autowired 默认是按照类型注入,而@Resource是按照名称注入
小结:
1. 依赖注入的注解 @Autowired :默认按照类型自动装配 如果同类型的 bean 存在多个: • @Primary • @Autowired + @Qualifier • @Resource 2. @Resource 与 @Autowired 区别 ? @Autowired 是 Spring 框架提供的注解,而 @Resource 是 JavaEE 规范提供的 @Autowired 默认是按照类型注入,而 @Resource 默认是按照名称注入标签:Web,Dl,Resource,Autowired,bean,注解,IOC,注入 From: https://blog.csdn.net/m0_63949203/article/details/145106323