SpringBoot ApplicationContextAware拓展接口使用详解

近日沉醉于熟悉公司新项目的过程,不断地接触新的应用场景与实现技术,对于我是一种学不来的进步,实践是检验真理的唯一标准。我们今天就浅浅的谈一谈springboot提供的16个拓展接口之一的ApplicationContextAware接口的应用场景与实际作用!

ApplicationContextAware接口:

public interface ApplicationContextAware extends Aware {
    void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}

首先Aware接口就知道这是springboot扩展给用户使用的,这里提供了方法setApplicationContext,参数就是传递spring容器上下文对象进来,我们可以接收这个上下文对象,我们要想知道获取spring容器上下文ApplicationContext具体有什么作用,这才是扩展接口的目的所在,获取上下文根据上下文的特性做一些事情。

我们来看ApplicationContext对象的方法:

来看看AbstractApplicationContext实现类的方法:

    public Object getBean(String name) throws BeansException {this.assertBeanFactoryActive();return this.getBeanFactory().getBean(name);}
    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {this.assertBeanFactoryActive();return this.getBeanFactory().getBean(name, requiredType);}
    public Object getBean(String name, Object... args) throws BeansException {this.assertBeanFactoryActive();return this.getBeanFactory().getBean(name, args);}
    public <T> T getBean(Class<T> requiredType) throws BeansException {this.assertBeanFactoryActive();return this.getBeanFactory().getBean(requiredType);}
    public <T> T getBean(Class<T> requiredType, Object... args) throws BeansException {this.assertBeanFactoryActive();return this.getBeanFactory().getBean(requiredType, args);}
    public <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType) {this.assertBeanFactoryActive();return this.getBeanFactory().getBeanProvider(requiredType);}
    public <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType) {this.assertBeanFactoryActive();return this.getBeanFactory().getBeanProvider(requiredType);}
    public boolean containsBean(String name) {return this.getBeanFactory().containsBean(name);}
    public boolean isSingleton(String name) throws NoSuchBeanDefinitionException {this.assertBeanFactoryActive();return this.getBeanFactory().isSingleton(name);}
    public boolean isPrototype(String name) throws NoSuchBeanDefinitionException {this.assertBeanFactoryActive();return this.getBeanFactory().isPrototype(name);}

这里我们可以发现 getBean()方法很眼熟,因为在最最开始学习spring时没有用spring的脚手架创建项目,我们获取bean的方法通常是classPathContextLoader扫描bean的xml文件解析组成ApplicationCOntext对象,再调用它的getBean方法获取实例bean。

由此可以发现我们主要的应用途径就是使用这个getBean的方法,那么动态的注入bean我们通过很多方法就能实现,所以这里不难想到,静态方法中无法使用注入的bean的问题。

其次我们来复现这个问题,大家来看如下的代码:

public class JsonGetter {
@Resource
private UuidGetter uuidGetter;
public static string Test(){
       return uuidGetter.getUuid();
}
public static JsONobject set0bjectToJsonObject(object data){
       return JsoNobject.parseObject(String.valueof(JsONObject.toJSON(data)));
}
public static JsONObject setStringTO3son0bject(String data) { return JsONObject.parseObject(data);
}

我们发现在静态的Test方法中调用注入的bean直接报错,这里解释一下:归功于类的加载机制与加载顺序,静态属性与静态代码块最先加载(static静态优先),这里加载静态方法是没有bean实例给你用的,自然会报错。

如何解决?我们可以采取Spring获取bean对象时调用getBean方法的思路,在容器加载时将spring容器的上下文进行静态存储:

@Component
@Lazy(value = false)
public class SpringContextHolder implements ApplicationContextAware, DisposableBean {
    /**
     * 将上下文静态设置,在初始化组件时就进行静态上下文的覆盖(这个覆盖是将远spring容器的上下文对象引用加到我们预定设置)
     */
    private static ApplicationContext applicationContext = null;
    public static ApplicationContext getApplicationContext() {
        assertContextInjected();
        return applicationContext;
    }
    @SuppressWarnings("unchecked")
    public static <T> T getBean(String name) {
        assertContextInjected();
        return (T) applicationContext.getBean(name);
    }
    public static  <T> T getBean(Class<T> beanType) {
        assertContextInjected();
        return applicationContext.getBean(beanType);
    }
    @Override
    public void setApplicationContext(@NotNull ApplicationContext applicationContext) throws BeansException {
        SpringContextHolder.applicationContext = applicationContext;
    }
    @Override
    public void destroy() {
        applicationContext = null;
    }
    private static void assertContextInjected() {
        Assert.notNull(applicationContext,
                "applicationContext属性未注入, 请在applicationContext.xml中定义SpringContextHolder.");
    }
    public static void pushEvent(ApplicationEvent event){
        assertContextInjected();
        applicationContext.publishEvent(event);
    }
}

这里只需要关注的是静态成员变量ApplicationContext的定义、赋值与验证:

    /**
     * 将上下文静态设置,在初始化组件时就进行静态上下文的覆盖(这个覆盖是将远spring容器的上下文对象引用加到我们预定设置)
     */
    private static ApplicationContext applicationContext = null;

重写扩展接口的方法,实现静态上下文的覆盖:

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

将获取它的方法公有修饰,便于共享:

    public static ApplicationContext getApplicationContext() {
        assertContextInjected();
        return applicationContext;
    }

写到这里还是不明白,这么定义一个组件,将spring上下文对象静态覆盖到底有何作用?

不要慌,我们来看看这个类的这个方法:

public class AppContext {
    static transient ThreadLocal<Map<String, String>> contextMap = new ThreadLocal<>();
    ......省略n行业务代码
    public static void fillLoginContext() {
        DingAppInfo appInfo = SpringContextHolder.getBean(DingAppInfoService.class).findAppInfo(APP_CODE);
        setDingVerifyInfo(appInfo);
        CloudChatAppInfo cloudChatAppInfo = SpringContextHolder.getBean(CloudChatAppInfoService.class).findAppInfo(APP_CODE);
        setCloudChatInfo(cloudChatAppInfo);
    }
    public static void clear() {
        contextMap.remove(); //本地线程的remove方法极其重要,注意每次给它使用之后一定要调用remove清理,防止内存泄露。
    }
}

我们发现上例代码中进行了查库的操作:

DingAppInfo appInfo = SpringContextHolder.getBean(DingAppInfoService.class).findAppInfo(APP_CODE);

这里是不是就解决了最初我们的问题?

实现了扩展applicationContextAware接口,解决静态方法无法获取bean实例调用其方法的问题?

到此这篇关于SpringBoot ApplicationContextAware拓展接口使用详解的文章就介绍到这了,更多相关SpringBoot ApplicationContextAware内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • springboot项目配置context path失效的问题解决

    目录 前言 现象 解决办法 前言 最近搭建的springbootboot的网关,配置请求路径,竟然没有生效 现象 配置文件如下: 启动类,控制台打印的结果如下: 我随便更换端口都可以生效,就是配置文件的:/api始终无法加载 解决办法 网关本身没有contextPath,通过自己转发自己,达到能处理contextPath 到此这篇关于springboot项目配置context path失效的问题解决的文章就介绍到这了,更多相关springboot配置context path失效内容请搜索我们以前

  • Spring容器-BeanFactory和ApplicationContext使用详解

    目录 将BeanFactory和ApplicationContext作为容器使用 BeanFactory容器 ApplicationContext容器 Spring内嵌Web容器的过程 将BeanFactory和ApplicationContext作为容器使用 在Spring中,BeanFactory和ApplicationContext是容器的两种实现方式,可以使用它们来管理对象的生命周期以及实现依赖注入等功能.下面我们来分别演示一下BeanFactory和ApplicationContext

  • Spring中ApplicationContextAware的使用方法详解

    ApplicationContextAware 通过它Spring容器会自动把上下文环境对象调用ApplicationContextAware接口中的setApplicationContext方法. 我们在ApplicationContextAware的实现类中,就可以通过这个上下文环境对象得到Spring容器中的Bean. 看到—Aware就知道是干什么的了,就是属性注入的,但是这个ApplicationContextAware的不同地方在于,实现了这个接口的bean,当spring容器初始化

  • SpringBoot微信消息接口配置详解

    1.申请测试号,并记录appID和appsecret 2.关注测试号 3.添加消息模板 {{topic.DATA}} 用户名: {{user.DATA}} 单车编号:{{car.DATA}} 锁定时间:{{date.DATA}} {{remark.DATA}} 微信接口配置和代码 1.添加微信配置文件 import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframe

  • Springboot实现动态定时任务流程详解

    目录 一.静态 二.动态 1.基本代码 2.方案详解 2.1 初始化 2.2 单次执行 2.3 停止任务 2.4 启用任务 三.小结 一.静态 静态的定时任务可以直接使用注解@Scheduled,并在启动类上配置@EnableScheduling即可 @PostMapping("/list/test1") @Async @Scheduled(cron = "0 * * * * ?") public void test1() throws Exception { Ob

  • springboot与mybatis整合实例详解(完美融合)

    简介 从 Spring Boot 项目名称中的 Boot 可以看出来,Spring Boot 的作用在于创建和启动新的基于 Spring 框架的项目.它的目的是帮助开发人员很容易的创建出独立运行和产品级别的基于 Spring 框架的应用.Spring Boot 会选择最适合的 Spring 子项目和第三方开源库进行整合.大部分 Spring Boot 应用只需要非常少的配置就可以快速运行起来. Spring Boot 包含的特性如下: 创建可以独立运行的 Spring 应用. 直接嵌入 Tomc

  • SpringBoot整合Shiro的代码详解

    shiro是一个权限框架,具体的使用可以查看其官网 http://shiro.apache.org/  它提供了很方便的权限认证和登录的功能. 而springboot作为一个开源框架,必然提供了和shiro整合的功能!接下来就用springboot结合springmvc,mybatis,整合shiro完成对于用户登录的判定和权限的验证. 1.准备数据库表结构 这里主要涉及到五张表:用户表,角色表(用户所拥有的角色),权限表(角色所涉及到的权限),用户-角色表(用户和角色是多对多的),角色-权限表

  • springboot配置内存数据库H2教程详解

    业务背景:因soa系统要供外网访问,处于安全考虑用springboot做了个前置模块,用来转发外网调用的请求和soa返回的应答.其中外网的请求接口地址在DB2数据库中对应专门的一张表来维护,要是springboot直接访问数据库,还要专门申请权限等,比较麻烦,而一张表用内置的H2数据库维护也比较简单,就可以作为替代的办法. 环境:springboot+maven3.3+jdk1.7 1.springboot的Maven工程结构 说明一下,resource下的templates文件夹没啥用.我忘记

  • SpringBoot整合MongoDB的步骤详解

    项目结构: 1.pom引入mongodb依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency> 2 配置application.properties #spring.data.mongodb.host=127.0.0.1 #spr

  • springBoot整合rabbitMQ的方法详解

    引入pom <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0

  • springboot项目配置swagger2示例详解

    swagger简介 Swagger是一款RESTful接口的文档在线自动生成.功能测试功能框架.一个规范和完整的框架,用于生成.描述.调用和可视化RESTful风格的Web服务,加上swagger-ui,可以有很好的呈现. 当我们在后台的接口修改了后,swagger可以实现自动的更新,而不需要人为的维护这个接口进行测试. 一.swagger2中常用的注解作用 注解 作用 @Api 修饰整个类,描述Controller的作用 ,表示标识这个类是swagger的资源 @ApiOperation 描述

  • SpringBoot解析yml全流程详解

    目录 背景 加载监听器 执行run方法 加载配置文件 封装Node 调用构造器 思考 背景 前几天的时候,项目里有一个需求,需要一个开关控制代码中是否执行一段逻辑,于是理所当然的在yml文件中配置了一个属性作为开关,再配合nacos就可以随时改变这个值达到我们的目的,yml文件中是这样写的: switch: turnOn: on 程序中的代码也很简单,大致的逻辑就是下面这样,如果取到的开关字段是on的话,那么就执行if判断中的代码,否则就不执行: @Value("${switch.turnOn}

  • Springboot通过lucene实现全文检索详解流程

    目录 建立索引 检索文档 Lucene提供了一个简单却强大的应用程序接口(API),能够做全文索引和搜寻,在Java开发环境里Lucene是一个成熟的免费开放源代码工具. Lucene全文检索就是对文档中全部内容进行分词,然后对所有单词建立倒排索引的过程.主要操作是使用Lucene的API来实现对索引的增(创建索引).删(删除索引).改(修改索引).查(搜索数据). 假设我们的电脑的目录中含有很多文本文档,我们需要查找哪些文档含有某个关键词.为了实现这种功能,我们首先利用 Lucene 对这个目

随机推荐