【Spring】8.深入探索Spring Context:由浅入深直击Spring的心脏

Spring Context 是 Spring 框架中的一个核心组件,负责提供 Spring 应用的运行时环境。Context 表示“上下文”或“环境”,在 Spring 中,它不仅管理着应用中的对象(称为 Beans),还提供了许多其他关键服务,这些服务对于构建企业级应用至关重要。

作用

  1. IoC 容器:作为控制反转(IoC)容器,Spring Context 负责创建、配置、组装和销毁 Beans。它通过依赖注入(DI)管理对象之间的依赖关系。

  2. 资源管理:提供对外部资源的访问,如数据库连接、文件、网络资源等。

  3. 事件机制:支持事件发布和监听机制,允许应用组件之间通过事件进行通信。

  4. 国际化:支持基于区域的资源文件管理,实现多语言国际化。

  5. 事务管理:提供声明式和编程式的事务管理,支持对事务的细粒度控制。

  6. 安全性:与 Spring Security 集成,提供认证和授权等安全功能。

  7. 数据访问:支持对各种数据访问技术的集成,如 JDBC、Hibernate、JPA 等。

  8. 模块化:支持模块化的应用程序设计,允许应用按模块进行组织和部署。

  9. 扩展点:提供多个扩展点,如 BeanFactoryPostProcessorBeanPostProcessor,允许开发者自定义容器的行为。

  10. 上下文信息:提供关于 Bean 的上下文信息,如 Bean 的定义、作用域和生命周期。

重要性

  • 解耦:通过 IoC 容器,Spring Context 帮助实现了对象之间的松耦合,使得应用更易于管理和维护。
  • 灵活性:提供了灵活的配置和扩展机制,使得应用可以根据需求快速适应变化。
  • 企业级支持:提供了企业级应用开发所需的各种服务和支持,如事务管理、安全性、消息传递等。
  • 集成性:Spring Context 可以很容易地与 Spring 框架的其他模块如 Spring MVC、Spring Data 等集成,构建全栈式的 Java 应用。

总的来说,Spring Context 是 Spring 框架的心脏,为整个应用提供动力和环境支持,是构建和管理企业级 Java 应用的基础。

ApplicationContext接口的实现

ApplicationContext 接口在Spring框架中是用于提供应用上下文的接口,它定义了一系列获取应用环境信息、消息解析、事件发布等基本操作。以下是几种常用的 ApplicationContext 接口实现,以及它们各自的作用和源码片段:

  1. ClassPathXmlApplicationContext
    作用:这个实现从类路径(ClassPath)中加载XML配置文件来初始化Spring上下文。它是最常用的上下文实现之一,特别适合于独立的Java应用程序。
    源码片段

    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    // 这里可以获取配置在applicationContext.xml中的Bean
    MyBean myBean = context.getBean(MyBean.class);
    
  2. FileSystemXmlApplicationContext
    作用:这个实现从文件系统的指定位置加载XML配置文件来初始化Spring上下文。它适用于需要从外部文件系统加载配置文件的场景。
    源码片段

    ApplicationContext context = new FileSystemXmlApplicationContext("/path/to/applicationContext.xml");
    // 获取Bean
    MyBean myBean = context.getBean(MyBean.class);
    
  3. AnnotationConfigApplicationContext
    作用:这个实现用于基于注解的配置。它不依赖于XML文件,而是使用Java注解来配置Bean,适用于现代Spring应用程序,特别是当与Spring Boot结合使用时。
    源码片段

    ApplicationContext context = new AnnotationConfigApplicationContext();
    context.register(AppConfig.class); // AppConfig是一个带有@Configuration注解的类
    context.refresh();
    // 获取Bean
    MyBean myBean = context.getBean(MyBean.class);
    
  4. AnnotationConfigWebApplicationContext
    作用:这是AnnotationConfigApplicationContext的Web版本,用于Web应用程序。它可以与Servlet容器集成,用于Spring MVC等Web应用。
    源码片段

    public class MyWebApplicationInitializer implements WebApplicationInitializer {
        public void onStartup(ServletContext container) {
            AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
            context.register(AppConfig.class);
            context.setServletContext(container);
            // 其他servlet配置
        }
    }
    
  5. GenericApplicationContext
    作用:这是一个通用的Spring应用上下文实现,可以与各种BeanDefinitionReaderBeanFactoryPostProcessor配合使用,用于动态添加Bean定义。

    • 源码片段
      GenericApplicationContext ctx = new GenericApplicationContext();
      XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(ctx);
      xmlReader.loadBeanDefinitions(new ClassPathResource("applicationContext.xml"));
      ctx.refresh();
      // 获取Bean
      MyBean myBean = ctx.getBean(MyBean.class);
      
  6. StaticApplicationContext
    作用:这个实现主要用于编程式的注入Bean和消息,而不是从外部的配置源读取Bean的定义。它通常用于测试环境,因为它允许以声明式的方式添加Beans。
    源码片段

    StaticApplicationContext applicationContext = new StaticApplicationContext();
    applicationContext.registerBean(User.class);
    applicationContext.refresh();
    // 获取Bean
    User user = applicationContext.getBean(User.class);
    

