Spring两大核心思想 IoC和AoP

目录

 一、什么是IoC

1、定义 🎊

2、IoC思想 🎊

3、优势 🎊

4、对象的管理 🎊

存对象:@Component

取对象:@AutoWired 

二、什么是DI 

1、定义 🎊

2、IoC和DI的关系🎊

可以说DI是IoC的一种实现

三、IoC&DI的使用 

1、实现实例:用@Component注解实现存 🎊

2、 使用@AutoWired注解实现从容器中取对象🎊

四、IoC详解 

1、Bean的存储(类注解)🎊

1) @Controller(控制器存储)(控制层,接受请求,对请求进行处理,并进行响应)

从容器中获取对象:Spring上下文

2)@Service(服务存储)(业务逻辑层,处理具体的业务逻辑) 

​编辑 

3)Repository(仓库存储)(数据访问层,也称为持久层,负责数据的访问操作)

4)Component(组件存储)

5)Configuration(配置存储)(配置层,处理项目中的一些配置信息)

 2、Bean的命名🎊

 3、获取bean对象的方法(是父类(BeanFactory)提供的功能)🎊

常见的面试题: ApplicationContext VS BeanFactory

 4、方法注解(@Bean)🎊

1、一个对象的情况 

2、多个对象的情况 

 3、重命名Bean

5、扫描路径🎊

五、DI详解 

1、依赖注入的三种方法 🎊

1)属性注入(Field Injection)Autowired

2) 构造方法注入(Constructor Injection)

3)Setter注入(Setter Jniection)

2、三种注入的优缺点分析 🎊

3、@Autowired存在问题(当同一类型存在多个bean时)🎊


让我们先回顾一下什么是Spring:Spring是一个开源框架,他让我们的开发更简单,简单来说,Spring是包含了众多工具的IoC容器。

那么问题来了,什么是容器?什么是IoC容器?

容器是用来容纳某种物品的(基本)装置

  • List/Map ->数据存储器
  • Tomact -> Web容器

 一、什么是IoC

1、定义 

  Inversion of Control(控制反转),也就是说“Spring”是一个控制反转容器。

当需要某个对象时,传统的开发模式中需要new来创建对象,现在不需要再进行创建了,把创建对象的任务交给容器,由Spring来负责对象的创建和销毁,程序只需要依赖注入(Dependency Injection,DI) 就可以了。

这个容器称为:IoC容器。Spring是一个IoC容器,有时候Spring也称为Spring容器。(容器里面装的是对象,Spring管理的对象称之为bean

2、IoC思想 

     像我们之前写代码,在类上面添加@RestController和@Controller注解,就是把这个对象交给Spring来管理,Spring框架启动时就会加载该类,把对象交给Spring管理,就是IoC思想。 

3、优势 

资源不由使用资源的双方管理,而由不使用资源的第三方管理。

  1. 资源集中管理:IoC容器会帮我们管理一些资源(对象等),需要时,只需要从IoC容器中去取就可以了
  2. 我们在创建实例的时候不需要了解其中的细节,降低了使用资源双方的依赖程度,也就是耦合度。 

4、对象的管理 

  1. 存对象:@Component

  2. 取对象:@AutoWired 

二、什么是DI 

1、定义 

 Dependency Injection,DI(依赖注入),容器在运行期间,动态的为应用程序提供运行时所依赖的资源,称之为依赖注入。

2、IoC和DI的关系

可以说DI是IoC的一种实现

可以看出,依赖注入和控制反转是从不同的角度的描述同一件事情,就是指通过引入IoC容器,利用依赖关系注入的方式,实现对象之间的解耦。 

三、IoC&DI的使用 

1、实现实例:用@Component注解实现存 

@Component
public class BookDao {
    public List<BookInfo> mockBookData() {
        List<BookInfo> bookInfos = new ArrayList<>();
        for(int i = 1;i < 15; i++) {
            BookInfo bookInfo = new BookInfo();
            bookInfo.setId(i);
            bookInfo.setBookName("图书" + i);
            bookInfo.setAuthor("作者" + i);
            bookInfo.setCount(i*15 + 3);
            bookInfo.setPrice(new BigDecimal(new Random().nextInt(100)));
            bookInfo.setPublish("出版社" + i);
            bookInfo.setStatus(i%5==0?2:1);
            bookInfos.add(bookInfo);
        }

        return bookInfos;
    }
}
@Component
public class BookService {
    /**
     * 根据数据层返回的结果对数据进行处理
     * @return
     */
    //从Spring中获取对象
    @Autowired
    private BookDao bookDao;
    public List<BookInfo> bookInfoList(){
        List<BookInfo> bookInfos = bookDao.mockBookData();
        for(BookInfo bookInfo: bookInfos) {
            if(bookInfo.getStatus()==1) {
                bookInfo.setStateCN("可借阅");
            }else if(bookInfo.getStatus()==2){
                bookInfo.setStateCN("不可借阅");
            }
        }
        return bookInfos;
    }
}

2、 使用@AutoWired注解实现从容器中取对象

@Autowired
    private BookDao bookDao;

四、IoC详解 

1、Bean的存储(类注解)

通过前面 学习,我们知道了把某个对象交给IoC容器进行管理,需要在类上添加一个注解,而Spring也提供了更丰富的注解。

类注解:@Controller、@Service(服务存储)、@Component(组件存储)、@Repository(仓库存储)、@Configuration(配置存储)

方法注解:@Bean

设置这么多类注解目的是为了让程序员看到类注解之后,就直接了当的了解当前类的用途

1) @Controller(控制器存储)(控制层,接受请求,对请求进行处理,并进行响应)

