0


Spring IoC & DI

博主主页: 码农派大星.

** 数据结构专栏**:Java数据结构

** 数据库专栏:**MySQL数据库

**JavaEE专栏:**JavaEE

关注博主带你了解更多数据结构知识

1. 应用分层

应⽤分层是⼀种软件开发设计思想,它将应⽤程序分成N个层次,这N个层次分别负责各⾃的职责,多个层次之间协同提供完整的功能.根据项⽬的复杂度,把项⽬分成三层,四层或者更多层,之前为了让项⽬快速上线,我们通常是不考虑分层的.但是随着业务越来越复杂,⼤量的 代码混在⼀起,会出现逻辑不清晰、各模块相互依赖、代码扩展性差、改动⼀处就牵⼀发⽽动全⾝等问题.所以学习对项⽬进⾏分层对我们来说就是很有必要的了.

1.1 如何分层:

我们上一篇博客中学的Spring MVC中就把整体的系统分成了Model(模型),View(视图)Controller(控制器)三个层次,也就是将⽤⼾视图和业务处理隔离开,并且通过控制器连接起来,很好地实现了表现和逻辑的解耦,是⼀种标准的软件分层架构

对于我们后端开发来说,我们可以把整体架构分为表现层、业务逻辑层和数据层.这种分层⽅式也称之为"三层架构"

  1. 表现层:就是展⽰数据结果和接受⽤⼾指令的,是最靠近⽤⼾的⼀层;(请求处理、响应数据:负责,接收⻚⾯的请求,给⻚⾯响应数据)

  2. 业务逻辑层:负责处理业务逻辑, ⾥⾯有复杂业务的具体实现;(逻辑处理:负责业务逻辑处理的代码)

  3. 数据层: 负责存储和管理与应⽤程序相关的数据(数据访问:负责业务数据的维护操作,包括增、删、改、查等操作.)

在Spring中我们把这三层分别分为:

Controller:控制层,接收前端发送的请求,对请求进⾏处理,并响应数据。

Service:业务逻辑层,处理具体的业务逻辑。

Dao:数据访问层,也称为持久层。负责数据访问操作,包括数据的增、删、改、查

1.2 MVC与三层架构区别联系

MVC 是一种设计模式,用于分离应用程序的用户界面(UI)和业务逻辑,强调用户界面和业务逻辑的分离,使得开发者可以专注于单一方面的开发,而不必担心其他部分的实现细节

三层架构是一种软件架构模式,强调应用程序的不同功能层之间的分离,使得每一层都可以独立开发和测试

MVC 更侧重于用户界面的实现和业务逻辑的分离,而三层架构侧重于整个应用程序的分层和模块化

MVC模式强调数据和视图分离,将数据展⽰和数据处理分开,通过控制器对两者进⾏组合. 三层架构强调不同维度数据处理的⾼内聚和低耦合,将交互界⾯,业务处理和数据库操作的逻辑分开

联系:提高代码的可维护性和可扩展性,⼆者的⽬的是相同的,都是"解耦,分层,代码复⽤"

可测试性:通过分离不同的功能到不同的层或组件,两者都使得单元测试和集成测试变得更加容易。

可维护性:在 MVC 和三层架构中,代码的组织方式使得维护和更新变得更加简单

2. Spring

Spring就是包含了众多⼯具⽅法的IoC容器

3.IoC & DI⼊⻔

**3.1 **什么是IoC?

IoC 是Spring的核⼼思想,其实IoC我们在前⾯已经使⽤了,我们在前⾯讲到,在类上⾯添加 @RestController 和 @Controller 注解,就是把这个对象交给Spring管理,Spring框架启动时就会加载该类.把对象交 给Spring管理,就是IoC思想.

IoC: Inversion of Control (控制反转),也就是说Spring是⼀个"控制反转"的容器