这些实现覆盖了从传统的基于XML的配置到现代的注解和编程式配置的多种应用场景。可以根据项目需求和偏好选择合适的上下文实现。

Spring Context的配置

配置Spring Context可以通过XML文件或Java注解来完成。以下是两种配置方式的基本步骤:

通过XML配置

  1. 创建XML配置文件:首先,在项目中创建一个XML文件,比如命名为applicationContext.xml

  2. 定义Beans:在XML文件中定义所需的Beans,指定它们的类、属性和依赖。

  3. 指定配置文件位置:在启动Spring应用时,需要指定XML配置文件的位置。

  4. 初始化Spring Context:使用ClassPathXmlApplicationContextFileSystemXmlApplicationContext来加载配置文件并初始化Spring Context。

示例XML配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="myBean" class="com.example.MyBean">
        <property name="dependency" ref="dependencyBean"/>
    </bean>

    <bean id="dependencyBean" class="com.example.DependencyBean"/>
</beans>

初始化Context

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
MyBean myBean = context.getBean(MyBean.class);

通过注解配置

  1. 添加注解驱动的配置类:创建一个带有@Configuration注解的类,定义Bean。

  2. 使用@Bean注解:在配置类中,使用@Bean注解方法来声明Spring管理的Beans。

  3. 组件扫描:使用@ComponentScan注解指定Spring扫描组件的包。

  4. 初始化Spring Context:使用AnnotationConfigApplicationContext加载配置类并初始化Spring Context。

示例注解配置

@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {

    @Bean
    public MyBean myBean(DependencyBean dependencyBean) {
        return new MyBean(dependencyBean);
    }

    @Bean
    public DependencyBean dependencyBean() {
        return new DependencyBean();
    }
}

初始化Context

ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
MyBean myBean = context.getBean(MyBean.class);

通过这两种方式,可以定义Spring应用中的Beans,以及它们的依赖关系和配置。XML配置提供了声明式的配置方法,而注解配置则更加简洁且与Java代码紧密集成。随着Spring Boot的普及,注解配置方式越来越受到开发者的青睐。

BeanFactory和ApplicationContext的区别

在Spring框架中,BeanFactoryApplicationContext是控制反转(IoC)容器的两个核心接口。以下是这两个接口的功能对比和一些简单的源码示例来辅助说明它们之间的区别。

BeanFactory

BeanFactory 是Spring IoC容器的最基础形式,提供了依赖注入的基础设施。它主要负责实例化、配置和组装Beans。

public interface BeanFactory {
    Object getBean(String name) throws BeansException;
    <T> T getBean(String name, Class<T> requiredType) throws BeansException;
    boolean containsBean(String name);
    // ... 其他方法
}

使用场景示例(通常不会直接使用BeanFactory,而是使用其实现类):

BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
MyBean myBean = beanFactory.getBean(MyBean.class);

ApplicationContext

ApplicationContext 继承自BeanFactory,不仅包含了其所有功能,还提供了更多的高级功能,适用于企业级应用。

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
        MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
    // ... 继承自ListableBeanFactory等接口的方法

    // 发布事件
    void publishEvent(ApplicationEvent event);

    // 获取应用启动时间
    long getStartupDate();

    // ... 其他方法
}

使用场景示例:

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
MyBean myBean = context.getBean(MyBean.class);
context.publishEvent(new CustomEvent());