看下面例子:使用 @Controller存储bean的代码

package com.example.example1.controller;

import org.springframework.stereotype.Controller;

@Controller
public class UserController {
    public void sayHi() {
        System.out.println("祝你好运,小李");
    }
}

如何观察这个对象已经存在在Spring容器中了呢?

@SpringBootApplication
public class Example1Application {

    public static void main(String[] args) {
        //获取Spring上下文对象
       ApplicationContext context = SpringApplication.run(Example1Application.class, args);
       //从Spring上下文中获取对象
        UserController userController = context.getBean(UserController.class);
        //使用对象
        userController.sayHi();
    }

}

运行程序: 

但如果删除@Controller,观察运行结果: 

 

从容器中获取对象:Spring上下文

 上下文:就是指当前的运行环境,也可以看做是一个容器,容器里面存了很多内容,这些内容是当前的运行的环境。

ApplicationContext context = SpringApplication.run(Example1Application.class, args);

2)@Service(服务存储)(业务逻辑层,处理具体的业务逻辑) 

package com.example.example1.service;

import org.springframework.stereotype.Service;

@Service
public class UserService {
    public void sayHi() {
        System.out.println("祝你幸福快乐,小李");
    }
}
  //获取Spring上下文对象
       ApplicationContext context = SpringApplication.run(Example1Application.class, args);       
       UserService userService = context.getBean(UserService.class);
       userService.sayHi();

 

3)Repository(仓库存储)(数据访问层,也称为持久层,负责数据的访问操作)

4)Component(组件存储)

5)Configuration(配置存储)(配置层,处理项目中的一些配置信息)

 2、Bean的命名

程序开发人员不需要为bean指定名称 ,如果没有显示的提供名称,Spring容器将为该Bean生成唯一的名称

来看spring官方文档中说明:Bean Overview :: Spring Framework

 

 3、获取bean对象的方法(是父类(BeanFactory)提供的功能)

package com.example.example1;

import com.example.example1.controller.UserController;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

@SpringBootApplication
public class Example1Application {

    public static void main(String[] args) {
        //获取Spring上下文对象
       ApplicationContext context = SpringApplication.run(Example1Application.class, args);
       //从Spring上下文中获取对象,根据类型
        UserController userController1 = context.getBean(UserController.class);
        //根据名称
        UserController userController2 = (UserController) context.getBean("userController");
        //根据类型+名称
        UserController userController3 = context.getBean("userController", UserController.class);
 System.out.println(userController1);
        System.out.println(userController2);
        System.out.println(userController3);
    }

}

 

常见的面试题: ApplicationContext VS BeanFactory

  • 继承关系和功能方面来说:Spring容器有两个顶级的接口:BeanFactory和ApplicationContext。其中前者提供了基础的访问容器的能力,后者属于 BeanFactory的子类,他除了继承了BeanFactory的所有功能之外,它还具有独特的特性,还添加了对国际化支持、资源访问支持、以及事件传播等方面的支持。
  • 性能方面:后者是一次性加载并初始化所有的Bean对象,而前者是需要哪个才去加载哪个,因此更加轻量(空间换时间)

 4、方法注解(@Bean)

考虑以下场景:1、使用外部包里面的类,没办法添加类注解

