程序员scholar 程序员scholar
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • Web 标准

    • HTML
    • CSS
    • JavaScript
  • 前端框架

    • Vue2
    • Vue3
    • Vue3 + TS
    • 微信小程序
    • uni-app
  • 工具与库

    • jQuery
    • Ajax
    • Axios
    • Webpack
    • Vuex
    • WebSocket
    • 第三方登录
  • 后端与语言扩展

    • ES6
    • Typescript
    • node.js
  • Element-UI
  • Apache ECharts
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • Web 标准

    • HTML
    • CSS
    • JavaScript
  • 前端框架

    • Vue2
    • Vue3
    • Vue3 + TS
    • 微信小程序
    • uni-app
  • 工具与库

    • jQuery
    • Ajax
    • Axios
    • Webpack
    • Vuex
    • WebSocket
    • 第三方登录
  • 后端与语言扩展

    • ES6
    • Typescript
    • node.js
  • Element-UI
  • Apache ECharts
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
npm

(进入注册为作者充电)

  • Spring Boot

    • Spring Boot - 自动配置
    • Spring Boot - 自定义starter
    • Spring Boot - 配置文件
    • Spring Boot - 自定义SpringApplication
    • Spring Boot - 生命周期与事件
    • Spring Boot - 事件驱动
    • Spring Boot - Bean 加载方式
    • Spring Boot - 容器资源感知与获取
      • 1. Spring Aware接口概
      • 2. 常用Aware接口
      • 3. Aware接口实现原理
        • 3.1 Aware接口处理流程
        • 3.2 执行机制
      • 4. 常用Aware接口使用
        • 4.1 BeanFactoryAware
        • 4.2 BeanNameAware
        • 4.3 EnvironmentAware
        • 4.4 ApplicationContextAware
        • 4.5 ResourceLoaderAware
        • 4.6 ApplicationEventPublisherAware
        • 4.7 MessageSourceAware
      • 5. 实际应用场景
        • 5.1 Aware接口的应用场景
        • 5.2 最佳实践
    • Spring Boot - 定时任务
    • Spring Boot - 异步任务
    • Spring Boot - 内置日志
    • Spring Boot - 函数式 Web
    • Spring Boot - 响应式远程调用
    • Spring Boot - 接口文档
    • Spring Boot - 单元测试
    • Spring Boot - 内容协商
    • Spring Boot - 参数校验
    • Spring Boot - HTTP客户端工具
    • Spring Boot - 控制器请求映射
    • Spring Boot - 请求参数接收
    • Spring Boot - 通用响应类
    • Spring Boot - 全局异常处理
    • Spring Boot - 整合Druid
    • Spring Boot - 整合Thymeleaf
    • Spring Boot - 国际化实现
    • Spring Boot - 自定义注解
  • Spring高级
  • Spring Boot
scholar
2023-11-02
目录

Spring Boot - 容器资源感知与获取

# Spring Boot - 容器资源感知与获取

# 1. Spring Aware接口概

在Spring框架的设计理念中,一个重要原则是让应用组件(Bean)不感知容器的存在,从而降低组件与框架之间的耦合度。这种"非侵入式"设计允许开发者专注于业务逻辑,而无需关心组件是如何被管理的。

然而,在某些特定场景下,我们确实需要在Bean中感知到Spring容器的存在,获取容器提供的资源或服务。例如:

  • 获取当前应用的环境配置信息
  • 获取其他Bean的引用
  • 获取容器中的特定资源
  • 发布应用事件等

为了满足这些需求,Spring框架提供了一系列的"Aware"接口。通过实现这些接口,Bean可以在其生命周期的特定阶段获得对Spring容器特定资源的访问权限。

Aware接口的核心思想:允许Bean在不破坏容器封装性的前提下,有选择地获取容器提供的服务和资源。

# 2. 常用Aware接口

Spring框架提供了多种Aware接口,每种接口都允许Bean获取容器中的不同资源。以下是最常用的Aware接口及其功能详解:

接口名称 回调方法 提供的资源 使用场景
BeanNameAware setBeanName(String name) Bean在容器中的名称 需要在代码中获取Bean自身的名称
BeanFactoryAware setBeanFactory(BeanFactory factory) BeanFactory实例,可用于获取其他Bean 需要编程式获取其他Bean实例
ApplicationContextAware setApplicationContext(ApplicationContext ctx) 应用上下文,功能比BeanFactory更丰富 获取应用上下文中的各种资源,最常用的Aware接口
EnvironmentAware setEnvironment(Environment env) 应用的环境配置信息 获取配置文件中的属性、系统环境变量等
EmbeddedValueResolverAware setEmbeddedValueResolver(StringValueResolver resolver) 字符串解析器,可解析配置文件中的占位符 解析properties文件或yml文件中的属性值
ResourceLoaderAware setResourceLoader(ResourceLoader loader) 资源加载器,用于加载各种资源 加载类路径或文件系统中的资源文件
ApplicationEventPublisherAware setApplicationEventPublisher(ApplicationEventPublisher publisher) 事件发布器 发布自定义应用事件
MessageSourceAware setMessageSource(MessageSource ms) 消息源,用于国际化 获取国际化消息,支持多语言应用
BeanClassLoaderAware setBeanClassLoader(ClassLoader classLoader) 类加载器 获取加载Bean的类加载器,通常用于高级场景

# 3. Aware接口实现原理

Spring容器是如何感知并处理实现了Aware接口的Bean的?其内部实现原理如下:

# 3.1 Aware接口处理流程

  1. Bean实例化:Spring容器首先实例化Bean对象。

  2. Aware接口检测:在Bean的初始化流程中,Spring容器会检查Bean是否实现了各种Aware接口。

  3. 回调方法调用:如果Bean实现了某个Aware接口,容器会调用对应的回调方法,传入相应的资源。

  4. 注入时机:Aware接口的回调方法通常在属性填充之后、初始化方法(如@PostConstruct或afterPropertiesSet())调用之前执行。

# 3.2 执行机制

Spring在AbstractAutowireCapableBeanFactory类的initializeBean方法中处理Aware接口:

// Spring内部处理Aware接口的代码片段(简化版)
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
    // 处理Aware接口
    if (bean instanceof Aware) {
        if (bean instanceof BeanNameAware) {
            ((BeanNameAware) bean).setBeanName(beanName);
        }
        if (bean instanceof BeanClassLoaderAware) {
            ((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
        }
        if (bean instanceof BeanFactoryAware) {
            ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
        }
        // 处理其他Aware接口...
    }
    
    // 继续Bean的初始化流程...
    return bean;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

不同的Aware接口在Bean生命周期的不同阶段被处理。例如,ApplicationContextAware接口是通过ApplicationContextAwareProcessor这个BeanPostProcessor来处理的,它在Bean实例化后的后处理阶段被调用。

# 4. 常用Aware接口使用

下面通过具体示例展示如何使用各种Aware接口:

# 4.1 BeanFactoryAware

BeanFactoryAware接口允许我们获取到Spring的BeanFactory实例,从而可以编程式地获取其他Bean。

/**
 * BeanFactoryAware示例
 * 通过实现BeanFactoryAware接口获取Spring的BeanFactory
 */
@Component
public class MyBeanFactoryAware implements BeanFactoryAware {
    
    private BeanFactory beanFactory;
    
    /**
     * 当Bean被创建时,Spring容器会调用此方法并传入BeanFactory实例
     * @param beanFactory Spring容器的BeanFactory实例
     * @throws BeansException 如果获取BeanFactory时出错
     */
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        // 保存BeanFactory的引用,以便后续使用
        this.beanFactory = beanFactory;
        
        // 演示:从BeanFactory中获取AccountService实例
        AccountService accountService = beanFactory.getBean(AccountService.class);
        System.out.println("BeanFactoryAware:成功获取AccountService实例 - " + accountService);
    }
    
    /**
     * 公共方法示例:使用保存的BeanFactory获取任意Bean
     * @param beanClass 需要获取的Bean类型
     * @return 对应类型的Bean实例
     */
    public <T> T getBean(Class<T> beanClass) {
        return this.beanFactory.getBean(beanClass);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

# 4.2 BeanNameAware

BeanNameAware接口允许Bean获取自己在Spring容器中的名称。

/**
 * BeanNameAware示例
 * 通过实现BeanNameAware接口获取Bean在容器中的名称
 */
@Component
public class MyBeanNameAware implements BeanNameAware {
    
    private String beanName;
    
    /**
     * 当Bean被创建时,Spring容器会调用此方法并传入Bean的名称
     * @param name Bean在容器中的名称
     */
    @Override
    public void setBeanName(String name) {
        // 保存Bean名称,以便后续使用
        this.beanName = name;
        System.out.println("BeanNameAware:当前Bean的名称是 - " + name); 
    }
    
    /**
     * 获取当前Bean的名称
     * @return Bean名称
     */
    public String getBeanName() {
        return this.beanName;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# 4.3 EnvironmentAware

EnvironmentAware接口允许我们获取Spring应用的环境信息,包括配置文件中的属性、系统环境变量等。

/**
 * EnvironmentAware示例
 * 通过实现EnvironmentAware接口获取应用环境配置
 */
@Component
public class MyEnvironmentAware implements EnvironmentAware {
    
    private Environment environment;
    
    /**
     * 当Bean被创建时,Spring容器会调用此方法并传入Environment实例
     * @param environment Spring应用的环境配置实例
     */
    @Override
    public void setEnvironment(Environment environment) {
        // 保存Environment引用,以便后续使用
        this.environment = environment;
        
        // 演示:获取配置文件中的服务端口配置
        String serverPort = environment.getProperty("server.port");
        System.out.println("EnvironmentAware:应用服务端口配置为 - " + serverPort);
        
        // 获取多个配置属性示例
        String appName = environment.getProperty("spring.application.name", "默认应用名");
        boolean isDevProfile = environment.acceptsProfiles(Profiles.of("dev"));
        
        System.out.println("应用名称: " + appName);
        System.out.println("是否是开发环境: " + isDevProfile);
    }
    
    /**
     * 获取任意配置属性的便捷方法
     * @param key 配置键
     * @return 配置值,如果不存在则返回null
     */
    public String getProperty(String key) {
        return this.environment.getProperty(key);
    }
    
    /**
     * 获取带默认值的配置属性
     * @param key 配置键
     * @param defaultValue 默认值
     * @return 配置值,如果不存在则返回默认值
     */
    public String getProperty(String key, String defaultValue) {
        return this.environment.getProperty(key, defaultValue);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

# 4.4 ApplicationContextAware

ApplicationContextAware是最常用的Aware接口,它提供了对Spring应用上下文的完整访问,功能比BeanFactory更加丰富。

/**
 * ApplicationContextAware示例
 * 通过实现ApplicationContextAware接口获取Spring应用上下文
 */
@Component
public class MyApplicationContextAware implements ApplicationContextAware {
    
    private ApplicationContext applicationContext;
    
    /**
     * 当Bean被创建时,Spring容器会调用此方法并传入ApplicationContext实例
     * @param applicationContext Spring应用上下文实例
     * @throws BeansException 如果获取ApplicationContext时出错
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        // 保存ApplicationContext引用,以便后续使用
        this.applicationContext = applicationContext;
        
        // 演示:从ApplicationContext中获取Bean
        CouponService couponService = applicationContext.getBean(CouponService.class);
        System.out.println("ApplicationContextAware:成功获取CouponService实例 - " + couponService);
        
        // 演示:通过ApplicationContext获取环境配置
        String serverPort = applicationContext.getEnvironment().getProperty("server.port");
        System.out.println("ApplicationContextAware:应用服务端口配置为 - " + serverPort);
        
        // 演示:获取应用名称
        String appName = applicationContext.getApplicationName();
        System.out.println("应用名称: " + appName);
        
        // 演示:检查Bean是否存在
        boolean userServiceExists = applicationContext.containsBean("userService");
        System.out.println("userService是否存在: " + userServiceExists);
    }
    
    /**
     * 获取指定类型的Bean
     * @param clazz Bean类型
     * @return Bean实例
     */
    public <T> T getBean(Class<T> clazz) {
        return this.applicationContext.getBean(clazz);
    }
    
    /**
     * 根据名称获取Bean
     * @param beanName Bean名称
     * @return Bean实例
     */
    public Object getBean(String beanName) {
        return this.applicationContext.getBean(beanName);
    }
    
    /**
     * 获取ApplicationContext,可用于外部访问
     * @return ApplicationContext实例
     */
    public ApplicationContext getApplicationContext() {
        return this.applicationContext;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

# 4.5 ResourceLoaderAware

ResourceLoaderAware接口允许我们获取Spring的资源加载器,用于加载各种资源文件。

/**
 * ResourceLoaderAware示例
 * 通过实现ResourceLoaderAware接口获取Spring资源加载器
 */
@Component
public class MyResourceLoaderAware implements ResourceLoaderAware {
    
    private ResourceLoader resourceLoader;
    
    /**
     * 当Bean被创建时,Spring容器会调用此方法并传入ResourceLoader实例
     * @param resourceLoader Spring资源加载器实例
     */
    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        // 保存ResourceLoader引用,以便后续使用
        this.resourceLoader = resourceLoader;
        
        // 演示:加载类路径下的配置文件
        Resource applicationYml = resourceLoader.getResource("classpath:application.yml");
        System.out.println("ResourceLoaderAware:成功加载资源 - " + applicationYml.getDescription());
        
        // 演示:加载多种资源
        try {
            // 加载类路径资源
            Resource classpathResource = resourceLoader.getResource("classpath:logback.xml");
            System.out.println("类路径资源是否存在: " + classpathResource.exists());
            
            // 加载文件系统资源
            Resource fileResource = resourceLoader.getResource("file:///D:/config/app-config.properties");
            System.out.println("文件系统资源是否存在: " + fileResource.exists());
            
            // 加载URL资源
            Resource urlResource = resourceLoader.getResource("https://example.com/config.json");
            System.out.println("URL资源描述: " + urlResource.getDescription());
            
        } catch (Exception e) {
            System.out.println("加载资源时发生错误: " + e.getMessage());
        }
    }
    
    /**
     * 加载指定路径的资源
     * @param location 资源路径,如:classpath:config.xml, file:/config/app.properties
     * @return 资源对象
     */
    public Resource getResource(String location) {
        return this.resourceLoader.getResource(location);
    }
    
    /**
     * 读取资源内容为字符串
     * @param location 资源路径
     * @return 资源内容字符串
     * @throws IOException 如果读取失败
     */
    public String getResourceAsString(String location) throws IOException {
        Resource resource = getResource(location);
        try (InputStream is = resource.getInputStream();
             BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
            return reader.lines().collect(Collectors.joining("\n"));
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

# 4.6 ApplicationEventPublisherAware

ApplicationEventPublisherAware接口允许我们获取Spring的事件发布器,用于发布应用事件。

/**
 * ApplicationEventPublisherAware示例
 * 通过实现ApplicationEventPublisherAware接口获取Spring事件发布器
 */
@Component
public class MyEventPublisherAware implements ApplicationEventPublisherAware {
    
    private ApplicationEventPublisher eventPublisher;
    
    /**
     * 当Bean被创建时,Spring容器会调用此方法并传入ApplicationEventPublisher实例
     * @param eventPublisher Spring事件发布器实例
     */
    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher eventPublisher) {
        // 保存事件发布器引用,以便后续使用
        this.eventPublisher = eventPublisher;
        System.out.println("ApplicationEventPublisherAware:成功获取事件发布器");
    }
    
    /**
     * 发布自定义事件的示例方法
     * @param message 事件携带的消息
     */
    public void publishCustomEvent(String message) {
        // 创建自定义事件对象
        CustomEvent event = new CustomEvent(this, message);
        
        // 通过事件发布器发布事件
        eventPublisher.publishEvent(event);
        System.out.println("已发布自定义事件: " + message);
    }
    
    /**
     * 发布任意事件对象
     * @param event 要发布的事件对象
     */
    public void publishEvent(Object event) {
        this.eventPublisher.publishEvent(event);
    }
    
    /**
     * 自定义事件类示例
     */
    public static class CustomEvent extends ApplicationEvent {
        private final String message;
        
        public CustomEvent(Object source, String message) {
            super(source);
            this.message = message;
        }
        
        public String getMessage() {
            return message;
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

# 4.7 MessageSourceAware

MessageSourceAware接口允许我们获取Spring的消息源,用于国际化和多语言支持。

/**
 * MessageSourceAware示例
 * 通过实现MessageSourceAware接口获取Spring消息源
 */
@Component
public class MyMessageSourceAware implements MessageSourceAware {
    
    private MessageSource messageSource;
    
    /**
     * 当Bean被创建时,Spring容器会调用此方法并传入MessageSource实例
     * @param messageSource Spring消息源实例
     */
    @Override
    public void setMessageSource(MessageSource messageSource) {
        // 保存消息源引用,以便后续使用
        this.messageSource = messageSource;
        
        // 演示:获取国际化消息
        String welcome = messageSource.getMessage("welcome", null, Locale.getDefault());
        System.out.println("MessageSourceAware:默认语言的欢迎消息 - " + welcome);
        
        // 获取带参数的消息
        String greeting = messageSource.getMessage("greeting", new Object[]{"John"}, Locale.US);
        System.out.println("英文问候: " + greeting);
        
        // 获取中文消息
        String chineseGreeting = messageSource.getMessage("greeting", new Object[]{"张三"}, Locale.CHINESE);
        System.out.println("中文问候: " + chineseGreeting);
    }
    
    /**
     * 获取指定语言的国际化消息
     * @param code 消息代码
     * @param args 消息参数
     * @param locale 语言环境
     * @return 格式化后的国际化消息
     */
    public String getMessage(String code, Object[] args, Locale locale) {
        return this.messageSource.getMessage(code, args, locale);
    }
    
    /**
     * 获取当前语言环境的国际化消息
     * @param code 消息代码
     * @param args 消息参数
     * @return 格式化后的国际化消息
     */
    public String getMessage(String code, Object[] args) {
        return this.messageSource.getMessage(code, args, Locale.getDefault());
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

# 5. 实际应用场景

# 5.1 Aware接口的应用场景

  1. 通用工具类:创建全局可访问的工具Bean,提供对Spring容器资源的访问。
/**
 * Spring上下文工具类
 * 通过ApplicationContextAware接口实现全局访问Spring容器的能力
 */
@Component
public class SpringContextUtil implements ApplicationContextAware {
    
    private static ApplicationContext applicationContext;
    
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringContextUtil.applicationContext = applicationContext;
    }
    
    /**
     * 获取ApplicationContext
     */
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }
    
    /**
     * 通过名称获取Bean
     */
    public static Object getBean(String name) {
        return applicationContext.getBean(name);
    }
    
    /**
     * 通过类型获取Bean
     */
    public static <T> T getBean(Class<T> clazz) {
        return applicationContext.getBean(clazz);
    }
    
    /**
     * 获取配置属性
     */
    public static String getProperty(String key) {
        return applicationContext.getEnvironment().getProperty(key);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
  1. 定制化配置处理:在应用启动时读取特定配置并进行处理。
/**
 * 数据库配置处理器
 * 在应用启动时初始化数据库连接池配置
 */
@Component
public class DatabaseConfigProcessor implements EnvironmentAware {
    
    @Override
    public void setEnvironment(Environment environment) {
        // 获取数据库配置
        String dbUrl = environment.getProperty("spring.datasource.url");
        String dbUsername = environment.getProperty("spring.datasource.username");
        
        // 处理敏感信息
        String dbPassword = environment.getProperty("spring.datasource.password");
        if (dbPassword != null) {
            // 解密密码(示例)
            dbPassword = decryptPassword(dbPassword);
            
            // 重新设置解密后的密码(通过系统属性)
            System.setProperty("DB_DECRYPTED_PASSWORD", dbPassword);
        }
        
        System.out.println("数据库配置已处理: " + dbUrl);
    }
    
    private String decryptPassword(String encryptedPassword) {
        // 实现密码解密逻辑
        return "decrypted:" + encryptedPassword;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  1. 自定义事件发布:实现业务事件的发布与监听。
/**
 * 订单服务
 * 使用事件发布器实现订单状态变更通知
 */
@Service
public class OrderService implements ApplicationEventPublisherAware {
    
    private ApplicationEventPublisher eventPublisher;
    
    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher eventPublisher) {
        this.eventPublisher = eventPublisher;
    }
    
    /**
     * 创建新订单
     */
    public Order createOrder(OrderRequest request) {
        // 创建订单逻辑
        Order newOrder = new Order();
        newOrder.setId(generateOrderId());
        newOrder.setCustomerId(request.getCustomerId());
        newOrder.setAmount(request.getAmount());
        newOrder.setStatus("CREATED");
        
        // 保存订单
        // orderRepository.save(newOrder);
        
        // 发布订单创建事件
        eventPublisher.publishEvent(new OrderCreatedEvent(newOrder));
        
        return newOrder;
    }
    
    /**
     * 更新订单状态
     */
    public void updateOrderStatus(Long orderId, String newStatus) {
        // 获取订单
        Order order = getOrderById(orderId);
        String oldStatus = order.getStatus();
        
        // 更新状态
        order.setStatus(newStatus);
        // orderRepository.update(order);
        
        // 发布订单状态变更事件
        eventPublisher.publishEvent(
            new OrderStatusChangedEvent(order, oldStatus, newStatus));
    }
    
    // 模拟方法 - 实际项目中应连接数据库
    private Order getOrderById(Long orderId) {
        Order order = new Order();
        order.setId(orderId);
        order.setStatus("PENDING");
        return order;
    }
    
    private Long generateOrderId() {
        return System.currentTimeMillis();
    }
    
    // 内部类 - 订单请求
    @Data
    public static class OrderRequest {
        private Long customerId;
        private Double amount;
    }
    
    // 内部类 - 订单实体
    @Data
    public static class Order {
        private Long id;
        private Long customerId;
        private Double amount;
        private String status;
    }
    
    // 内部类 - 订单创建事件
    public static class OrderCreatedEvent extends ApplicationEvent {
        public OrderCreatedEvent(Order order) {
            super(order);
        }
        
        public Order getOrder() {
            return (Order) getSource();
        }
    }
    
    // 内部类 - 订单状态变更事件
    public static class OrderStatusChangedEvent extends ApplicationEvent {
        private final String oldStatus;
        private final String newStatus;
        
        public OrderStatusChangedEvent(Order order, String oldStatus, String newStatus) {
            super(order);
            this.oldStatus = oldStatus;
            this.newStatus = newStatus;
        }
        
        public Order getOrder() {
            return (Order) getSource();
        }
        
        public String getOldStatus() {
            return oldStatus;
        }
        
        public String getNewStatus() {
            return newStatus;
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114

# 5.2 最佳实践

  1. 谨慎使用:Aware接口引入了对Spring容器的依赖,破坏了组件的独立性。只在必要时使用。

  2. 选择最小权限的接口:如果只需要特定功能,选择对应的专用Aware接口,而不是总是使用ApplicationContextAware。

  3. 考虑替代方案:在许多情况下,可以使用依赖注入替代Aware接口。例如,可以直接注入Environment而不是实现EnvironmentAware。

  4. 注意线程安全:在多线程环境中使用Aware接口获取的资源时,需要考虑线程安全问题。

  5. 避免在构造函数中使用:Aware接口的回调方法是在Bean实例化后调用的,不要在构造函数中尝试使用这些资源。

编辑此页 (opens new window)
上次更新: 2025/03/30, 23:46:38
Spring Boot - Bean 加载方式
Spring Boot - 定时任务

← Spring Boot - Bean 加载方式 Spring Boot - 定时任务→

Theme by Vdoing | Copyright © 2019-2025 程序员scholar
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式