区别

  1. 初始化方式
    BeanFactory 采用懒加载方式,即只有在第一次通过getBean获取Bean时才会创建和配置该Bean。
    ApplicationContext 采用急加载方式,容器启动时就创建所有非懒加载的Bean。

  2. 资源访问
    ApplicationContext 提供了对资源文件的访问能力,如通过getResourceAsStream方法。

  3. 事件机制
    只有ApplicationContext 支持事件发布和监听机制。

  4. 国际化
    只有ApplicationContext 支持国际化的MessageSource

  5. Web应用
    ApplicationContext 有专门针对Web应用的子接口,如WebApplicationContext

  6. 扩展性
    ApplicationContext 提供了更多的扩展点,如BeanFactoryPostProcessorBeanPostProcessor

  7. 使用场景
    对于简单应用或不需要Spring高级特性的应用,可以选择BeanFactory
    对于需要使用Spring高级特性的企业级应用,推荐使用ApplicationContext

在实际开发中,我们通常使用ApplicationContext的实现类来初始化Spring容器,如AnnotationConfigApplicationContextClassPathXmlApplicationContext,因为它们提供了更丰富的功能和更好的易用性。

Spring Context的生命周期

Spring Context的生命周期从容器的启动开始,一直到它的关闭。在这段时间内,Spring管理的Beans也会经历各自的生命周期。以下是Spring Context及其Bean生命周期的关键阶段,以及相应的代码说明:

1. 创建Spring Context

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

2. 注册配置类

context.register(SomeConfigClass.class);

3. 刷新容器(刷新是Spring Context生命周期的开始)

context.refresh();

刷新容器会触发以下操作:

  • 记录容器的开始创建时间。
  • 标记容器的活跃状态。
  • 初始化属性源、事件早期多播器等。
  • 获取BeanFactory,并检查是否存在自定义的BeanFactoryPostProcessor和BeanPostProcessor。
  • 注册几个特定的beans,如那些与生命周期管理相关的。
  • 初始化MessageSource,用于国际化等功能。
  • 初始化ApplicationEventMulticaster,用于事件发布和监听。

4. 获取BeanFactory

BeanFactory beanFactory = context.getBeanFactory();

5. BeanFactoryPostProcessor的执行

// 假设SomeBeanFactoryPostProcessor是自定义的BeanFactoryPostProcessor
context.addBeanFactoryPostProcessor(new SomeBeanFactoryPostProcessor());

6. BeanPostProcessor的执行

// 假设SomeBeanPostProcessor是自定义的BeanPostProcessor
context.addBeanPostProcessor(new SomeBeanPostProcessor());

7. 初始化Beans

  • 容器会按照定义的顺序创建和初始化所有的非懒加载的Bean。

8. Bean的初始化和生命周期回调

public class SomeBean implements InitializingBean, DisposableBean {
    
    public void afterPropertiesSet() {
        // Bean属性设置之后调用,由InitializingBean接口提供
    }
    
    public void destroy() {
        // Bean销毁之前调用,由DisposableBean接口提供
    }
}

9. 触发@PostConstruct注解的方法

public class SomeBean {
    
    @PostConstruct
    public void initMethod() {
        // Bean初始化后调用
    }
}

10. 触发@PreDestroy注解的方法

public class SomeBean {
    
    @PreDestroy
    public void cleanupMethod() {
        // Bean销毁前调用
    }
}

11. 使用Beans

SomeBean someBean = context.getBean(SomeBean.class);

12. 关闭容器

context.close();

关闭容器会触发以下操作:

  • 触发单例Bean的销毁。
  • 发布相应的上下文关闭事件。
  • 关闭用于国际化等功能的MessageSource。
  • 关闭其他自定义的资源。

Spring Context的生命周期从refresh()方法开始,到close()方法结束。在这段时间内,每个Bean都会经历从实例化、属性赋值、初始化到销毁的完整过程。理解并利用这些生命周期特征,可以更好地管理资源、执行自定义的初始化或销毁逻辑。

自定义BeanFactoryPostProcessor 和 BeanPostProcessor

在Spring中,自定义BeanFactoryPostProcessorBeanPostProcessor可以让你在容器的生命周期过程中的特定点执行自定义逻辑。以下是如何自定义这两种处理器的步骤和示例:

自定义 BeanFactoryPostProcessor

BeanFactoryPostProcessor接口允许你在容器实例化后、依赖注入之前修改Bean的定义信息。

  1. 实现接口:创建一个类实现BeanFactoryPostProcessor接口。
  2. 重写方法:重写postProcessBeanFactory方法。
  3. 注册处理器:将你的处理器添加到Spring上下文中。

示例

