Spring Bean是如何初始化的详解

当Spring应用启动时,Spring容器会初始化所有由用户定义的bean(也就是Spring应用上下文中的bean),并映射它们之间的依赖关系。那么Spring Bean是如何初始化的呢?下面详细介绍一下Spring Bean的初始化过程。

1. Spring Bean的加载

首先,Spring容器会扫描Bean配置文件,找到所有的Bean定义,并将其保存在容器内部的BeanDefinitionMap中,这个Map中保存了每个Bean的属性信息,包括Bean的名称、Bean的类名、依赖关系等。

2. 实例化Bean

接下来,Spring容器会根据Bean的定义信息,通过Java反射机制实例化Bean对象,也就是将Bean的类实例化。Spring默认使用的是无参构造函数实例化Bean对象,也可以通过配置指定使用有参构造函数。

例如,以下是一个简单的Java类:

public class Student {
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

在配置文件中定义该Bean:

<bean id="student" class="com.example.Student"/>

Spring容器将会使用无参构造函数实例化该Bean对象。

如果使用有参构造函数实例化Bean对象,可以在配置文件中指定参数:

<bean id="student" class="com.example.Student">
    <constructor-arg value="Bob"/>
    <constructor-arg value="18"/>
</bean>

3. Bean属性的注入

Spring容器将通过反射机制调用Setter方法或者直接给对象属性赋值,完成Bean属性的注入。

例如,在上面的Student类中,我们定义了两个Setter方法:setName和setAge。我们可以在配置文件中指定Bean的属性值:

<bean id="student" class="com.example.Student">
    <property name="name" value="Bob"/>
    <property name="age" value="18"/>
</bean>

4. 实现BeanPostProcessor接口

对于实现了BeanPostProcessor接口的Bean,Spring容器会在实例化Bean对象后,调用BeanPostProcessor的两个方法,分别是postProcessBeforeInitialization和postProcessAfterInitialization。可以在这两个方法中对Bean对象进行一些初始化操作。

例如,下面定义一个实现了BeanPostProcessor接口的类:

public class StudentBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // 在Bean对象初始化之前做一些操作
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // 在Bean对象初始化之后做一些操作
        return bean;
    }
}

在配置文件中指定该BeanPostProcessor:

<bean id="studentBeanPostProcessor" class="com.example.StudentBeanPostProcessor"/>

<bean id="student" class="com.example.Student">
    <property name="name" value="Bob"/>
    <property name="age" value="18"/>
</bean>

5. 实现InitializingBean和DisposableBean接口

除了实现BeanPostProcessor接口外,Bean还可以实现InitializingBean和DisposableBean接口。当Bean实现了InitializingBean接口时,在Bean对象初始化完成后,Spring容器会调用afterPropertiesSet()方法对Bean进行自定义初始化操作;当Bean实现了DisposableBean接口时,在Bean对象被销毁前,Spring容器会调用destroy()方法对Bean进行自定义销毁操作。

例如,下面定义一个实现了InitializingBean和DisposableBean接口的类:

public class Student implements InitializingBean, DisposableBean {
    private String name;
    private int age;

    @Override
    public void afterPropertiesSet() throws Exception {
        // 在Bean对象初始化之后做一些操作
    }

    @Override
    public void destroy() throws Exception {
        // 在Bean对象被销毁前做一些操作
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

6. 示例说明

以下是一个简单的示例,演示Spring容器是如何初始化Bean对象的。

定义一个Person类,包含两个属性:姓名和年龄。

public class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }    
}

在Bean配置文件中定义Person类的Bean:

<bean id="person" class="com.example.Person">
    <property name="name" value="Tom"/>
    <property name="age" value="18"/>
</bean>

在代码中获取Person类的Bean,并输出其属性值:

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person = (Person) context.getBean("person");
System.out.println(person.getName() + ", " + person.getAge());

以上输出结果为:Tom, 18。

通过上述示例,可以看到Spring Bean的初始化过程:首先将Bean的定义信息保存到容器中,然后使用Java反射机制实例化Bean对象,接着对Bean对象进行属性注入,最后调用BeanPostProcessor、InitializingBean和DisposableBean接口中的方法对Bean进行自定义初始化和销毁操作。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Spring Bean是如何初始化的详解 - Python技术站