什么是控制反转呢? 也就是控制权反转.什么的控制权发⽣了反转? 获得依赖对象的过程被反转了 也就是说,当需要某个对象时,传统开发模式中需要⾃⼰通过new创建对象,现在不需要再进⾏创 建, 把创建对象的任务交给容器, 程序中只需要依赖注⼊(DI)就可以了. 这个容器称为:IoC容器. Spring是⼀个IoC容器,所以有时Spring也称为Spring容器

控制反转是⼀种思想,在⽣活中也是处处体现. ⽐如⾃动驾驶, 传统驾驶⽅式,⻋辆的控制权由驾驶员行驶来控制,现在交给了驾驶自动化系统来控制,这也是控制反转思想在⽣活中的实现

IoC容器具备优点:

  1. 资源集中管理: IoC容器会帮我们管理⼀些资源(对象等),我们需要使⽤时,只需要从IoC容器中去取 就可以了

  2. 我们在创建实例的时候不需要了解其中的细节,降低了使⽤资源双⽅的依赖程度,也就是耦合度

3.2 DI 介绍

DI就是依赖注入

它是实现 IoC一种设计模式。依赖注入的主要思想是将组件的依赖关系(即它所依赖的对象或资源)通过外部传递给它,而不是让组件自己创建或查找这些依赖

DI 是 IoC 的一种实现方式,它专注于解决对象之间的依赖关系。在 DI 中,一个对象(称为消费者)所依赖的另一个对象(称为服务提供者)不是由消费者自己创建的,而是由 IoC 容器在运行时动态注入到消费者中

4.IoC 使⽤

类注解:@Controller、@Service、@Repository、@Component、@Configuration.
⽅法注解:@Bean

4.1 类注解区别

@Controller:控制层,接收请求,对请求进⾏处理,并进⾏响应.
@Servie:业务逻辑层,处理具体的业务逻辑.
@Repository:数据访问层,也称为持久层.负责数据访问操作
@Configuration:配置层.处理项⽬中的⼀些配置信息

我们发现@Service、@Repository、@Configuration.中都包含@Component说明这些注解本身属于@Component的“子类”。

4.2 ⽅法注解@Bean

1.使⽤外部包⾥的类, 没办法添加类注解

  1. ⼀个类,需要多个对象,⽐如多个数据源

4.2.1⽅法注解要配合类注解使⽤

@Component
public class UserInfoComonent {

    @Bean
    public UserInfo userInfo(){
        return new UserInfo("zhangsan",29);
    }
}
public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
        UserInfo bean = context.getBean(UserInfo.class);
        System.out.println(bean);

    }

4.2.2 定义多个对象

定义多个对象运行会报错,对象不唯一,运行失败

@Component
public class UserInfoComonent {

    @Bean
    public UserInfo userInfo(){
        return new UserInfo("zhangsan",29);
    }
    @Bean
    public UserInfo userInfo1(){
        return new UserInfo("lisi",23);
    }
}

可以看出来, @Bean注解的bean,bean的名称就是它的⽅法名

**@Bean可以针对同⼀个类,定义多个对象,但我们得根据他们的名称来获取bean对象 **

Object userInfo1 = context.getBean("userInfo1");
        System.out.println(userInfo1);

4.2.3 重命名Bean

可以通过设置name属性给Bean对象进⾏重命名操作,name={} 可以省略,也可以重命名多个名字

public class UserInfoComonent {

    @Bean(name = {"cxk","zhangsan"})
    public UserInfo userInfo(){
        return new UserInfo("zhangsan",29);
    }
    @Bean(name = "mjq")
    public UserInfo userInfo1(){
        return new UserInfo("lisi",23);
    }

    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
        
        Object userInfo1 = context.getBean("cxk");
        System.out.println(userInfo1);

    }

5. DI 依赖注入

依赖注⼊,Spring给我们提供了三种⽅式:

1. 属性注⼊

2. 构造⽅法注⼊

3. Setter 注⼊

**5.1 **属性注⼊

属性注⼊是使⽤ @Autowired 实现的,将Service类注⼊到Controller类中

