Spring Bean的获取方式

发布于:2023-09-14 ⋅ 阅读:(136) ⋅ 点赞:(0)

参考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。