在实际的项目中,在使用spring注解的方式管理bean时,只能通过注解或者配置文件注入的方式获取相应的bean。但是在某些特殊情况下,我们需要在一个普通的JAVA类中获取由spring所管理的bean,一下是解决方法,实现接口ApplicationContextAware。
package com.example.demo.service;
import com.baomidou.mybatisplus.core.toolkit.ArrayUtils;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
/**
* 以静态变量保存Spring ApplicationContext, 可在任何代码任何地方任何时候取出ApplicaitonContext.
*
* @author lst
* @date 2019-12-21 16:52
*/
@Service
@Lazy(false)
public class SpringContextHolder implements ApplicationContextAware, DisposableBean {
private static ApplicationContext applicationContext = null;
private static Logger logger = LoggerFactory.getLogger(SpringContextHolder.class);
/**
* 取得存储在静态变量中的ApplicationContext.
*/
public static ApplicationContext getApplicationContext() {
assertContextInjected();
return applicationContext;
}
/**
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) {
assertContextInjected();
return (T) applicationContext.getBean(name);
}
/**
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
public static <T> T getBean(Class<T> requiredType) {
assertContextInjected();
return applicationContext.getBean(requiredType);
}
/**
* 清除SpringContextHolder中的ApplicationContext为Null.
*/
public static void clearHolder() {
if (logger.isDebugEnabled()) {
logger.debug("清除SpringContextHolder中的ApplicationContext:" + applicationContext);
}
applicationContext = null;
}
/**
* 实现ApplicationContextAware接口, 注入Context到静态变量中.
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
SpringContextHolder.applicationContext = applicationContext;
}
/**
* 实现DisposableBean接口, 在Context关闭时清理静态变量.
*/
@Override
public void destroy() throws Exception {
SpringContextHolder.clearHolder();
}
/**
* 检查ApplicationContext不为空.
*/
private static void assertContextInjected() {
Validate.validState(applicationContext != null, "applicaitonContext属性未注入, 请在applicationContext.xml中定义SpringContextHolder.");
}
/**
* // 获取当前环境参数 exp: dev,prod,test
* @return
*/
public static String getActiveProfile() {
String[] profiles = SpringContextHolder.getApplicationContext().getEnvironment().getActiveProfiles();
if (!ArrayUtils.isEmpty(profiles)) {
return profiles[0];
}
return "";
}
}
以上的工具可以通过一下方式去获取。
private static DictMapper dictMapper = SpringContextHolder.getBean(DictMapper.class);
其实我们获取的Bean是从Spring容器中获取的,所以肯定要获取Spring上下文,即ApplicationContext。当然,首先我们编写的SpringContextHolder首先自身要被Spring管理,实现ApplicationContextAware、DisposableBean接口。这样在Spring加载的时候,会执行setApplicationContext方法将ApplicabletionContext注入到当前的SpringContextHolder的成员变量ApplicationContext ctx。这样就获取到了Spring上下文,后面动态获取Bean就方便了。
要注意的是,如果你获取的这个Bean是singleton的话(Spring默认的作用域),那该工具类获取的也是singleton,如果是prototype的话,Spring每次会跟你new一个出来。