一、背景
建立一个全局拦截器LoginFilter,它继承了Filter,web应用启动的顺序是:listener->filter->servlet,而因为项目应用了spring mvc,所以我们会有一个配置文件(applixationContext.xml),我们在配置spring时会用到spring的listener,它会读取applicationContext.xml里的配置对spring context进行初始化;项目启动时,先初始化listener,因此配置在applicationContext.xml里的bean会被初始化和注入;然后再来就filter的初始化,再接着才到我们的dispathServlet的初始化,因此,当我们需要在filter里注入一个注解的bean时,就会注入失败,因为filter初始化时,注解的bean还没初始化,没法注入。
二、方案
1、新建ClosableApplicationContextAware类保存applicationContext对象
@Service
public class ClosableApplicationContextAware implements ApplicationContextAware{
private static Logger LOGGER = LoggerFactory.getLogger(ClosableApplicationContextAware.class);
private static ApplicationContext applicationContextStatic;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
applicationContextStatic = applicationContext;
}
public ApplicationContext getApplicationContext() {
return applicationContextStatic;
}
public static Object getBean(String beanName) {
return applicationContextStatic.getBean(beanName);
}
public static <T>T getBean(Class<T> clazz) {
return applicationContextStatic.getBean(clazz);
}
}
2、新建ClosableApplication类
1)@PostConstruct:如果想在生成对象时完成某些初始化操作,而偏偏这些初始化操作又依赖于依赖注入,那么就无法在构造函数中实现。为此,可以使用@PostConstruct注解一个方法来完成初始化,@PostConstruct注解的方法将会在依赖注入完成后被自动调用。
Constructor >> @Autowired >> @PostConstruct
2)ConfigurableApplicationContext:此接口结合了所有ApplicationContext需要实现的接口,它在ApplicationContext的基础上增加了一系列配置应用上下文的功能。配置应用上下文和控制应用上下文生命周期的方法在此接口中被封装起来,以免客户端程序直接使用。
3)registerShutdownHook():向JVM注册一个回调函数,用以在JVM关闭时,销毁此应用上下文。
public class ClosableApplication {
@Autowired
ClosableApplicationContextAware applicationContextAware;
private static Logger LOGGER = LoggerFactory.getLogger(ClosableApplication.class);
@PostConstruct
public void init() {
LOGGER.info("ClosableApplication init");
ApplicationContext applicationContext = applicationContextAware.getApplicationContext();
if (applicationContext instanceof ConfigurableApplicationContext) {
((ConfigurableApplicationContext)applicationContext).registerShutdownHook();
}
}
}
3、在applicationContext.xml中添加
<bean class="com.dami.ClosableApplication" init-method="init" lazy-init="false"> </bean>
4、LoginFileter类调用
public class LoginFilter implements Filter {
private UserService userService;
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
userService = ClosableApplicationContextAware.getBean(UserService.class);
}
}
注:原文作者测试了四个方案,本文只摘取了成功的方案,如果想了解测试失败了的方案,请点下面的链接去看原文。
本文转载自:https://blog.csdn.net/xiao__jia__jia/article/details/102468865