前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >工具类如何获取到 Spring 容器中的 Bean?

工具类如何获取到 Spring 容器中的 Bean?

作者头像
江南一点雨
发布于 2022-06-24 10:45:47
发布于 2022-06-24 10:45:47
1.3K00
代码可运行
举报
文章被收录于专栏:玩转JavaEE玩转JavaEE
运行总次数:0
代码可运行

松哥最近正在录制 TienChin 项目视频~采用 Spring Boot+Vue3 技术栈,里边会涉及到各种好玩的技术,小伙伴们来和松哥一起做一个完成率超 90% 的项目,戳戳戳这里-->TienChin 项目配套视频来啦


1. Aware 接口

小伙伴们知道,Spring 容器最大的特点在于所有的 Bean 对于 Spring 容器的存在是没有意识的,因此我们常说理论上你可以无缝将 Spring 容器切换为其他容器(然而在现实世界中,我们其实没有这样的选择,除了 Spring 容器,难道还有更好用的?)。

当然这只是一个理论,在实际开发中,我们往往要用到 Spring 容器为我们提供的诸多资源,例如想要获取到容器中的配置、获取到容器中的 Bean 等等。在这种情况下,就需要 Spring 容器中的 Bean 真正的意识到 Spring 容器的存在,才能要到这些东西,那么如何让一个 Bean 意识到 Spring 容器的存在呢?

这就依赖于 Spring 容器给我们提供的各种 Aware 接口了。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * A marker superinterface indicating that a bean is eligible to be notified by the
 * Spring container of a particular framework object through a callback-style method.
 * The actual method signature is determined by individual subinterfaces but should
 * typically consist of just one void-returning method that accepts a single argument.
 *
 * <p>Note that merely implementing {@link Aware} provides no default functionality.
 * Rather, processing must be done explicitly, for example in a
 * {@link org.springframework.beans.factory.config.BeanPostProcessor}.
 * Refer to {@link org.springframework.context.support.ApplicationContextAwareProcessor}
 * for an example of processing specific {@code *Aware} interface callbacks.
 *
 * @author Chris Beams
 * @author Juergen Hoeller
 * @since 3.1
 */
public interface Aware {

}

从这个接口的注释中,我们也能大概看出来,这个接口的子类,主要是提供了一些只有一个参数的 set 方法,通过这些方法可以让 Spring 容器感知到某一件事情。

Aware 的实现有很多,大的方向来说主要有如下一些:

每一个 Aware 的作用如下:

  • ApplicationEventPublisherAware:实现该接口的对象可以获取事件发布的能力。
  • ServletContextAware:实现该接口的对象可以获取到 ServletContext 对象。
  • MessageSourceAware:实现该接口的对象可以获取到 MessageSource 对象,MessageSource 支持多消息源,主要用于主要用于国际化。
  • ResourceLoaderAware:实现该接口的对象可以获取到一个 ResourceLoader,Spring ResourceLoader 则为我们提供了一个统一的 getResource() 方法来通过资源路径检索外部资源,例如文本文件、XML 文件、属性文件或图像文件等。
  • ApplicationStartupAware:实现该接口的对象可以获取到一个 ApplicationStartup 对象,这个比较新,是 Spring 5.3 中新推出的,通过 ApplicationStartup 可以标记应用程序启动期间的步骤,并收集有关执行上下文或其处理时间的数据。
  • NotificationPublisherAware:实现该接的对象可以获取到一个 NotificationPublisher 对象,通过该对象可以实现通知的发送。
  • EnvironmentAware:实现该接口的对象可以获取到一个 Environment 对象,通过 Environment 可以获取到容器的环境信息。
  • BeanFactoryAware:实现该接口的对象可以获取到一个 BeanFactory 对象,通过 BeanFactory 可以完成 Bean 的查询等操作。
  • ImportAware:实现该接口的对象可以获取到一个 AnnotationMetadata 对象,ImportAware 接口是需要和 @Import 注解一起使用的。在 @Import 作为元注解使用时,通过 @Import 导入的配置类如果实现了 ImportAware 接口就可以获取到导入该配置类接口的数据配置。
  • EmbeddedValueResolverAware:实现该接口的对象可以获取到一个 StringValueResolver 对象,通过 StringValueResolver 对象,可以读取到 Spring 容器中的 properties 配置的值(YAML 配置也可以)。
  • ServletConfigAware:实现该接口的对象可以获取到一个 ServletConfig 对象,不过这个似乎没什么用,我们很少自己去配置 ServletConfig。
  • LoadTimeWeaverAware:实现该接口的对象可以获取到一个 LoadTimeWeaver 对象,通过该对象可以获取加载 Spring Bean 时织入的第三方模块,如 AspectJ 等。
  • BeanClassLoaderAware:实现该接口的对象可以获取到一个 ClassLoader 对象,ClassLoader 能干嘛不需要我多说了吧。
  • BeanNameAware:实现该接口的对象可以获取到一个当前 Bean 的名称。
  • ApplicationContextAware:实现该接口的对象可以获取到一个 ApplicationContext 对象,通过 ApplicationContext 可以获取容器中的 Bean、环境等信息。