public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 修改beanFactory中的bean定义信息
        // 例如,打印所有bean的名字
        String[] beanNames = beanFactory.getBeanDefinitionNames();
        for (String name : beanNames) {
            System.out.println(name);
        }
    }
}

在配置类中注册:

@Configuration
public class AppConfig {
    @Bean
    public MyBeanFactoryPostProcessor myBeanFactoryPostProcessor() {
        return new MyBeanFactoryPostProcessor();
    }
}

自定义 BeanPostProcessor

BeanPostProcessor接口允许你在容器初始化Bean的前后执行自定义逻辑。

  1. 实现接口:创建一个类实现BeanPostProcessor接口。
  2. 重写方法:重写postProcessBeforeInitializationpostProcessAfterInitialization方法。
  3. 注册处理器:将你的处理器添加到Spring上下文中。

示例

public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Before initialization of " + beanName);
        // 可以修改bean实例
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("After initialization of " + beanName);
        // 可以修改bean实例
        return bean;
    }
}

在配置类中注册:

@Configuration
public class AppConfig {
    @Bean
    public MyBeanPostProcessor myBeanPostProcessor() {
        return new MyBeanPostProcessor();
    }
}

使用 @Bean 标注的方法参数注入

在Spring 4.3+,你可以使用@Bean方法的参数来注入其他beans,实现更加精细的控制。

@Bean
public MyBeanPostProcessor myBeanPostProcessor(AnotherBean anotherBean) {
    return new MyBeanPostProcessor(anotherBean);
}

注意事项

  • BeanFactoryPostProcessor的优先级高于BeanPostProcessor,因此可以在Bean的属性设置之前修改Bean的定义。
  • BeanPostProcessor允许修改新创建的bean实例,可以在初始化前后执行逻辑。
  • 过度使用这些处理器可能会使代码逻辑变得复杂,因此应当谨慎使用。

通过自定义BeanFactoryPostProcessorBeanPostProcessor,可以在Spring容器的启动过程中插入自定义逻辑,增强了框架的灵活性和扩展性。

事件机制

Spring框架的事件机制允许在Spring容器中发布和监听不同的事件。以下是Spring事件机制的描述和如何使用ApplicationEventApplicationListener

1. 发布事件

在Spring中,任何继承自ApplicationEvent的类都可以作为一个事件被发布。

自定义事件

public class CustomEvent extends ApplicationEvent {
    private String message;

    public CustomEvent(Object source, String message) {
        super(source);
        this.message = message;
    }

    public String getMessage() {
        return message;
    }
}

发布事件

public class SomeComponent {
    @Autowired
    private ApplicationEventPublisher publisher;

    public void someMethod() {
        // 发布一个自定义事件
        publisher.publishEvent(new CustomEvent(this, "Hello World!"));
    }
}

2. 监听事件

可以使用ApplicationListener接口或@EventListener注解来监听事件。

使用ApplicationListener接口

public class CustomEventListener implements ApplicationListener<CustomEvent> {
    @Override
    public void onApplicationEvent(CustomEvent event) {
        System.out.println("Received custom event - " + event.getMessage());
    }
}

使用@EventListener注解

@Component
public class AnotherEventListener {
    @EventListener
    public void onCustomEvent(CustomEvent event) {
        System.out.println("Received custom event with @EventListener - " + event.getMessage());
    }
}

3. 注册监听器

Spring会自动注册那些通过@Component@Service@Repository@Configuration注解的类作为监听器,只要它们实现了ApplicationListener接口或使用了@EventListener注解。

4. 异步监听

Spring还支持异步事件监听,只需在@EventListener注解中设置fallbackExecution属性即可。

@EventListener(fallbackExecution = "defaultOnCustomEventListener")
public void onCustomEvent(CustomEvent event) {
    // 异步处理事件
}

public void defaultOnCustomEventListener(CustomEvent event) {
    // 默认方法,当异步处理失败时执行
}

5. 事件传播

事件可以在不同的层次(如父子容器)之间传播,子容器可以发布事件到父容器。

Spring的事件机制提供了一种在Spring容器内部组件之间进行通信的方法。通过发布和监听自定义事件,可以在Spring应用中实现复杂的业务逻辑和解耦。使用ApplicationEventApplicationListener可以轻松地创建和响应事件,而异步监听则提供了处理长时间运行操作的能力,从而不会阻塞主线程。

自定义事件和监听器

在Spring框架中,自定义事件和监听器主要涉及以下几个步骤:

1. 创建自定义事件类

