今天临时加了个需求,我想着用 Spring 来装载,配合 localcache 这样就能做到无感在 web 启动的时候预先将需要的数据加载到内存中。以便于以后直接拿来使用,不用再次进行加载。
目录
ContextLoaderListener和ContextLoaderServlet
Spring提供ApplicationContext多种实现机制
解决初始化ApplicationContext 为null的问题
ApplicationContextAware 初始化
通过它Spring容器会自动把上下文环境对象调用ApplicationContextAware接口中的setApplicationContext方法,我们在ApplicationContextAware的实现类中,就可以通过这个上下文环境对象得到Spring容器中的Bean。
它实现的方法大体可以分为 4 步走:
- 实现ApplicationContextAware接口;
- Spring 容器装载并调用 set 方法;
- webxml 配置中配置 Listener;
- 使用getBean方法。
接下来我会一一讲解,并简单说下,我遇到的 ApplicationContext 为 null 是怎么造成的。
实现ApplicationContextAware 接口
先上工具类(util),这个工具类还是比较常见的,一百度一大把。
package com.csdn.imenger.utils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* 装载Spring 应用上下文 工具类
*
* @author imenger
* @date 2021/1/21 5:31 下午
*/
@Component
public class SpringContextUtil implements ApplicationContextAware {
private static ApplicationContext context;
/**
* Set the ApplicationContext that this object runs in.
* Normally this call will be used to initialize the object.
* <p>Invoked after population of normal bean properties but before an init callback such
* as {@link InitializingBean#afterPropertiesSet()}
* or a custom init-method. Invoked after {@link ResourceLoaderAware#setResourceLoader},
* {@link ApplicationEventPublisherAware#setApplicationEventPublisher} and
* {@link MessageSourceAware}, if applicable.
*
* @param applicationContext the ApplicationContext object to be used by this object
* @throws ApplicationContextException in case of context initialization errors
* @throws BeansException if thrown by application context methods
* @see BeanInitializationException
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public static ApplicationContext getContext() {
return context != null ? context : null;
}
public static Object getBean(String name) {
return context.getBean(name);
}
}
我这里是实现 ApplicationContextAware 后直接 override 了 setApplicationContext 这个方法,idea 会自动将注释加上。
简单的翻译一下注释:
设置该对象在其中运行的ApplicationContext。通常,此调用将用于初始化该对象。
在填充正常的bean属性之后但在初始化回调(例如InitializingBean.afterPropertiesSet()或自定义init方法InitializingBean.afterPropertiesSet()之前调用。 在ResourceLoaderAware.setResourceLoader , ApplicationEventPublisherAware.setApplicationEventPublisher和MessageSourceAware之后调用(如果适用)。这里就用到了我上一篇文章中说的生命周期。
Spring 容器装载并调用 set 方法
在Spring的配置文件中配置这个类,Spring容器会在加载完Spring容器后把上下文对象调用这个对象中的setApplicationContext方法:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<bean id="SpringContextUtil" class="com.csdn.imenger.utils.SpringContextUtil"></bean>
<context:component-scan base-package="com.csdn.imenger.utils"/>
</beans>
webxml 配置中配置 Listener
在web项目中的web.xml中配置加载Spring容器的Listener:
<!-- 初始化Spring容器,让Spring容器随Web应用的启动而自动启动 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
这个 listener 呢是一般只要开发 web 就要写的,后期我会根据 spring 实战中详细介绍,这里不做过多叙述。
使用getBean方法
在项目中即可通过这个SpringContextUtil调用getBean()方法得到Spring容器中的对象了。
比如:
WoainiService niyeaiwoService = (WoainiService) SpringContextUtil.getBean("woainiService");
return niyeaiwoService.getlove();
ApplicationContext 加载机制
ContextLoaderListener和ContextLoaderServlet
加载器目前有两种选择:ContextLoaderListener和ContextLoaderServlet
这两者在功能上完全等同,只是一个是基于Servlet2.3版本中新引入的Listener接口实现 而另一个基于Servlet接口实现。
开发中可根据目标Web容器的实际情况进行选择。
配置非常简单,第一种在web.xml中增加:
<!-- 初始化Spring容器,让Spring容器随Web应用的启动而自动启动 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
第二种:
<servlet>
<servlet-name>context</servlet-name>
<servlet-class>
org.springframework.web.context.ContextLoaderServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
通过以上配置,Web容器会自动加载/WEB-INF/applicationContext.xml初始化
ApplicationContext实例,如果需要指定配置文件位置,可通过context-param加以指定:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext-bean.xml,classpath:spring-jamon.xml </param-value>
</context-param>
Spring提供ApplicationContext多种实现机制
这里不做过多介绍,上篇文章中提及过,
实战Spring容器(container)容纳你的Bean:https://blog.youkuaiyun.com/Soinice/article/details/112900824
解决初始化ApplicationContext 为null的问题
我这儿遇到的这个问题呢,是启动时就没装载到 spring 容器中,我认真核实之后,有两点造成的。
@Component注解
我刚开始没用这个注解,然后 也没写 装载 bean id,所以 spring 肯定不知道我写的这个是什么鬼,只是一个简简单单普普通通的 java util 而已。
后来我用了 @Component 注解,当然这个注解吧,你写或者不写问题都不大。
简单介绍一下这个注解:
说白了,他就是 上文中:<bean id="SpringContextUtil" class="com.csdn.imenger.utils.SpringContextUtil"></bean> 这句话。
@component (把普通pojo实例化到spring容器中,相当于配置文件中的<bean id="" class=""/>
)
- 泛指各种组件,就是说当做我们自己的类
<context:component-scan base-package=”com.*”>
<context:component-scan base-package="com.csdn.imenger.utils"/>
这是第二个问题,我的配置文件其是是有的,不过不知道啥时候被我隐藏了,我就有点难受了。不过还好,按着我上面的步骤一步一步排查,问题便解决了。
解决了,我就抓紧写篇文章记录一下。下班下班。bye