Bean管理

复习IOC容器中Bean的其他使用细节,主要学习以下三个方面:

  1.如何从IOC容器中手动获取bean对象

  2.bean的作用域配置

  3.管理第三方的bean对象

1.获取bean

默认情况下,springboot项目在启动的时候会自动创建IOC容器(也称之为Spring容器),并且在启动的过程中会自动的将bean对象都创建好,存放在IOC容器当中。应用程序在运行时需要依赖什么bean对象,就直接进行依赖注入就可以了。

在spring容器当中提供了一些方法,可以主动从IOC容器当中获取到bean对象,有3种常用方式:

  1.根据name获取bean

  2.根据类型获取bean

  3.根据name获取bean(带类型转换)

注意:要想从IOC容器中来获取bean对象,需要先拿到IOC容器对象,怎么才能拿到IOC容器对象呢????

测试代码:

@SpringBootTest
class SpringbootWebConfig2ApplicationTests {

    @Autowired
    private ApplicationContext applicationContext; //IOC容器对象

    //获取bean对象
    @Test
    public void testGetBean(){
        //根据bean的名称获取
        DeptController bean1 = (DeptController) applicationContext.getBean("deptController");
        System.out.println(bean1);

        //根据bean的类型获取
        DeptController bean2 = applicationContext.getBean(DeptController.class);
        System.out.println(bean2);

        //根据bean的名称 及 类型获取
        DeptController bean3 = applicationContext.getBean("deptController", DeptController.class);
        System.out.println(bean3);
    }
}

 程序运行后控制台日志:

题:输出的bean对象地址值是一样的,说明IOC容器当中的bean对象有几个?

答案:只有一个。 (默认情况下,IOC中的bean对象是单例)那么能不能将bean对象设置为非单例的(每次获取的bean都是一个新对象)?

注意事项:

  • 上述所说的 【Spring项目启动时,会把其中的bean都创建好】还会受到作用域及延迟初始化影响,这里主要针对于默认的单例非延迟加载的bean而言。

2.Bean作用域

在Spring中支持五种作用域,后三种在web环境才生效:

作用域说明
singleton容器内同名称的bean只有一个实例(单例)(默认)
prototype每次使用该bean时会创建新的实例(非单例)
request每个请求范围内会创建新的实例(web环境中,了解)
session每个会话范围内会创建新的实例(web环境中,了解)
application每个应用范围内会创建新的实例(web环境中,了解)

知道了bean的5种作用域了,我们要怎么去设置一个bean的作用域呢?

  • 可以借助Spring中的@Scope注解来进行配置作用域

 测试一:

//默认bean的作用域为:singleton (单例)
@Lazy //延迟加载(第一次使用bean对象时,才会创建bean对象并交给ioc容器管理)
@RestController
@RequestMapping("/depts")
public class DeptController {

    @Autowired
    private DeptService deptService;

    public DeptController(){
        System.out.println("DeptController constructor ....");
    }

    //省略其他代码...
}
@SpringBootTest
class SpringbootWebConfig2ApplicationTests {

    @Autowired
    private ApplicationContext applicationContext; //IOC容器对象

    //bean的作用域
    @Test
    public void testScope(){
        for (int i = 0; i < 10; i++) {
            DeptController deptController = applicationContext.getBean(DeptController.class);
            System.out.println(deptController);
        }
    }
}

 注意事项:

  • IOC容器中的bean默认使用的作用域:singleton (单例)

  • 默认singleton的bean,在容器启动时被创建,可以使用@Lazy注解来延迟初始化(延迟到第一次使用时)

测试二:

@Scope("prototype") //bean作用域为非单例
@Lazy //延迟加载
@RestController
@RequestMapping("/depts")
public class DeptController {

    @Autowired
    private DeptService deptService;

    public DeptController(){
        System.out.println("DeptController constructor ....");
    }

    //省略其他代码...
}

注意事项:

  • prototype的bean,每一次使用该bean的时候都会创建一个新的实例

  • 实际开发当中,绝大部分的Bean是单例的,也就是说绝大部分Bean不需要配置scope属性

 3.第三方Bean

学习完bean的获取、bean的作用域之后,接下来我们再来学习第三方bean的配置。

之前我们所配置的bean,像controller、service,dao三层体系下编写的类,这些类都是我们在项目当中自己定义的类(自定义类)。当我们要声明这些bean,也非常简单,我们只需要在类上加上@Component以及它的这三个衍生注解(@Controller、@Service、@Repository),就可以来声明这个bean对象了。 但是在我们项目开发当中,还有一种情况就是这个类它不是我们自己编写的,而是我们引入的第三方依赖当中提供的。