自定义事件类通常继承自ApplicationEvent类。你可以在自定义事件类中添加额外的状态字段,以携带事件相关的信息。

示例

import org.springframework.context.ApplicationEvent;

public class CustomEvent extends ApplicationEvent {
    private String info;

    public CustomEvent(Object source, String info) {
        super(source);
        this.info = info;
    }

    public String getInfo() {
        return info;
    }
}

2. 发布自定义事件

要在Spring应用中发布事件,你需要获取ApplicationEventPublisher的实例,并通过它来发布事件。

示例

import org.springframework.context.ApplicationEventPublisher;

public class SomeComponent {
    @Autowired
    private ApplicationEventPublisher publisher;

    public void someMethod() {
        // 发布一个自定义事件
        CustomEvent ce = new CustomEvent(this, "Some event info");
        publisher.publishEvent(ce);
    }
}

3. 创建事件监听器

事件监听器可以是任何Spring管理的Bean,它通过实现ApplicationListener接口或使用@EventListener注解来监听事件。

使用ApplicationListener接口

import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

@Component
public class CustomEventListener implements ApplicationListener<CustomEvent> {
    @Override
    public void onApplicationEvent(CustomEvent event) {
        System.out.println("Received custom event - " + event.getInfo());
    }
}

使用@EventListener注解

import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Component
public class AnotherEventListener {

    @EventListener
    public void onCustomEvent(CustomEvent event) {
        System.out.println("Received custom event with @EventListener - " + event.getInfo());
    }
}

4. 异步事件监听

Spring还支持异步事件监听,你可以在@EventListener注解中设置fallbackExecution属性来实现。

示例

@EventListener(fallbackExecution = "handleException")
public void handleCustomEvent(CustomEvent event) {
    // 异步处理事件
}

public void handleException(CustomEvent event, Throwable ex) {
    // 异常处理
}

5. 注册事件监听器

在Spring中,事件监听器通常是Spring容器中的Bean。因此,你只需要用@Component@Service@Repository注解标注你的监听器类,Spring会自动注册它们。

6. 事件传播

在基于继承的Spring容器结构中,事件会在所有子容器中传播。如果需要,可以通过设置事件的propagation属性来控制这一行为。

通过创建自定义的事件类和监听器,可以在Spring应用中实现复杂的通信机制。事件机制为解耦合应用组件提供了一种有效的方式,同时异步事件监听增加了处理长时间运行操作的能力。自定义事件和监听器是Spring框架中实现事件驱动架构的重要工具。

资源访问机制

Spring框架提供了一套强大的资源访问机制,允许应用程序以统一的方式访问各种类型的资源,包括类路径资源、文件系统资源、Web资源等。以下是Spring资源访问机制的工作原理和关键组件的解释:

Resource 接口

Resource 接口是Spring资源访问机制的核心,它代表了低层次的资源访问抽象。Resource 接口提供了多种方法来访问和操作资源:

  • InputStream getInputStream(): 获取资源的输入流。
  • boolean exists(): 检查资源是否存在。
  • boolean isOpen(): 检查资源是否已打开。
  • URL getURL(): 获取资源的URL。
  • File getFile(): 获取资源的File对象。
  • String getDescription(): 获取资源的描述信息。

ResourceLoader 接口

ResourceLoader 接口用于加载资源,并为其他接口如BeanFactoryApplicationContext提供资源访问的能力。它定义了一个getResource方法,用于根据给定的资源位置返回Resource对象:

Resource getResource(String location);

ClassPathResource 和 FileSystemResource

Spring提供了多种Resource的实现类,用于访问不同类型的资源:

  • ClassPathResource: 用于访问类路径下的资源,如通过"classpath:example.properties"
  • FileSystemResource: 用于访问文件系统上的资源,如通过"file:/path/to/file.txt"

资源访问示例

以下是如何使用Spring资源访问机制的示例:

import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import java.io.IOException;

public class ResourceExample {
    public void readClassPathResource() throws IOException {
        // 创建类路径资源
        Resource resource = new ClassPathResource("example.properties");
        
        // 读取资源内容
        String content = StreamUtils.copyToString(resource.getInputStream(), StandardCharsets.UTF_8);
        System.out.println(content);
    }
    
    public void readFileSystemResource() throws IOException {
        // 创建文件系统资源
        Resource resource = new FileSystemResource("/path/to/file.txt");
        
        // 读取资源内容
        String content = StreamUtils.copyToString(resource.getInputStream(), StandardCharsets.UTF_8);
        System.out.println(content);
    }
}

