在spring上下文中获取bean

使用spring技术的web应用中,如何在程序中获取Spring上下文ApplicationContext,有两种方式:

1:实现ApplicationContextAware接口(实现此接口的setApplicationContext方法),在web应用中,spring会在启动时加载springContext上下文,spring的配置文件中配置了<context:component-scan/>会扫描配置了@Component注解的类,当扫描到实现了ApplicationContextAware接口的类时,spring启动线程会自动调用此类中的setApplicationContext方法,这样就可以将spring上下文注入到此类中的成员变量中(假设此变量的名称为applicationContext)。

使用main方法测试此类时,可以使用ClassPathXmlApplicationContext的构造器去加载spring上下文,然后让spring的启动线程去走完上述流程。web.xml的加载顺序是context-param->Listener(一般这里配置的spring的Listener接口即ContextLoaderListener)->filter->servlet(springmvc作为第一个Servlet加载),先加载tomcat中的ServletContext,再加载spring上下文,再加载springmvc上下文。spring的加载配置文件的机制:在web.xml中配置listen-class:org.springframework.web.context.ContextLoaderListener,此类是spring容器的入口,此接口有contextInitialized方法(初始化 root web application context)和contextDestroyed方法(销毁the root web application context).在项目启动时在ContextLoader的initWebApplicationContext的方法中打断点,此时的servletContext对象中的context是org.apache.catalina.core.ApplicationContext,继续走是使用WebappClassLoader去加载XmlWebApplicationContext上下文,继续走到BeanUtils.instantiateClass方法中使用clazz.getDeclaredConstructor()来获取一个默认构造器,后面过程略过。

@Component
public class SpringContextHolder implements ApplicationContextAware {
	
	private static ApplicationContext applicationContext;

	private volatile static int i = 0 ;

	// 实现ApplicationContextAware接口的context注入函数, 将其存入静态变量.
	public synchronized void setApplicationContext(ApplicationContext applicationContext) {
		System.out.println("i : " + (++i));
		SpringContextHolder.applicationContext = applicationContext;
	}

	// 取得存储在静态变量中的ApplicationContext.
	public static ApplicationContext getApplicationContext() {
		checkApplicationContext();
		return applicationContext;
	}

	// 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.
	@SuppressWarnings("unchecked")
	public static <T> T getBean(String name) {
		checkApplicationContext();
		return (T) applicationContext.getBean(name);

	}

	public static Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType) {
		checkApplicationContext();
		return applicationContext.getBeansWithAnnotation(annotationType);
	}

	// 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.
	// 如果有多个Bean符合Class, 取出第一个.
	@SuppressWarnings("unchecked")
	public static <T> T getBean(Class<T> clazz) {
		checkApplicationContext();
		@SuppressWarnings("rawtypes")
		Map beanMaps = applicationContext.getBeansOfType(clazz);
		if (beanMaps != null && !beanMaps.isEmpty()) {
			return (T) beanMaps.values().iterator().next();
		} else {
			return null;
		}
	}

	public static <T> Map<String, T> getBeanMap(Class<T> clazz) {
		checkApplicationContext();
		return applicationContext.getBeansOfType(clazz);
	}

	private static void checkApplicationContext() {
		if (applicationContext == null) {
			throw new IllegalStateException("applicaitonContext未注入,请在applicationContext.xml中定义SpringContextHolder");
		}
	}
	
	public static void main(String[] args) {
		applicationContext = new ClassPathXmlApplicationContext("cfg-spring/spring-application.xml");
		Map<String, Object> map = SpringContextHolder.getBeansWithAnnotation(InitService.class);
		Iterator<Map.Entry<String, Object>> iter = map.entrySet().iterator();
		while(iter.hasNext()){
			Entry<String, Object> next = iter.next();
			System.out.println(next.getKey() + " : " + next.getValue());
		}
	}

 2:继承ApplicationObjectSupport(直接在当前类中使用this.getApplicationContext())

例如:Map<String, Object> map = this.getApplicationContext().getBeansWithAnnotation(InitService.class) 直接中map中获取对应注解(InitService)值的class

猜你喜欢

转载自cc-weige.iteye.com/blog/2380659