Web基础-分层解耦-IOC&Dl详解

(回顾重点)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 默认是按照名称注入
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值