@Service
public class UserService {

    public void say(){
        System.out.println("UserService say....");

    }
}
@Controller
public class UserCotroller {
    @Autowired
    private UserService userService;

    public void say(){
        System.out.println("UserController say....");
        userService.say();
    }
}
UserCotroller bean = context.getBean(UserCotroller.class);
bean.say();

5.2 构造方法注入

构造⽅法注⼊是在类的构造⽅法中实现注⼊,如果类只有⼀个构造⽅法,那么@Autowired 注解可以省略

@Controller
public class UserCotroller {
  

    private UserService userService;

    public UserCotroller(UserService userService) {
        this.userService = userService;
    }

    public void say(){
        System.out.println("UserController say....");
        userService.say();
    }
}

如果存在多种构造方法需要添加上@Autowired 来明确指定到底使⽤哪个构造⽅法

@Controller
public class UserCotroller {
  
    private UserService userService;

    public UserCotroller() {
        System.out.println("无参构造");
    }

    @Autowired
    public UserCotroller(UserService userService) {
        this.userService = userService;
        System.out.println("有参构造");
    }

    public void say(){
        System.out.println("UserController say....");
        userService.say();
    }
}

5.3 Setter 注⼊

Setter 注⼊和属性的Setter⽅法实现类似,只不过在设置set⽅法的时候需要加上@Autowired 注解

@Controller
public class UserCotroller {
  
   private UserService userService;

    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    public void say(){
        System.out.println("UserController say....");
        userService.say();
    }
}

5.4 三种注⼊优缺点

属性注⼊

优点:简洁,使⽤⽅便

缺点:只能⽤于IoC容器,如果是⾮IoC容器不可⽤,并且只有在使⽤的时候才会出现NPE(空指 针异常)

不能注⼊⼀个Final修饰的属性

构造函数注⼊

优点:

可以注⼊final修饰的属性

注⼊的对象不会被修改

依赖对象在使⽤前⼀定会被完全初始化,因为依赖是在类的构造⽅法中执⾏的,⽽构造⽅法 是在类加载阶段就会执⾏的⽅法.

通⽤性好,构造⽅法是JDK⽀持的,所以更换任何框架,他都是适⽤的

缺点:

注⼊多个对象时,代码会⽐较繁琐

Setter注⼊

优点: ⽅便在类实例之后,重新对该对象进⾏配置或者注⼊

缺点:

不能注⼊⼀个Final修饰的属性

注⼊对象可能会被改变,因为setter⽅法可能会被多次调⽤,就有被修改的风险

5.5 @Autowired存在问题

@Component
public class UserInfoComonent {

    @Bean
    public UserInfo userInfo(){
        return new UserInfo("zhangsan",29);
    }
    @Bean
    public UserInfo userInfo1(){
        return new UserInfo("lisi",23);
    }
}

当同⼀类型存在多个对象时,按照名称来匹配,该类型只有一个对象时,直接注入;有多个对象时,按照名称注入

@Primary

当存在多个相同类型的Bean注⼊时,加上@Primary注解,确定哪个是默认的实现

@Component
public class UserInfoComonent {

    @Bean
    public UserInfo userInfo(){
        return new UserInfo("zhangsan",29);
    }
   @Primary
    @Bean
    public UserInfo userInfo1(){
        return new UserInfo("lisi",23);
    }

    @Bean
    public UserInfo userInfo2() { return new UserInfo("cxk",34);}
}

@Qualifier

使⽤@Qualifier注解:指定当前要注⼊的bean对象。在@Qualifier的value属性中,指定注⼊的bean 的名称

@Qualifier注解不能单独使⽤,必须配合@Autowired使⽤

@Component
public class UserComponent {

   @Qualifier("userInfo2")
    @Autowired
    private UserInfo ui;

    public void say(){
        System.out.println("UserComponent say.... ");
        System.out.println(ui);
    }
}
@Component
public class UserInfoComonent {

