在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