场景一 : 拦截器中
原因:
Spring框架中的拦截器是在容器启动时就进行实例化的;
在Spring框架中,拦截器的实例化和配置是通过拦截器配置类(Interceptor Configuration Class)完成的。拦截器配置类是一个专门用于配置拦截器的类,通常使用@Configuration
注解进行标记。
在拦截器配置类中,可以使用@Bean
注解来创建拦截器的实例,并进行配置。这样一来,拦截器就成为了Spring容器中的一个Bean,可以由Spring管理。
当容器启动时,会读取拦截器配置类,并实例化其中的拦截器Bean。这意味着拦截器可以在容器启动之后的任何时候被使用,而不需要等待Bean实例化。
因此,通过在拦截器配置类中实例化拦截器,并将其纳入Spring容器的管理,可以确保在需要时拦截器可以被正确地使用,并且可以进行依赖注入等操作。
解决方法:
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
/**实例化拦截器 创建拦截器的实例*/
@Bean
public UserLoginInterceptor getUserLoginInterceptor() {
return new UserLoginInterceptor();
}
/**
* 注册自定义拦截器
* @param registry ·
*/
String[] strs = new String[]{
"/error",
"/IM/login/**"
};
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(getUserLoginInterceptor())
.addPathPatterns("/**") // 拦截地址
.excludePathPatterns(strs);// 开放登录路径
}
}
场景二: 在非Spring管理的类中获取Spring容器中的Bean
比如再Netty中,以及一些工具类中
原因:
在非Spring管理的类中获取Spring容器中的Bean
解决方法:
1. 先创建一个SpringUtils
的类; 通过这个类拿到Spring中的bean;
@Repository
public class SpringUtils implements BeanFactoryPostProcessor {
//Spring应用上下文环境
private static ConfigurableListableBeanFactory beanFactory;
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
SpringUtils.beanFactory = beanFactory;
}
public static ConfigurableListableBeanFactory getBeanFactory() {
return beanFactory;
}
/**
* 获取对象
*
* @param name
* @return Object 一个以所给名字注册的bean的实例
* @throws org.springframework.beans.BeansException
*
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) throws BeansException {
return (T) getBeanFactory().getBean(name);
}
/**
* 获取类型为requiredType的对象
*
* @param clz
* @return
* @throws org.springframework.beans.BeansException
*
*/
public static <T> T getBean(Class<T> clz) throws BeansException {
T result = (T) getBeanFactory().getBean(clz);
return result;
}
/**
* 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true
*
* @param name
* @return boolean
*/
public static boolean containsBean(String name) {
return getBeanFactory().containsBean(name);
}
/**
* 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException)
*
* @param name
* @return boolean
* @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
*
*/
public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
return getBeanFactory().isSingleton(name);
}
/**
* @param name
* @return Class 注册对象的类型
* @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
*
*/
public static Class<?> getType(String name) throws NoSuchBeanDefinitionException {
return getBeanFactory().getType(name);
}
/**
* 如果给定的bean名字在bean定义中有别名,则返回这些别名
*
* @param name
* @return
* @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
*
*/
public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {
return getBeanFactory().getAliases(name);
}
}
2. 在非Spring类中这样注入:
private StringRedisTemplate stringRedisTemplate = SpringUtils.getBean(StringRedisTemplate.class);
原理:
SpringUtils
实现了BeanFactoryPostProcessor
接口,这是Spring框架提供的一个扩展点接口。通过实现该接口,SpringUtils
可以在Spring容器加载Bean定义后,在Bean实例化之前对BeanFactory进行后置处理。
这个类的主要目的是提供一些静态方法,用于方便地访问和操作Spring容器中的BeanFactory。下面是一些主要方法的解释:
-
postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
: 这个方法是BeanFactoryPostProcessor
接口的实现方法。在Spring容器加载Bean的定义后,会调用该方法,并传入beanFactory
作为参数。SpringUtils
将这个beanFactory
赋值给自己的静态变量beanFactory
,以便后续的静态方法可以使用它。 -
getBeanFactory()
: 这个静态方法返回beanFactory
,即Spring容器中的BeanFactory实例。其他静态方法可以通过调用这个方法来获取BeanFactory实例。 -
getBean(String name)
: 这个静态方法用于根据给定的名称获取对应的Bean实例。它通过调用getBeanFactory().getBean(name)
来实现,在Spring容器中查找并返回匹配名称的Bean实例。 -
getBean(Class<T> clz)
: 这个静态方法用于根据给定的类型获取对应的Bean实例。它通过调用getBeanFactory().getBean(clz)
来实现,在Spring容器中查找并返回匹配类型的Bean实例。 -
其他方法,如
containsBean(String name)
、isSingleton(String name)
、getType(String name)
和getAliases(String name)
,提供了一些额外的功能,用于判断Bean是否存在、获取Bean的类型和别名等。
通过使用SpringUtils
类,可以在任何需要访问Spring容器中的Bean的地方,方便地获取和操作Bean实例。