这是 Spring 中提供的一堆 Aware。

接下来松哥随便写个例子大家来看下 Aware 的用法。

2. BeanFactoryAware

实现该接口的对象可以获取到一个 BeanFactory 对象,通过 BeanFactory 可以完成 Bean 的查询等操作。这算是一个比较常见的 Aware 了,我们一起来看下。

这里为了省事,我就在 Spring Boot 中来和大家演示。

首先我们来定义一个简单的 UserService:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Service
public class UserService {
    public void hello() {
        System.out.println("hello javaboy!");
    }
}

然后提供一个工具类:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Component
public class BeanUtils implements BeanFactoryAware {
    private static BeanFactory beanFactory = null;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        BeanUtils.beanFactory = beanFactory;
    }

    public static <T> T getBean(String beanName) {
        return (T) beanFactory.getBean(beanName);
    }
}

有了这个工具类,接下来我们就可以在一个非 Spring 管理的 Bean 中,随时随地的查询 Bean 了,像下面这样:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
UserService userService = BeanUtils.getBean("userService");
userService.hello();

3. TienChin 项目实践

为什么会有今天这篇文章呢?主要是在松哥最近做的 TienChin 项目中,有一个地方涉及到这块知识点了,但是有的小伙伴不熟悉,因此就拎出来和大家梳理下。

在 TienChin 项目中,在记录日志的时候,因为日志是一个延迟任务,所以提前准备好了相关的 Bean 已经注册到 Spring 容器中了,像下面这样:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Configuration
public class ThreadPoolConfig {

    /**
     * 执行周期性或定时任务
     */
    @Bean(name = "scheduledExecutorService")
    protected ScheduledExecutorService scheduledExecutorService() {
        return new ScheduledThreadPoolExecutor(corePoolSize,
                new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build(),
                new ThreadPoolExecutor.CallerRunsPolicy()) {
            @Override
            protected void afterExecute(Runnable r, Throwable t) {
                super.afterExecute(r, t);
                Threads.printException(r, t);
            }
        };
    }
}
@Component
public final class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware {
    /**
     * Spring应用上下文环境
     */
    private static ConfigurableListableBeanFactory beanFactory;

    private static ApplicationContext applicationContext;

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        SpringUtils.beanFactory = beanFactory;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringUtils.applicationContext = applicationContext;
    }

    /**
     * 获取对象
     *
     * @param name
     * @return Object 一个以所给名字注册的bean的实例
     * @throws org.springframework.beans.BeansException
     */
    @SuppressWarnings("unchecked")
    public static <T> T getBean(String name) throws BeansException {
        return (T) beanFactory.getBean(name);
    }

    /**
     * 获取类型为requiredType的对象
     *
     * @param clz
     * @return
     * @throws org.springframework.beans.BeansException
     */
    public static <T> T getBean(Class<T> clz) throws BeansException {
        T result = (T) beanFactory.getBean(clz);
        return result;
    }
}