(0)
上一篇 2023年5月27日
下一篇 2023年5月27日

相关文章

  • 详解spring整合shiro权限管理与数据库设计

    详解Spring整合Shiro权限管理与数据库设计 引言 本文详细讲解如何使用Spring框架整合Shiro权限管理,并给出完整的数据库设计方案和示例代码。 Shiro简介 Shiro是一个强大的Java安全框架,可以提供身份认证、授权、加密等各种安全相关的功能。Shiro使用非常简单,易于集成到Java应用中。 Spring整合Shiro权限管理 引入Sh…

    Java 2023年5月20日
    00
  • 利用ECharts.js画K线图的方法示例

    下面是关于“利用ECharts.js画K线图的方法示例”的完整攻略。 什么是K线图 K线图是一种专业股票分析图表,它能够充分反映出股票市场的交易情况和趋势走势。K线图是由四个价格点构成的,包括开盘价、收盘价、最高价和最低价,每个价格点都用线条或实体块来表示。 使用ECharts.js绘制K线图 ECharts.js是一款非常强大的JavaScript图表库,…

    Java 2023年6月15日
    00
  • 详解Struts2中对未登录jsp页面实现拦截功能

    Struts2框架提供了一种过滤器拦截机制,可以在Action类之前做一些权限控制的处理,例如对未登录的用户拦截访问特定的jsp页面。下面是针对该问题的完整攻略: 步骤一:配置Struts2的过滤器 在web.xml文件中配置Struts2的拦截器: <!–Struts2拦截器配置–> <filter> <filter-na…

    Java 2023年6月15日
    00
  • Java获取当前时间方法总结

    Java获取当前时间方法总结 在Java中,有多种方法可以获取当前时间。本文将总结其中常用的方法,并提供示例代码。 方法一:使用System.currentTimeMillis() System.currentTimeMillis()方法返回当前时间的毫秒数。可以使用这个值来获取当前时间。 示例代码: long currentTimeMillis = Sys…

    Java 2023年5月20日
    00
  • Terry七月Ruby读书笔记(比较详细)第2/4页

    你好,针对“Terry七月Ruby读书笔记(比较详细)第2/4页”的完整攻略,我将分享以下内容: 1. 阅读前的准备 在阅读该笔记之前,我们需要先掌握 Ruby 的基本语法知识,并且了解 Ruby 中常用的代码结构和函数库。如果我们对 Ruby 还不是很了解,可以先通过官方文档、教程或者其他学习资源进行学习。 2. 分析文章的结构 在开始阅读该笔记时,我们应…

    Java 2023年5月20日
    00
  • Spring MVC中自定义拦截器的实例讲解

    以下是关于“Spring MVC中自定义拦截器的实例讲解”的完整攻略,其中包含两个示例。 Spring MVC中自定义拦截器的实例讲解 拦截器是Spring MVC中的一个重要组件,它可以在请求到达Controller之前或之后执行一些操作。在本文中,我们将讲解如何在Spring MVC中自定义拦截器。 步骤一:创建Maven项目 打开IntJ IDEA,选…

    Java 2023年5月17日
    00
  • hibernate批量操作实例详解

    Hibernate批量操作实例详解 批量操作是什么? Hibernate中的批量操作是指将多个数据库操作语句合并成一个批量操作,通过一次提交将所有语句提交到数据库,从而提高数据库操作效率。 常见的批量操作方法 批量新增 Session session = sessionFactory.getCurrentSession(); for(int i = 0; i…

    Java 2023年5月20日
    00
  • Java结合JS实现URL编码与解码

    URL编码 & 解码的概念 URL编码:将URL中特殊字符转义成十六进制字节,以便浏览器和服务器可以更好地理解和传递这些字节。 URL解码:将URL中的十六进制字节转换为特殊字符。 需要注意的是:URL编码与解码操作是成对出现的, 编码后的URL需要解码才能得到正确的值。 Java实现URL编码 & 解码 Java中URL编码的实现主要依赖于…

    Java 2023年5月20日
    00
合作推广
合作推广
分享本页
返回顶部