作用和优势

  • 解耦资源访问:通过ResourceResourceLoader接口,Spring将资源访问的实现细节抽象化,使得代码不依赖于具体的资源位置或类型。
  • 支持多种资源:Spring的资源机制支持多种资源类型,包括URL、文件、类路径资源等,提供了统一的访问方式。
  • 易于扩展:开发者可以根据需要实现自定义的ResourceResourceLoader,以支持访问特殊的资源。

Spring的资源访问机制为处理不同来源的资源提供了一种灵活和统一的方法,这在构建需要访问外部资源的应用时非常有用。

国际化

Spring框架的国际化功能主要依赖于MessageSource接口来实现。以下是Spring实现国际化的详细步骤和概念:

1. 理解国际化消息

在国际化应用程序中,消息通常不会硬编码为特定语言的字符串,而是使用消息代码来表示。这些代码可以在不同的属性文件中找到对应的翻译文本。

2. MessageSource接口

MessageSource接口是Spring框架中用于解析消息的关键组件。它允许你根据消息代码和可选的参数来检索国际化消息。

3. ResourceBundleMessageSource

Spring提供了ResourceBundleMessageSource实现,它使用Java的ResourceBundle来加载属性文件。这些属性文件包含了消息代码和对应语言的消息文本。

4. 创建属性文件

根据需要支持的语言,创建相应的属性文件。例如:

  • messages.properties:默认英文消息。
  • messages_fr.properties:法语消息。
  • messages_de.properties:德语消息。

5. 配置MessageSource

在Spring配置中,指定basename属性来加载基本的属性文件。如果有多个属性文件,可以使用逗号分隔的列表。

Java配置

@Bean
public MessageSource messageSource() {
    ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
    messageSource.setBasenames("messages", "validation"); // 可以指定多个basename
    messageSource.setDefaultEncoding("UTF-8");
    return messageSource;
}

XML配置

<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <property name="basenames">
        <list>
            <value>messages</value>
            <value>validation</value>
        </list>
    </property>
    <property name="defaultEncoding" value="UTF-8"/>
</bean>

6. 使用消息

在代码中,使用MessageSource来获取国际化消息。

@Autowired
private MessageSource messageSource;

public String getLocalizedMessage(String code, Locale locale) {
    return messageSource.getMessage(code, null, locale);
}

7. 在视图模板中使用消息

在Thymeleaf、JSP或其他视图模板中,使用#{}语法来插入国际化消息。

Thymeleaf示例

<span th:text="#{home.welcome}">Welcome!</span>

8. 设置区域设置(Locale)

Spring将根据用户的区域设置来加载相应的消息。区域设置可以通过多种方式设置,包括用户偏好、HTTP请求头或配置。

Java代码中设置Locale

Locale locale = new Locale("fr", "FR");
messageSource.getMessage("home.welcome", null, locale);

在Web应用程序中根据请求设置Locale

LocaleResolver localeResolver = ...; // 由框架提供
Locale locale = localeResolver.resolveLocale(request);

9. 属性文件的热加载

对于开发期间,可以使用ReloadableResourceBundleMessageSource来实现属性文件的热加载,这样修改消息后不需要重启应用。

Spring的国际化支持允许创建多语言应用程序,而无需硬编码消息文本。通过使用MessageSource接口和属性文件,可以为不同的区域设置提供适当的消息。这使得应用程序能够适应全球化需求,为不同语言的用户提供本地化体验。

附加内容

深入理解Spring Context的源码,特别是AbstractApplicationContextDefaultListableBeanFactory,可以更好地掌握Spring框架的工作原理。以下是这两个类更详细的分析:

AbstractApplicationContext

AbstractApplicationContext是Spring中所有具体应用上下文实现的基类,它实现了ApplicationContext接口,提供了应用上下文的通用行为和生命周期管理。

关键组件和流程

  1. 生命周期管理

    • refresh():刷新容器,初始化属性源、事件早期多播器、MessageSource、ApplicationEventMulticaster等。
    • registerShutdownHook():注册关闭钩子,以确保应用关闭时能优雅地释放资源。
  2. 获取BeanFactory

    • obtainFreshBeanFactory():获取一个新的DefaultListableBeanFactory实例,这是实际管理Bean生命周期的地方。
  3. BeanFactoryPostProcessor和BeanPostProcessor的注册

    • 允许开发者通过这些处理器在容器启动时自定义或修改Bean的定义和行为。
  4. 事件发布

    • publishEvent():发布应用事件,可以用于在组件之间进行通信。
  5. 资源访问

    • 提供了访问资源文件的方法,如getResourceAsStream()
  6. MessageSource

    • 用于国际化等功能,允许根据区域设置获取本地化消息。

