小工具知识网

当前位置: 首页 > 行业知识 > 【Java EE】 IoC详解(Bean的存储)

行业知识

【Java EE】 IoC详解(Bean的存储)

2026-11-07 07:07:09 来源:互联网转载

文章目录

  • @Controller(控制器存储)
    • 如何从Spring容器中获取对象(ApplicationContext)
    • 获取bean对象的其他方式(BeanFactory)
    • Bean 命名约定
    • Bean面试题
    • @Service、@Repository、@Component、@Configuration.
    • 为什么要这么多类注解?
    • 类注解之间的关系
    • 方法注解 @Bean
      • 方法注解要配合类注解使用
      • 定义多个对象
      • 重命名 Bean
      • 扫描路径

        既然 Spring 是⼀个 IoC(控制反转)容器,作为容器, 那么它就具备两个最基础的功能:

        • 存
        • 取

          Spring 容器 管理的主要是对象, 这些对象, 我们称之为"Bean". 我们把这些对象交由Spring管理, 由

          Spring来负责对象的创建和销毁. 我们程序只需要告诉Spring, 哪些需要存, 以及如何从Spring中取出

          对象

          前⾯我们提到IoC控制反转,就是将对象的控制权交给Spring的IOC容器,由IOC容器创建及管理对

          象。

          也就是bean的存储.

          把某个对象交给IOC容器管理,Spring框架为了更好的服务web应⽤程序, 提供了更丰富的注解.

          共有两类注解类型可以实现bean的存储:

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

          @Controller(控制器存储)

          使⽤ @Controller 存储 bean 的代码如下所⽰:

          @Controller // 将对象存储到 Spring 中public class UserController { public void sayHi(){ System.out.println("hi,UserController..."); }}

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

          如何从Spring容器中获取对象(ApplicationContext)

          接下来我们学习如何从Spring容器中获取对象

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

          ApplicationContext 翻译过来就是: Spring 上下⽂

          因为对象都交给 Spring 管理了,所以获取对象要从 Spring 中获取,那么就得先得到 Spring 的上下

          ⽂

          关于上下⽂的概念

          上学时, 阅读理解经常会这样问: 根据上下⽂, 说⼀下你对XX的理解

          在计算机领域, 上下⽂这个概念, 咱们最早是在学习线程时了解到过, ⽐如我们应⽤进⾏线程切换的时

          候,切换前都会把线程的状态信息暂时储存起来,这⾥的上下⽂就包括了当前线程的信息,等下次该

          线程⼜得到CPU时间的时候, 从上下⽂中拿到线程上次运⾏的信息

          这个上下⽂, 就是指当前的运⾏环境, 也可以看作是⼀个容器, 容器⾥存了很多内容, 这些内容是当前

          运⾏的环境

          观察运⾏结果, 发现成功从Spring中获取到Controller对象, 并执⾏Controller的sayHi⽅法

          如果把@Controller删掉, 再观察运⾏结果

          报错信息显⽰: 找不到类型是: com.example.demo.controller.UserController的bean

          获取bean对象的其他方式(BeanFactory)

          上述代码是根据类型来查找对象, 如果Spring容器中, 同⼀个类型存在多个bean的话, 怎么来获取呢?

          ApplicationContext 也提供了其他获取bean的方式, ApplicationContext 获取bean对象的功能, 是父类BeanFactory提供的功能.

          public interface BeanFactory {  //以上省略...  // 1. 根据bean名称获取bean Object getBean(String var1) throws BeansException; // 2. 根据bean名称和类型获取bean  T getBean(String var1, Class var2) throws BeansException; // 3. 按bean名称和构造函数参数动态创建bean,只适⽤于具有原型(prototype)作⽤域的bean Object getBean(String var1, Object... var2) throws BeansException; // 4. 根据类型获取bean  T getBean(Class var1) throws BeansException; // 5. 按bean类型和构造函数参数动态创建bean, 只适⽤于具有原型(prototype)作⽤域的bean  T getBean(Class var1, Object... var2) throws BeansException;  //以下省略...}

          常⽤的是上述1,2,4种, 这三种⽅式,获取到的bean是⼀样的

          其中1,2种都涉及到根据名称来获取对象. bean的名称是什么呢?

          Spring bean是Spring框架在运⾏时管理的对象, Spring会给管理的对象起⼀个名字.

          ⽐如学校管理学⽣, 会给每个学⽣分配⼀个学号, 根据学号, 就可以找到对应的学⽣.

          Spring也是如此, 给每个对象起⼀个名字, 根据Bean的名称(BeanId)就可以获取到对应的对象.

          Bean 命名约定

          程序开发⼈员不需要为bean指定名称(BeanId), 如果没有显式的提供名称(BeanId),Spring容器将为该bean⽣成唯⼀的名称.

          命名约定使⽤Java标准约定作为实例字段名. 也就是说,bean名称以⼩写字⺟开头,然后使⽤驼峰式⼤⼩写.

          ⽐如

          类名: UserController, Bean的名称为: userController

          类名: AccountManager, Bean的名称为: accountManager

          类名: AccountService, Bean的名称为: accountService

          也有⼀些特殊情况, 当有多个字符并且第⼀个和第⼆个字符都是⼤写时, 将保留原始的⼤⼩写

          ⽐如

          类名: UController, Bean的名称为: UController

          类名: AManager, Bean的名称为: AManager

          根据这个命名规则, 我们来获取Bean

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

          运⾏结果:

          地址⼀样, 说明对象是⼀个

          Bean面试题

          获取bean对象, 是⽗类BeanFactory提供的功能

          ApplicationContext VS BeanFactory(常⻅⾯试题)

          • 继承关系和功能⽅⾯来说:Spring 容器有两个顶级的接⼝:BeanFactory 和

            ApplicationContext。其中 BeanFactory 提供了基础的访问容器的能⼒,⽽

            ApplicationContext 属于 BeanFactory 的⼦类,它除了继承了 BeanFactory 的所有功能之外,

            它还拥有独特的特性,还添加了对国际化⽀持、资源访问⽀持、以及事件传播等⽅⾯的⽀持.

          • 从性能⽅⾯来说:ApplicationContext 是⼀次性加载并初始化所有的 Bean 对象,⽽

            BeanFactory 是需要那个才去加载那个,因此更加轻量. (空间换时间)

            @Service、@Repository、@Component、@Configuration.

            使用与Controller一致,这里不做演示

            为什么要这么多类注解?

            这个也是和咱们前⾯讲的应⽤分层是呼应的. 让程序员看到类注解之后,就能直接了解当前类的⽤途.

            • @Controller:控制层, 接收请求, 对请求进⾏处理, 并进⾏响应.

            • @Servie:业务逻辑层, 处理具体的业务逻辑.

            • @Repository:数据访问层,也称为持久层. 负责数据访问操作

            • @Configuration:配置层. 处理项⽬中的⼀些配置信息.

            程序的应⽤分层,调⽤流程如下:

            类注解之间的关系

            查看 @Controller / @Service / @Repository / @Configuration 等注解的源码发

            现:

            其实这些注解⾥⾯都有⼀个注解 @Component ,说明它们本⾝就是属于 @Component 的"⼦类".

            @Component 是⼀个元注解,也就是说可以注解其他类注解,如 @Controller , @Service ,

            @Repository 等. 这些注解被称为 @Component 的衍⽣注解.

            @Controller , @Service 和 @Repository ⽤于更具体的⽤例(分别在控制层, 业务逻辑层, 持

            久化层), 在开发过程中, 如果你要在业务逻辑层使⽤ @Component 或@Service,显然@Service是更

            好的选择

            方法注解 @Bean

            类注解是添加到某个类上的, 但是存在两个问题:

            1. 使⽤外部包⾥的类, 没办法添加类注解
            2. ⼀个类, 需要多个对象, ⽐如多个数据源

            这种场景, 我们就需要使⽤⽅法注解 @Bean

            我们先来看看⽅法注解如何使⽤:

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

            然⽽,当我们写完以上代码,尝试获取 bean 对象中的 user 时却发现,根本获取不到:

            @SpringBootApplicationpublic class SpringIocDemoApplication { public static void main(String[] args) { //获取Spring上下⽂对象 ApplicationContext context = SpringApplication.run(SpringIocDemoApplication.class, args); //从Spring上下⽂中获取对象 User user = context.getBean(User.class); //使⽤对象 System.out.println(user); }}

            方法注解要配合类注解使用

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

            如下代码所⽰:

            定义多个对象

            对于同⼀个类, 如何定义多个对象呢?

            ⽐如多数据源的场景, 类是同⼀个, 但是配置不同, 指向不同的数据源

            @Componentpublic class BeanConfig { @Bean public User user1(){ User user = new User(); user.setName("zhangsan"); user.setAge(18); return user; } @Bean public User user2(){ User user = new User(); user.setName("lisi"); user.setAge(19); return user; }}

            定义了多个对象的话, 我们根据类型获取对象, 获取的是哪个对象呢?

            @Bean 注解的bean, bean的名称就是它的⽅法名

            重命名 Bean

            可以通过设置 name 属性给 Bean 对象进⾏重命名操作,如下代码所⽰

            @Bean(name = {"u1","user1"})public User user1(){ User user = new User(); user.setName("zhangsan"); user.setAge(18); return user;}

            或者是

            @Bean("u1")public User user1(){ User user = new User(); user.setName("zhangsan"); user.setAge(18); return user;}

            扫描路径

            bean想要⽣效,还需要被Spring扫描)

            使⽤五⼤注解声明的bean,要想⽣效, 还需要配置扫描路径, 让Spring扫描到这些注解

            也就是通过 @ComponentScan 来配置扫描路径

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

            那为什么前⾯没有配置 @ComponentScan注解也可以呢?

            @ComponentScan 注解虽然没有显式配置,但是实际上已经包含在了启动类声明注解

            @SpringBootApplication 中了

            默认扫描的范围是SpringBoot启动类所在包及其⼦包

            推荐做法:

            把启动类放在我们希望扫描的包的路径下, 这样我们定义的bean就都可以被扫描到

上一篇:ure怎么读音发音英语?

下一篇:怎么领取方舟服务器任务?