例如:在pom.xml文件中,引入dom4j:

<!--Dom4j-->
<dependency>
    <groupId>org.dom4j</groupId>
    <artifactId>dom4j</artifactId>
    <version>2.1.3</version>
</dependency>

dom4j就是第三方组织提供的。 dom4j中的SAXReader类就是第三方编写的。

当我们需要使用到SAXReader对象时,直接进行依赖注入是不是就可以了呢?

  • 按照我们之前的做法,需要在SAXReader类上添加一个注解@Component(将当前类交给IOC容器管理)

  结论:第三方提供的类是只读的。无法在第三方类上添加@Component注解或衍生注解。

 那如何使用并定义第三方的Bean呢?

如果要管理的bean对象来自于第三方(不是自定义的),是无法用@Component 及衍生注解声明bean的,就需要用到@Bean注解。

解决方案1:在启动类上添加@Bean标识的方法

@SpringBootApplication
public class SpringbootWebConfig2Application {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootWebConfig2Application.class, args);
    }

    //声明第三方bean
    @Bean //将当前方法的返回值对象交给IOC容器管理, 成为IOC容器bean
    public SAXReader saxReader(){
        return new SAXReader();
    }
}

xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<emp>
    <name>Tom</name>
    <age>18</age>
</emp>

测试类:

@SpringBootTest
class SpringbootWebConfig2ApplicationTests {

    @Autowired
    private SAXReader saxReader;

    //第三方bean的管理
    @Test
    public void testThirdBean() throws Exception {
        Document document = saxReader.read(this.getClass().getClassLoader().getResource("1.xml"));
        Element rootElement = document.getRootElement();
        String name = rootElement.element("name").getText();
        String age = rootElement.element("age").getText();

        System.out.println(name + " : " + age);
    }

    //省略其他代码...
}
Tom : 18

说明:以上在启动类中声明第三方Bean的作法,不建议使用(项目中要保证启动类的纯粹性)

 解决方案2:在配置类中定义@Bean标识的方法

  • 如果需要定义第三方Bean时, 通常会单独定义一个配置类

@Configuration //配置类  (在配置类当中对第三方bean进行集中的配置管理)
public class CommonConfig {

    //声明第三方bean
    @Bean //将当前方法的返回值对象交给IOC容器管理, 成为IOC容器bean
          //通过@Bean注解的name/value属性指定bean名称, 如果未指定, 默认是方法名
    public SAXReader reader(DeptService deptService){
        System.out.println(deptService);
        return new SAXReader();
    }

}

 如果第三方Bean需要依赖其它bean对象,直接在bean定义方法中设置形参即可,容器会根据类型自动装配

@Test
    public void testGetBean2(){
        Object saxReader = applicationContext.getBean("reader");
        System.out.println(saxReader);
    }

4.Bean的生命周期

在Spring框架中,Bean的生命周期包括以下几个阶段:

(1)实例化(Instantiation):Spring 容器根据配置信息或注解创建Bean 的实例对象,这是 Bean 生命周期的起始点,通常通过反射调用 Bean 的构造方法来完成。

(2)属性赋值(Population):在实例化后,Spring会通过依赖注入(Dependency Injection)或者属性赋值的方式,将Bean的属性值设置好。这可以通过setter方法注入或者字段注入来实现。

(3)初始化(Initialization):

  • 实现 InitializingBean 接口:如果 Bean 实现了 InitializingBean 接口,Spring 容器会调用其 afterPropertiesSet() 方法,该方法可用于执行一些初始化操作。
  • 自定义初始化方法:通过配置文件或者注解指定自定义的初始化方法,Spring 容器会在合适的时机调用该方法。

(或者在配置文件中通过init-method属性指定。)

(4)使用(In Use):在初始化完成后,Bean进入可用状态,可以被其他对象引用和使用。

(5)销毁(Destruction):当Bean不再被需要时,Spring会调用Bean的销毁方法进行资源释放和清理工作。这个方法可以通过实现DisposableBean接口的destroy()方法,或者在配置文件中通过destroy-method属性指定。

        Bean的销毁阶段只有在容器关闭时才会触发,或者在使用单例作用域的Bean时,当Bean不再被引用时被垃圾回收器回收。以上是Spring框架中Bean的典型生命周期阶段,每个阶段都提供了相应的扩展点,可以在不同阶段进行自定义操作。

面试题:

1.请解释Spring中的延迟初始化是什么,如何配置延迟初始化??

在Spring中,延迟初始化(Lazy Initialization)是指在容器启动时不立即创建所有的Bean实例,而是在第一次使用该Bean时才进行创建。这可以有效地减少启动时间和资源消耗,特别是对于那些初始化耗时较长或者很少被使用的Bean。

要配置延迟初始化,可以使用两种方式:

使用注解配置:(1)在类级别上使用@Lazy注解,表示该类的Bean实例需要延迟初始化。例如:@Lazy。(2)在XML配置文件中,使用lazy-init="true"属性来配置延迟初始化。例如:

<bean id="myBean" class="com.example.MyBean" lazy-init="true" />

2.Spring Bean的生命周期中,哪些方法可以进行自定义操作??

(1)初始化方法(Initialization methods):

在配置文件中通过init-method属性指定的方法。在Bean类中实现InitializingBean接口,并重写afterPropertiesSet()方法。初始化方法用于在Bean实例化后,属性注入完成之后执行一些初始化逻辑,例如初始化资源、建立连接等。您可以根据需要选择其中一种方式来定义初始化方法。

(2)销毁方法(Destruction methods):

在配置文件中通过destroy-method属性指定的方法。
在Bean类中实现DisposableBean接口,并重写destroy()方法。
销毁方法用于在容器销毁Bean之前执行一些清理操作,例如释放资源、关闭连接等。您可以根据需要选择其中一种方式来定义销毁方法。

(3)后置处理器(Post-processors):

后置处理器可以在Bean的初始化前后对Bean进行自定义处理。postProcessBeforeInitialization()方法在初始化方法调用之前被调用,postProcessAfterInitialization()方法在初始化方法调用之后被调用。通过实现这些方法,您可以对Bean进行额外的操作,例如修改属性值、添加代理等。

实现BeanPostProcessor接口,并重写postProcessBeforeInitialization()和postProcessAfterInitialization()方法。
        除了上述方法外,还可以使用其他扩展机制来进行自定义操作,例如使用@PostConstruct和@PreDestroy注解来标记初始化方法和销毁方法,或者通过实现BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor接口来对Bean的定义进行修改。

Spring框架中的Bean管理Spring的核心功能之一,它通过控制反转(IoC)和依赖注入(DI)来实现对象的创建、配置和管理。以下是Spring Bean管理的一些关键点: 1. **控制反转(IoC)**: - IoC是一种设计原则,它将对象的创建、配置和管理交给容器,而不是由应用程序本身来控制。这使得代码更加松耦合,易于测试和维护。 2. **依赖注入(DI)**: - DI是IoC的一种实现方式,它通过构造函数、Setter方法或字段注入的方式将依赖对象注入到Bean中。Spring容器负责创建Bean并注入它们之间的依赖关系。 3. **Bean的配置方式**: - **XML配置**:通过XML文件定义Bean及其依赖关系。 - **注解配置**:使用注解(如`@Component`、`@Service`、`@Repository`、`@Autowired`等)来定义和管理Bean。 - **Java配置**:使用`@Configuration`和`@Bean`注解在Java类中定义Bean。 4. **Bean的作用域**: - **Singleton**:单例模式,整个应用程序中只有一个实例(默认)。 - **Prototype**:原型模式,每次请求都会创建一个新的实例。 - **Request**:每个HTTP请求创建一个实例。 - **Session**:每个HTTP会话创建一个实例。 - **Global Session**:在全局HTTP会话中创建一个实例。 5. **Bean的生命周期**: - Spring容器管理Bean的生命周期,包括Bean的创建、初始化、使用和销毁。可以通过实现`InitializingBean`和`DisposableBean`接口或使用`@PostConstruct`和`@PreDestroy`注解来定义初始化和销毁方法。 6. **自动装配**: - Spring可以通过`@Autowired`注解自动装配Bean之间的依赖关系。自动装配有多种模式,如`byType`、`byName`、`constructor`和`no`。 以下是一个简单的示例,展示了如何使用注解来配置Spring Bean: ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class MyService { private final MyRepository myRepository; @Autowired public MyService(MyRepository myRepository) { this.myRepository = myRepository; } public void performService() { myRepository.performRepositoryWork(); } } @Component public class MyRepository { public void performRepositoryWork() { System.out.println("Repository work performed"); } } ``` 在这个示例中,`MyService`和`MyRepository`类都被标注为`@Component`,表示它们是Spring管理Bean。`MyService`通过构造函数注入`MyRepository`的依赖。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值