使用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