2、一个类,需要多个对象,比如多个数据源 

1、一个对象的情况 

 示例:

package com.example.example1.bean;

import lombok.Data;

import javax.lang.model.element.NestingKind;
@Data
public class User {
    private String name;
    private int age;
}
package com.example.example1.bean;
import org.springframework.context.annotation.Bean;

public class BeanConfig {
    @Bean
    public User user(){
        User user = new User();
        user.setName("zhangsan");
        user.setAge(12);
        return user;
    }
}

 

User user = context.getBean(User.class);
        System.out.println(user);

 让我查看运行结果,结果报错了

什么原因造成的呢?

在Spring框架的设计中,方法注解@Bean要配合类注解才能将对象正常的存储到Spring容器中

对上述代码进行修改

package com.example.example1.bean;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@Component
public class BeanConfig {
    @Bean
    public User user(){
        User user = new User();
        user.setName("zhangsan");
        user.setAge(12);
        return user;
    }
}

再次运行:

2、多个对象的情况 

 

从运行结果可以看出:@Bean注解的Bean,bean名称就是它的方法名

所以我们根据名称来获取bean对象 

 3、重命名Bean

    @Bean(name = {"u3","user3"})
    public User user3(){
        User user = new User();
        user.setName("wangwu");
        user.setAge(14);
        return user;
    }
 User u3 = (User) context.getBean("u3");
        System.out.println(u3);

 

5、扫描路径

问题:使用前面学过的四个注解声明Bean,一定会生效吗?

答案是不一定的,bean要想生效,还需要被Spring扫描 

  1. 通过@CompontentScan 

@ComponentScan({"com.example.example1"}) 

五、DI详解 

 依赖注入是一个过程,是指IoC在创建Bean时,去提供运行时所依赖的资源,而资源指的就是对象,之前,我们使用@Autowired这个注解,完成了依赖注入的操作

简单来说,就是把对象取出来放到某个类属性中

1、依赖注入的三种方法 

1)属性注入(Field Injection)Autowired

@Controller
public class UserController {
    @Autowired
    private UserService userService;
    public void sayHi() {
        System.out.println("祝你好运,小李");
        userService.sayHi();
    }
}

 

@Service
public class UserService {
    public void sayHi() {
        System.out.println("祝你幸福快乐,小李");
    }
}
      UserController userController = (UserController) context.getBean("userController");
        userController.sayHi();

 

2) 构造方法注入(Constructor Injection)

 

package com.example.example1.controller;

import com.example.example1.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class UserController2 {
    private UserService userService;
    @Autowired
    public UserController2 (UserService userService) {
        this.userService = userService;
    }
    public void sayHi() {
        System.out.println("祝你好运,小李");
        userService.sayHi();
    }
}

注意:如果类只有一个构造方法,那注解可以省略,反之则不行 

3)Setter注入(Setter Jniection)

2、三种注入的优缺点分析 

• 属性注⼊ ◦:

优点: 简洁,使⽤⽅便;

◦ 缺点: ▪ 只能⽤于 IoC 容器,如果是⾮ IoC 容器不可⽤,并且只有在使⽤的时候才会出现 NPE(空指 针异常) ▪ 不能注⼊⼀个Final修饰的属性

• 构造函数注⼊(Spring 4.X推荐)

◦ 优点: ▪ 可以注⼊final修饰的属性 ▪ 注⼊的对象不会被修改 ▪ 依赖对象在使⽤前⼀定会被完全初始化,因为依赖是在类的构造⽅法中执⾏的,⽽构造⽅法 是在类加载阶段就会执⾏的⽅法. ▪ 通⽤性好, 构造⽅法是JDK⽀持的, 所以更换任何框架,他都是适⽤的

◦ 缺点: ▪ 注⼊多个对象时, 代码会⽐较繁琐

• Setter注⼊(Spring 3.X推荐)

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

◦ 缺点: ▪ 不能注⼊⼀个Final修饰的属性 ▪ 注⼊对象可能会被改变, 因为setter⽅法可能会被多次调⽤, 就有被修改的⻛险. 

3、@Autowired存在问题(当同一类型存在多个bean时)

@Autowird 与 @Resource的区别

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

• @Autowired 默认是按照类型注⼊,⽽@Resource是按照名称注⼊.

相⽐于 @Autowired 来说, @Resource ⽀持更多的参数设置,例如 name 设置,根据名称获取 Bean。 

  • 24
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值