参考https://juejin.cn/post/7251780545972994108?searchId=2023091105493913AF7C1E3479BB943C80#heading-12
记录并补充
1.通过BeanFactoryAware
package com.toryxu.demo1.beans;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.stereotype.Component;
@Component
public class BeanFactoryHelper implements BeanFactoryAware {
private static BeanFactory beanFactory;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
BeanFactoryHelper.beanFactory = beanFactory;
}
public static Object getBean(String beanName) {
return beanFactory.getBean(beanName);
}
public static <T> T getBean(Class<T> requireType) {
return beanFactory.getBean(requireType);
}
}
2.获取启动时的ApplicationContext
存到静态对象里
@SpringBootApplication
public class Demo1Application {
public static void main(String[] args) {
var applicationContext = SpringApplication.run(Demo1Application.class, args);
}
}
3.继承ApplicationObjectSupport
需要声明为Bean
@Component
public class SpringContextUtil extends ApplicationObjectSupport {
public <T> T getBean(Class<T> requireType) {
ApplicationContext ac = getApplicationContext();
if (ac == null) return null;
return ac.getBean(requireType);
}
}
ApplicationObjectSupport继承了ApplicationContextAware,在容器创建完成后会执行setApplicationContext方法
4.继承WebApplicationObjectSupport
@Component
public class WebSpringContextUtil extends WebApplicationObjectSupport {
public <T> T getBean(Class<T> requireType) {
var applicationContext = getApplicationContext();
if (applicationContext == null) return null;
return applicationContext.getBean(requireType);
}
}
WebApplicationObjectSupport是extends ApplicationObjectSupport的
5.WebApplicationContextUtils
public class SpringContextUtil2 {
public <T> T getBean(ServletContext sc, Class<T> requireType) {
var webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(sc);
return webApplicationContext.getBean(requireType);
}
}
Web项目中通过ServletContext获取Bean。
@RequestMapping("/test/{beanName}")
public void test(HttpServletRequest request,@PathVariable("beanName") String beanName){
System.out.println("test");
var servletContext = request.getServletContext();
var webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
var bean = webApplicationContext.getBean(beanName);
}
6.通过ApplicationContextAware
public class SpringContextUtil3 implements ApplicationContextAware {
private static ApplicationContext ac;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ac = applicationContext;
}
}
7.通过ContextLoader(废弃)
public <T> T getBean(Class<T> requireType) {
var currentWebApplicationContext = ContextLoader.getCurrentWebApplicationContext();
return currentWebApplicationContext.getBean(requireType);
}
ContextLoader中维护了一个Context类加载器和ac的映射关系
通过当前线程获取当前类加载器,从而获得ac。
/**
* Obtain the Spring root web application context for the current thread
* (i.e. for the current thread's context ClassLoader, which needs to be
* the web application's ClassLoader).
* @return the current root web application context, or {@code null}
* if none found
* @see org.springframework.web.context.support.SpringBeanAutowiringSupport
*/
@Nullable
public static WebApplicationContext getCurrentWebApplicationContext() {
ClassLoader ccl = Thread.currentThread().getContextClassLoader();
if (ccl != null) {
WebApplicationContext ccpt = currentContextPerThread.get(ccl);
if (ccpt != null) {
return ccpt;
}
}
retu
@CallerSensitive
public ClassLoader getContextClassLoader() {
ClassLoader cl = this.contextClassLoader;
if (cl == null) {
return null;
} else {
if (!isSupportedClassLoader(cl)) {
cl = ClassLoader.getSystemClassLoader();
}
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
Class<?> caller = Reflection.getCallerClass();
ClassLoader.checkClassLoaderPermission(cl, caller);
}
return cl;
}
}
ServletContextListener:
通过ServletContextListener,监听到contextInitialized事件,执行initWebApplicationContext方法,创建context并建立映射关系
一般都是在SSM项目中,需要配置web.xml才行,springboot项目中不会执行SpringBootServletInitializer .startUp方法
现在的项目中是获取不到该值的。
8.通过BeanFactoryPostprocessor
public class SpringContextUtil4 implements BeanFactoryPostProcessor {
private static ConfigurableListableBeanFactory beanFactory;
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
public <T> T getBean(Class<T> requireType) {
return beanFactory.getBean(requireType);
}
}
9.直接获取容器中的ApplicationContext
@Autowired
private ApplicationContext applicationContext;
@RequestMapping("/test/{beanName}")
public void test(HttpServletRequest request,@PathVariable("beanName") String beanName){
System.out.println("test");
applicationContext.getBean(beanName);
}
总结:
从容器中获取Bean的方式主要在启动时将ApplicationContext(BeanFactory的子接口)或者BeanFactory放进static变量中
其中又主要通过:
1.BeanFactoryAware
2.ApplicationContextAware(建议)
3.BeanFactoryPostProcessor
4.构造方法或者autowired/resource注解获取
1、3都是获取BeanFactory不建议
默认就直接从容器中拿applicationContext就可以了
当我们的对象不在容器中时,要获取applicationContext的话,就只能先搞一个Utils将applicationContext拿到并通过静态资源的形式放进去,这个时候就需要用到ApplicationContextAware。