    @Bean
    public UserInfo userInfo(){
        return new UserInfo("zhangsan",29);
    }

    @Bean
    public UserInfo userInfo1(){
        return new UserInfo("lisi",23);
    }

    @Bean
    public UserInfo userInfo2() { return new UserInfo("cxk",34);}
}

@Component
public class UserInfoComonent {

    @Bean
    public UserInfo userInfo(){
        return new UserInfo("zhangsan",29);
    }
    
    @Bean
    public UserInfo userInfo1(){
        return new UserInfo("lisi",23);
    }
    @Bean
    public String name(){
        return "cxk";
    }
    @Bean
    public String name1(){
        return "mjq";
    }
    @Bean
    public UserInfo userInfo2(@Qualifier("name") String name3) { return new UserInfo(name3,34);}
}

@Resource

@Resource注解:是按照bean的名称进⾏注⼊。通过name属性指定要注⼊的bean的名称

@Component
public class UserInfoComonent {

    @Bean
    public UserInfo userInfo(){
        return new UserInfo("zhangsan",29);
    }

    @Bean
    public UserInfo userInfo1(){
        return new UserInfo("lisi",23);
    }
}
@Component
public class UserComponent {

    @Resource(name = "userInfo1")
    private UserInfo ui;

    public void say(){
        System.out.println("UserComponent say.... ");
        System.out.println(ui);
    }
}

@Resource 和@Autowired区别

@Autowired是spring框架提供的注解,⽽@Resource是JDK提供的注解

@Autowired默认是按照类型注⼊,⽽@Resource是按照名称注⼊.相⽐于@Autowired 来说, @Resource ⽀持更多的参数设置,例如name设置,根据名称获取Bean.

@Autowired根据类型匹配,@Resource根据名称匹配,优先按照类型匹配,如果同类型右多个对象,再按照名称匹配,它两基本原则都是根据类型匹配,但是@Autowired不能指定名称

6.Spring, Spring Boot和SpringMVC的关系以及区别

Spring: 简单来说,Spring是⼀个开发应⽤框架,什么样的框架呢,它轻量级、⼀ 站式、模块化,其⽬的是⽤于简化企业级应⽤程序开发,Spring的主要功能:管理对象,以及对象之间的依赖关系,⾯向切⾯编程,数据库事务管理,数据访 问,web框架⽀持等,但是Spring具备⾼度可开放性,并不强制依赖Spring,开发者可以⾃由选择Spring的部分或者全 部,Spring可以⽆缝继承第三⽅框架,⽐如MyBaties

Spring MVC:SpringMVC是Spring的⼀个⼦框架,Spring诞⽣之后,⼤家觉得很好⽤,于是按照MVC 模式设计了⼀个MVC框架(⼀些⽤Spring解耦的组件),主要⽤于开发WEB应⽤和⽹络接⼝,所以, Spring MVC是⼀个Web框架.Spring MVC基于Spring进⾏开发的,天⽣的与Spring框架集成.可以让我们更简洁的进⾏Web层 开发,⽀持灵活的URL到⻚⾯控制器的映射,提供了强⼤的约定⼤于配置的契约式编程⽀持,⾮常 容易与其他视图框架集成

Spring Boot: Spring Boot是对Spring的⼀个封装,为了简化Spring应⽤的开发⽽出现的,使⽤SpringBoot可以更加快速的搭建框架,降级开发成本,让开发 ⼈员更加专注于Spring应⽤的开发,⽽⽆需过多关注XML的配置和⼀些底层的实现

SpringMVC和SpringBoot都属于Spring,SpringMVC是基于Spring的⼀个 MVC框架,⽽SpringBoot是基于Spring的⼀套快速开发整合包

标签: spring java 后端

本文转载自: https://blog.csdn.net/jj666mhhh/article/details/143266924
版权归原作者 码农派大星. 所有, 如有侵权,请联系我们删除。

“Spring IoC & DI”的评论:

还没有评论