如何从ApplicationContext获取被Spring托管的bean对象

如何从ApplicationContext获取被Spring托管的bean对象

项目中有时需要从spring容器中获取bean或者获取ApplicationContext。下面提供两种方法:

- 方法1、创建一个实现ApplicationContextAware接口的bean,交由spring托管

// 将bean交由spring托管
@Component
public class ApplicationContextHolder implements ApplicationContextAware, DisableBean {
	private static ApplicationContext applicationContext = null;
	// 自动获取applicationContext
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        ApplicationContextHolder.applicationContext = applicationContext;
    }
    // 自动销毁
    @Override
    public void destroy() {
        ApplicationContextHolder.applicationContext = null;
    }
	
	// 根据bean类型获取bean
	public static <T> T getBean(CLass<T> clazz) {
		return applicationContext.getBean(clazz);
	}

	// 根据bean名称获取bean
	public static <T> T getBean(String name) {
		return applicationContext.getBean(name);
	}
	
	// 根据bean名称和类型获取bean
	public static <T> T getBean(String name, Class<T> clazz) {
		return applicationContext.getBean(name, clazz);
	}
}

重点是1.实现ApplicationContextAware;2.利用@Component等注解将此bean交由spring托管。之后spring在初始化这个ApplicationContextHolder的bean时,会调用ApplicationContextAwareProcessor的方法postProcessBeforeInitialization()。spring的源码注释如下:

@Override
@Nullable
// 初始化一个bean,创建完bean后会调用此方法进行后处理
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
	AccessControlContext acc = null;
	// 判断如果开启了安全模式,就获取安全的控制上下文,默认不开启,if条件为false
	if (System.getSecurityManager() != null &&
			(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
					bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
					bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
		acc = this.applicationContext.getBeanFactory().getAccessControlContext();
	}
	// 不开启安全模式,acc = null
	if (acc != null) {
		AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
			invokeAwareInterfaces(bean);
			return null;
		}, acc);
	}
	else {
		// 调用bean的自省
		invokeAwareInterfaces(bean);
	}
	return bean;
}

// 如果bean实现了下列自省接口,调用接口方法,否则不做操作
private void invokeAwareInterfaces(Object bean) {
	if (bean instanceof Aware) {
		if (bean instanceof EnvironmentAware) {
			((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
		}
		if (bean instanceof EmbeddedValueResolverAware) {
			((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
		}
		if (bean instanceof ResourceLoaderAware) {
			((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
		}
		if (bean instanceof ApplicationEventPublisherAware) {
			((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
		}
		if (bean instanceof MessageSourceAware) {
			((MessageSourceAware) bean).setMessageSource(this.applicationContext);
		}
		if (bean instanceof ApplicationContextAware) {
			((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
		}
	}
}

由此可见在invokeAwareInterfaces()方法中,ApplicationContextHolder实现了ApplicationContextAware,所以会自动调用setApplicationContext(),由此就可以获得Spring的上下文ApplicationContext。就可以从其中获取被spring托管的bean。

- 方法2、利用Spring的事件通知机制
在Spring的上下文ApplicationContext被初始化和刷新时会触发Spring的内置事件ContextRefreshedEvent,因此可以创建一个Listener监听此事件,当ApplicationContext被初始化和刷新时,获取ApplicationContext。

public enum ApplicationContextHolder{
    INSTANCE;

    private ApplicationContext applicationContext;

    public ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }
    
	// 根据bean类型获取bean
	public <T> T getBean(Class<T> clazz) {
		return applicationContext.getBean(clazz);
	}

	// 根据bean名称获取bean
	public <T> T getBean(String name) {
		return (T) applicationContext.getBean(name);
	}
	
	// 根据bean名称和类型获取bean
	public static <T> T getBean(String name, Class<T> clazz) {
		return applicationContext.getBean(name, clazz);
	}
}

// 将监听器交由spring托管,否则不生效,无法监听到事件执行onApplicationEvent
@Component
public class StartupListener implements ApplicationListener<ContextRefreshedEvent> {
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {           
    	ApplicationContextHolder.INSTANCE.setApplicationContext(event.getApplicationContext());
    }
}

重点是1.实现ApplicationListener创建监听器;2.利用@Component等注解将StartupListener监听器交由spring托管。当applicationContext被初始化或刷新时,spring会触发ContextRefreshedEvent事件,监听器StartupListener监听到事件后,执行onApplicationEvent()方法。

你可能感兴趣的:(Web开发遇到的问题,spring,java,后端,spring,boot)