DefaultListableBeanFactory

DefaultListableBeanFactory是Spring中用于管理Bean生命周期的核心工厂类,它实现了ListableBeanFactory接口。

关键特性和方法

  1. Bean定义

    • registerBeanDefinition():注册一个Bean的定义,可以是全限定类名、BeanDefinition对象或@Bean注解的方法。
  2. 依赖注入

    • autowireBeanProperties():自动装配Bean的属性,处理@Autowired注解。
  3. Bean生命周期

    • getBean():获取Bean实例,触发Bean的创建、属性设置、初始化和销毁。
    • initializeBean():初始化Bean,应用@PostConstruct注解的方法。
    • destroyBean():销毁Bean,应用@PreDestroy注解的方法。
  4. 扩展点

    • 提供了多个扩展点,如BeanFactoryPostProcessorBeanPostProcessorInstantiationAwareBeanPostProcessor等,允许开发者在不同阶段介入Bean的创建和管理。
  5. 类型转换

    • convertIfNecessary():进行类型转换,支持Spring的@Value注解。
  6. Bean创建过程

    • createBeanInstance():创建Bean实例。
    • populateBean():设置Bean属性。
    • initializeBean():初始化Bean。

通过深入理解Spring Context的工作原理和源码实现,我们不仅能够更加灵活地使用Spring框架构建企业级应用,还可以根据项目需求进行定制和扩展。从基础的IoC容器到复杂的事件驱动系统,Spring Context展示了其作为Spring心脏的强大功能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/593202.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

定时器编程前配置和控制LED隔一秒亮灭

1.配置定时器 0 工作模式16位计时 2.给初值&#xff0c;定一个10ms出来 3.开始计时

环形链表的判断方法与原理证明

&#xff08;题目来源&#xff1a;力扣&#xff09; 一.判读一个链表是否是环形链表 题目&#xff1a; 解答&#xff1a; 方法&#xff1a;快慢指针法 内容&#xff1a;分别定义快慢指针&#xff08;fast和slow&#xff09;&#xff0c;快指针一次走两步&#xff0c;慢指…

物体检测:如何检测小物体?

原文地址&#xff1a;https://medium.com/voxel51/how-to-detect-small-objects-cfa569b4d5bd 2024 年 4 月 22 日 物体检测是计算机视觉的基本任务之一。在高层次上&#xff0c;它涉及预测图像中物体的位置和类别。最先进的&#xff08;SOTA&#xff09;深度学习模型&#x…

3031087 -“无数据”:物料不显示在 MRP 应用中

症状 使用其中一个 MRP 应用&#xff08;监控物料覆盖范围、管理物料覆盖范围、监控外部需求等&#xff09;时无法找到物料。 用户在搜索过滤器时会收到错误消息“无数据”。 “本 KBA 中的图像/数据来自 SAP 内部系统、示例数据或演示系统。任何与真实数据相似的都是完全巧…

Apache反代理Tomcat项目,分离应用服务器和WEB服务器

项目的原理是使用单独的机器做应用服务器&#xff0c;再用单独的机器做WEB服务器&#xff0c;从网络需要访问我们的应用的话&#xff0c;就会先经过我们的WEB服务器&#xff0c;再到达应用程序&#xff0c;这样子的好处是我们可以保护应用程序的机器位置&#xff0c;同时还可以…

R语言中,查看经安装的包,查看已经加载的包,查看特定包是否已经安装,安装包,更新包,卸载包

创建于&#xff1a;2024.5.4 R语言中&#xff0c;查看经安装的包&#xff0c;查看已经加载的包&#xff0c;查看特定包是否已经安装&#xff0c;安装包&#xff0c;更新包&#xff0c;卸载包 文章目录 1. 查看经安装的包2. 查看已经加载的包3. 查看特定包是否已经安装4. 安装包…

java发送请求-http和https

http和https区别 1、http是网络传输超文本协议&#xff0c;client---- http------ server 2、httpshttpssl证书&#xff0c;让网络传输更安全 &#xff0c;client---- httpssl------ server 3、ssl证书是需要客户端认可的&#xff0c;注意官方证书和jdk生成的证书的用户来使…

