Spring通过工具类实现获取容器中的Bean

 更新时间:2022年06月23日 15:18:44   作者:江南一点雨  
在实际开发中,我们往往要用到Spring容器为我们提供的诸多资源,例如想要获取到容器中的配置、获取到容器中的Bean等等。本文为大家详细讲讲工具类如何获取到Spring容器中的Bean,需要的可以参考一下

1. Aware 接口

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

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

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

/**
 * 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:

@Service
public class UserService {
    public void hello() {
        System.out.println("hello javaboy!");
    }
}

然后提供一个工具类:

@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 了,像下面这样:

UserService userService = BeanUtils.getBean("userService");
userService.hello();

3. TienChin 项目实践

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

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

@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,如下:

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 了。

到此这篇关于Spring通过工具类实现获取容器中的Bean的文章就介绍到这了,更多相关Spring获取Bean内容请搜索得牛网以前的文章或继续浏览下面的相关文章希望大家以后多多支持得牛网!

相关文章

  • 分布式面试分布式锁实现及应用场景

    分布式面试分布式锁实现及应用场景

    这篇文章主要为大家介绍了关于分布式的面试问题,分布式锁的实现及应用不同场景下的使用,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步
    2022-03-03
  • spring cloud gateway 全局过滤器的实现

    spring cloud gateway 全局过滤器的实现

    全局过滤器作用于所有的路由,不需要单独配置,我们可以用它来实现很多统一化处理的业务需求,这篇文章主要介绍了spring cloud gateway 全局过滤器的实现,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-03-03
  • Java之Pattern.compile函数用法详解

    Java之Pattern.compile函数用法详解

    这篇文章主要介绍了Java之Pattern.compile函数用法详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08
  • java实现的冒泡排序算法示例

    java实现的冒泡排序算法示例

    这篇文章主要介绍了java实现的冒泡排序算法,结合实例形式分析了冒泡排序算法的具体操作步骤与实现技巧,需要的朋友可以参考下
    2017-01-01
  • JavaWeb实体类转为json对象的实现方法

    JavaWeb实体类转为json对象的实现方法

    这篇文章主要介绍了JavaWeb实体类转为json对象的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12
  • 基于Spring MVC 简介及入门小例子(推荐)

    基于Spring MVC 简介及入门小例子(推荐)

    下面小编就为大家带来一篇基于Spring MVC 简介及入门小例子(推荐)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-06-06
  • Java之ThreadLocal使用常见和方式案例讲解

    Java之ThreadLocal使用常见和方式案例讲解

    这篇文章主要介绍了Java之ThreadLocal使用常见和方式案例讲解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08
  • Java中FTPClient上传中文目录、中文文件名乱码问题解决方法

    Java中FTPClient上传中文目录、中文文件名乱码问题解决方法

    这篇文章主要介绍了Java中FTPClient上传中文目录、中文文件名乱码问题解决方法,本文使用apache-commons-net工具包时遇到这个问题,解决方法很简单,需要的朋友可以参考下
    2015-05-05
  • 玩转SpringBoot中的那些连接池(小结)

    玩转SpringBoot中的那些连接池(小结)

    这篇文章主要介绍了玩转SpringBoot中的那些连接池(小结),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12
  • Java实现给Word文件添加文字水印

    Java实现给Word文件添加文字水印

    Word中设置水印时,可预设的文字或自定义文字设置为水印效果,但通常添加水印效果时,会对所有页面都设置成统一效果。本文将利用Java给Word每一页设置不同文字水印效果,需要的可以参考一下
    2022-02-02

最新评论