而写日志的异步任务工具类,并非一个容器,所以要通过这个工具类获取相应的 Bean,如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class AsyncManager {
    /**
     * 操作延迟10毫秒
     */
    private final int OPERATE_DELAY_TIME = 10;

    /**
     * 异步操作任务调度线程池
     */
    private ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService");

    /**
     * 单例模式
     */
    private AsyncManager() {
    }

    private static AsyncManager me = new AsyncManager();

    public static AsyncManager me() {
        return me;
    }

    /**
     * 执行任务
     *
     * @param task 任务
     */
    public void execute(TimerTask task) {
        executor.schedule(task, OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS);
    }
}

有了 SpringUtils 我们就可以在一个非 Spring 容器所管理的 Bean 中,获取到 Spring 容器中的 Bean 了。

在 TienChin 项目视频中,我也会和大家详细聊一聊这块,视频戳这里:TienChin 项目配套视频来啦

just this。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-06-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 江南一点雨 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
面试官:展开说说,Spring中Bean对象是如何通过注解注入的?
你听过扰动函数吗?你写过斐波那契(Fibonacci)散列吗?你实现过梅森旋转算法吗?怎么 没听过这些写不了代码吗!不会的,即使没听过你一样可以写的了代码,比如你实现的数据库路由数据总是落在1库1表它不散列分布、你实现的抽奖系统总是把运营配置的最大红包发出去提高了运营成本、你开发的秒杀系统总是在开始后的1秒就挂了货品根本给不出去。
小傅哥
2021/08/04
8320
面试官:展开说说,Spring中Bean对象是如何通过注解注入的?
不一样的视角来学习Spring源码之容器与Bean---下
此时容器中只有一个Bean,显然config配置类的注解都没有被解析,此时就需要添加工厂后置处理器来解析这些注解了,从而可以往容器中添加更多的bean的定义信息
大忽悠爱学习
2022/05/10
2360
不一样的视角来学习Spring源码之容器与Bean---下
【小家Spring】一文读懂Spring中的BeanFactory和FactoryBean(以及它和ObjectFactory的区别)的区别
开始重视这个问题,源自一次阿里巴巴的二面面试题:说说你对Spring中BeanFactory的理解,它和FactoryBean有什么区别呢?
YourBatman
2019/09/03
5K0
面经手册 · 第29篇《Spring IOC 特性有哪些,不会读不懂源码!》
为什么这些无论从书本、课堂、面试都显得非常重要的知识,但是在实际的编程中没有提升你的编码能力呢?
小傅哥
2021/04/12
3240
面试官:Spring中获取Bean有几种方式?
5、使用Spring提供的工具类WebApplicationContextUtils
田维常
2022/11/25
9470
面试官:Spring中获取Bean有几种方式?
《Spring 手撸专栏》第 15 章:万人之敌,通过注解给属性注入配置和Bean对象
你听过扰动函数吗?你写过斐波那契(Fibonacci)散列吗?你实现过梅森旋转算法吗?怎么 没听过这些写不了代码吗!不会的,即使没听过你一样可以写的了代码,比如你实现的数据库路由数据总是落在1库1表它不散列分布、你实现的抽奖系统总是把运营配置的最大红包发出去提高了运营成本、你开发的秒杀系统总是在开始后的1秒就挂了货品根本给不出去。
小傅哥
2021/08/20
6020
《Spring 手撸专栏》第 15 章:万人之敌,通过注解给属性注入配置和Bean对象
手写Spring,定义标记类型Aware接口,实现感知容器对象
大佬的代码,就像 “赖蛤蟆泡青蛙,张的丑玩的花” :一个类实现了多个接口、继承的类又继承了其他类、接口还可以和接口继承、实现接口的抽象类再由类实现抽象类方法、类A继承的类B实现了类A实现的接口C,等等。
小傅哥
2021/06/29
6970
手写Spring,定义标记类型Aware接口,实现感知容器对象
spring中这些能升华代码的技巧,可能会让你爱不释手
最近越来越多的读者认可我的文章,还是件挺让人高兴的事情。有些读者私信我说希望后面多分享spring方面的文章,这样能够在实际工作中派上用场。正好我对spring源码有过一定的研究,并结合我这几年实际的工作经验,把spring中我认为不错的知识点总结一下,希望对您有所帮助。
苏三说技术
2021/01/20
1.2K0
【死磕 Spring】----- IOC 之 深入分析 BeanPostProcessor
Spring 作为优秀的开源框架,它为我们提供了丰富的可扩展点,除了前面提到的 Aware 接口,还包括其他部分,其中一个很重要的就是 BeanPostProcessor。这篇文章主要介绍 BeanPostProcessor 的使用以及其实现原理。我们先看 BeanPostProcessor 的定位:
用户1655470
2019/01/02
1.3K0
Spring 获取bean的八种方式
适合于Spring框架的B/S系统,通过ServletContext对象获取ApplicationContext对象。然后在通过它获取须要的类实例。以下两个工具方式的差别是,前者在获取失败时抛出异常。后者返回null。
小石头
2022/12/21
8670
《Spring 手撸专栏》第 9 章:虎行有雨,定义标记类型Aware接口,实现感知容器对象
大佬的代码,就像“赖蛤蟆泡青蛙,长的丑玩的花”:一个类实现了多个接口、继承的类又继承了其他类、接口还可以和接口继承、实现接口的抽象类再由类实现抽象类方法、类A继承的类B实现了类A实现的接口C,等等。
小傅哥
2021/07/23
3240
如何让 Bean 深度感知 Spring 容器
TienChin 视频杀青啦~采用 Spring Boot+Vue3 技术栈,里边会涉及到各种好玩的技术,小伙伴们来和松哥一起做一个完成率超 90% 的项目,戳戳戳这里-->TienChin 项目配套视频来啦。
江南一点雨
2023/11/05
2210
如何让 Bean 深度感知 Spring 容器
Java工具集-Spring工具(获取Spring容器中的Bean对象)
引入依赖 <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>5.1.9.RELEASE</version> </dependency> 代码示例 package *; import org.springframework.beans.BeansEx
cwl_java
2019/10/26
1.5K0
Spring - BeanFactoryAware扩展接口
扩展点方法为setBeanFactory,可以拿到BeanFactory这个属性。
小小工匠
2022/12/05
4890
Spring - BeanFactoryAware扩展接口
这一次搞懂Spring的Bean实例化原理
前两篇文章分析了Spring XML和注解的解析原理,并将其封装为BeanDefinition对象存放到IOC容器中,而这些只是refresh方法中的其中一个步骤——obtainFreshBeanFactory,接下来就将围绕着这些BeanDefinition对象进行一系列的处理,如BeanDefinitionRegistryPostProcessor对象方法的调用、BeanFactoryPostProcessor对象方法的调用以及Bean实例的创建都离不开这些BeanDefinition对象。下面就来看看Spring是如何处理这些对象的。
夜勿语
2020/09/07
8800
万能的BeanPostProcessor是如何让spring无限扩展的?
很多朋友一提到spring,首先想到的肯定是IOC(控制反转)和 AOP (面向切面编程),没错,这两个是spring的核心功能。但是什么技术让spring拥有如此强大的扩展能力,
苏三说技术
2020/10/15
2.3K0
万能的BeanPostProcessor是如何让spring无限扩展的?
不一样的视角来学习Spring源码之容器与Bean---上
Spring 的发展历史较为悠久,因此很多资料还在讲解它较旧的实现,这里出于怀旧的原因,把它们都列出来,供大家参考
大忽悠爱学习
2022/05/10
4680
不一样的视角来学习Spring源码之容器与Bean---上
Spring 源码系列之容器概览~
松哥原创的 Spring Boot 视频教程已经杀青,感兴趣的小伙伴戳这里-->Spring Boot+Vue+微人事视频教程
江南一点雨
2020/09/14
5290
SpringBoot集成WebSocket的基本实现
此时我们第一反应,前端定时使用HTTP协议调用后端接口,刷新界面。OK,需求实现,下班回家!
用户10714507
2023/10/08
1K0
Spring获取Bean的9种方式
随着SpringBoot的普及,Spring的使用也越来越广,在某些场景下,我们无法通过注解或配置的形式直接获取到某个Bean。比如,在某一些工具类、设计模式实现中需要使用到Spring容器管理的Bean,此时就需要直接获取到对应的Bean。
程序新视界
2023/01/14
2.2K0
推荐阅读
相关推荐
面试官:展开说说,Spring中Bean对象是如何通过注解注入的?
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文