实现批量自动文本标注(输出标签)代码复现

一&#xff1a;项目地址&#xff1a; IDEA-Research/Grounded-Segment-Anything: Grounded-SAM: Marrying Grounding-DINO with Segment Anything & Stable Diffusion & Recognize Anything - Automatically Detect , Segment and Generate Anything (github.com) 二…

3.SpringSecurity基本原理

SpringSecurity本质是一个过滤器链。十多个过滤器构成一个过滤器链。 这些过滤器在项目启动就会进行加载。每个过滤器执行放行操作才会执行下一个过滤器。 常见过滤器 FilterSecurityInterceptor 是一个方法级的权限过滤器&#xff0c;基本位于过滤器链的最底部。 Excepti…

内核workqueue框架

workqueue驱动的底半部实现方式之一就是工作队列&#xff0c;作为内核的标准模块&#xff0c;它的使用接口也非常简单&#xff0c;schedule_work或者指定派生到哪个cpu的schedule_work_on。 还有部分场景会使用自定义的workqueue&#xff0c;这种情况会直接调用queue_work和qu…

sql 中having和where区别

where 是用于筛选表中满足条件的行&#xff0c;不可以和聚类函数一起使用 having 是用于筛选满足条件的组 &#xff0c;可与聚合函数一起使用 所以having语句中不能使用select中定义的名字

QT:QT与操作系统

文章目录 信号槽与事件 信号槽与事件 在之前的信号槽中&#xff0c;已经有了一个基本的认识&#xff0c;那么对于QT中事件的理解其实就非常的类似&#xff0c;当用户进行某种操作的时候&#xff0c;就会触发事件&#xff0c;去执行一些对应的方法 QT对于事件又进行了封装&…

Lucene从入门到精通

**************************************************************************************************************************************************************************** 1、概述 【1】入门&#xff1a;作用、有点与缺点 【2】应用&#xff1a;索引、搜索、fie…

【软件开发规范篇】JAVA后端开发编程规范

作者介绍&#xff1a;本人笔名姑苏老陈&#xff0c;从事JAVA开发工作十多年了&#xff0c;带过大学刚毕业的实习生&#xff0c;也带过技术团队。最近有个朋友的表弟&#xff0c;马上要大学毕业了&#xff0c;想从事JAVA开发工作&#xff0c;但不知道从何处入手。于是&#xff0…

Python数据分析案例43——Fama-French回归模型资产定价(三因子/五因子)

案例背景 最近看到要做三因子模型的同学还挺多的&#xff0c;就是所谓的Fama-French回归模型&#xff0c;也就是CAMP资本资产定价模型的升级版&#xff0c;然后后面还升级为了五因子模型。 看起来眼花缭乱&#xff0c;其实抛开金融资产定价的背景&#xff0c;从机器学习角度来…

04_jvm性能调优_并行收集器介绍

并行收集器&#xff08;此处也称为吞吐量收集器&#xff09;是类似于串行收集器的分代收集器。串行和并行收集器之间的主要区别在于并行收集器具有多个线程&#xff0c;用于加速垃圾回收过程。 通过命令行选项-XX:UseParallelGC 可启用并行收集器。默认情况下&#xff0c;使用…

消息队列与信号量(基本概念及操作接口介绍)

一、消息队列 基本概念 System V消息队列是Unix系统中一种进程间通信&#xff08;IPC&#xff09;机制&#xff0c;它允许进程互相发送和接收数据块&#xff08;消息&#xff09; 操作系统可以在内部申请一个消息队列&#xff0c;可以让不同的进程向消息队列中发送数据块&…

Linux Systemd基础教程

一、什么是systemd&#xff1f; systemd是Linux系统的一套基本构建模块。它提供了一个系统和服务管理器&#xff0c;作为PID 1运行并启动系统的其余部分。 systemd提供积极的并行化功能&#xff0c;使用套接字和D-Bus激活来启动服务&#xff0c;提供按需启动守护进程&#xf…

《自动机理论、语言和计算导论》阅读笔记:p352-P401

《自动机理论、语言和计算导论》学习第 12 天&#xff0c;p352-P401总结&#xff0c;总计 50 页。 一、技术总结 1.Turing Machine ™ 2.undecidability ​ a.Ld(the diagonalization language) 3.reduction p392, In general, if we have an algorithm to convert insta…

Git系列:config 配置

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…