欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 锐评 > Spring两大核心思想 IoC和AoP

Spring两大核心思想 IoC和AoP

2024/11/30 14:42:02 来源:https://blog.csdn.net/leyhe/article/details/140104057  浏览:    关键词: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中获取对象@Autowiredprivate 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注解实现从容器中取对象

@Autowiredprivate 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 {@Beanpublic 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 {@Beanpublic 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 {@Autowiredprivate 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;@Autowiredpublic 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。 

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com