Spring ApplicationContext 简介
ApplicationContext是对BeanFactory的扩展,实现BeanFactory的所有功能,并添加了事件传播,国际化,资源文件处理等。
configure locations:(CONFIG_LOCATION_DELIMITERS = ",; \t\n" )分割多个配置文件。
refresh()执行所有逻辑。
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }
prepareRefresh():准备需要刷新的资源。
/** * Prepare this context for refreshing, setting its startup date and * active flag as well as performing any initialization of property sources. */ protected void prepareRefresh() { this.startupDate = System.currentTimeMillis(); //启动日期 this.closed.set(false); //激活标志 this.active.set(true); //激活标志 if (logger.isInfoEnabled()) { logger.info("Refreshing " + this); } // Initialize any placeholder property sources in the context environment initPropertySources(); //供扩展使用 // Validate that all properties marked as required are resolvable // see ConfigurablePropertyResolver#setRequiredProperties getEnvironment().validateRequiredProperties(); // Allow for the collection of early ApplicationEvents, // to be published once the multicaster is available... this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>(); }
initPropertySources()扩展使用如下:
class MyACTX extends ClassPathXmlApplicationContext { @Override protected void initPropertySources() { super.initPropertySources(); //TODO } }
一般不直接实现ApplicationContext(过多接口),可以继承ClassPathXmlApplicationContext类,然后重写相应的方法。做相关操作。
加载BeanFactory:ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(),(原有功能==配置读取,解析...)。
prepareBeanFactory():
/** * Configure the factory's standard context characteristics, * such as the context's ClassLoader and post-processors. * @param beanFactory the BeanFactory to configure */ protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { // Tell the internal bean factory to use the context's class loader etc. beanFactory.setBeanClassLoader(getClassLoader()); //表达式语言处理器,Spring3 SpEL表达式,#{xx.xx}支持。 beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); //属性编辑器支持 如处理Date注入 beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())); // Configure the bean factory with context callbacks. beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); //忽略自动装配的接口 beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); beanFactory.ignoreDependencyInterface(MessageSourceAware.class); beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); beanFactory.ignoreDependencyInterface(EnvironmentAware.class); // BeanFactory interface not registered as resolvable type in a plain factory. // MessageSource registered (and found for autowiring) as a bean. //设置自动装配规则 beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); beanFactory.registerResolvableDependency(ResourceLoader.class, this); beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this); beanFactory.registerResolvableDependency(ApplicationContext.class, this); // Detect a LoadTimeWeaver and prepare for weaving, if found. //AspectJ支持 if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); // Set a temporary ClassLoader for type matching. beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } // Register default environment beans. if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment()); } if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties()); } if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment()); } }
SpEL:Spring Expression Language,运行时构造复杂表达式,存取对象图属性,对象方法调用等。SpEL为单独模块,只依赖于core模块。
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="driverClassName" value="${dataSource.driverClassName}"/>
<property name="url" value="${dataSource.url}"/>
<property name="username" value="${dataSource.username}"/>
<property name="password" value="${dataSource.password}"/>
<property name="maxActive" value="${dataSource.maxActive}"/>
<property name="minIdle" value="${dataSource.minIdle}" />
<property name="initialSize" value="${dataSource.initialSize}"></property>
<property name="validationQuery" value="${dataSource.validationQuery}"/>
</bean>
PropertyEditor:自定义属性编辑器。
Spring中Date类型无法注入,需要注册相应的属性编辑器来做处理。Spring处理自定义属性编辑器类
org.springframework.beans.factory.config.CustomEditorConfigurer
/** * {@link BeanFactoryPostProcessor} implementation that allows for convenient * registration of custom {@link PropertyEditor property editors}. * 注册 * */ public class CustomEditorConfigurer implements BeanFactoryPostProcessor, Ordered { protected final Log logger = LogFactory.getLog(getClass()); private int order = Ordered.LOWEST_PRECEDENCE; // default: same as non-Ordered private PropertyEditorRegistrar[] propertyEditorRegistrars; private Map<Class<?>, Class<? extends PropertyEditor>> customEditors; ... ...
通过注册propertyEditorRegistrars或者customEditors。
customEditors(推荐):
自定义Date属性编辑器MyDateEditor: class MyDateEditor extends PropertyEditorSupport { private String format = "yyyy-MM-dd"; public void setFormat(String format){ this.format = format; } @Override public void setAsText(String text) throws IllegalArgumentException { SimpleDateFormat sp = new SimpleDateFormat(format); try{ this.setValue(sp.parse(text)); } catch (ParseException e) { e.printStackTrace(); } } } 配置: <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer"> <property name="customEditors"> <map> <entry key="java.util.Date"> <bean class="com.xxx.MyDateEditor"> <property name="format" value="yyyy-MM-dd HH:mm:ss"/> </bean> </entry> </map> </property> </bean>
propertyEditorRegistrars:
自定义Date EditorRegister: class MyDateRegister implements PropertyEditorRegistrar{ private String format = "yyyy-MM-dd"; public void setFormat(String format){ this.format = format; } @Override public void registerCustomEditors(PropertyEditorRegistry registry) { registry.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat(format), true)); } } 配置: <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer"> <property name="propertyEditorRegistrars"> <list> <bean class="com.xxx.MyDateRegister"> <property name="format" value="yyyy-MM-dd HH:mm:ss"/> </bean> </list> </property> </bean>
属性编辑器应用于Bean实例化属性填充阶段。
invokeBeanFactoryPostProcessors():容器级别的bean后置处理。
典型应用:PropertyPlaceholderConfigure。
PlaceholderConfigurerSupport extends PropertyResourceConfigurer .. implements BeanFactoryPostProcessor,间接实现BeanFactoryPostProcessor,会在BeanFacty载入bean配置之后进行属性文件的处理 :mergeProperties、convertProperties、processProperties,供后续bean的实例化使用。
可以注册自定义的BeanFactoryPostProcessor。
initMessageSource():初始化消息资源,国际化应用。
两个message资源文件message_en.properties, message_zh_CN.properties。
添加Spring配置:messageSource id固定。
<!-- 国际化资源文件 -->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<value>lang/message</value>
</property>
</bean>
读取:
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring/lang-resource.xml"); String msg = ctx.getMessage("xxx", null, Locale.CHINA); System.out.println(msg);
nitApplicationEventMulticaster():
/** * Add beans that implement ApplicationListener as listeners. * Doesn't affect other listeners, which can be added without being beans. */ protected void registerListeners() { // Register statically specified listeners first. for (ApplicationListener<?> listener : getApplicationListeners()) { getApplicationEventMulticaster().addApplicationListener(listener); } // Do not initialize FactoryBeans here: We need to leave all regular beans // uninitialized to let post-processors apply to them! String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false); for (String listenerBeanName : listenerBeanNames) { getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName); } // Publish early application events now that we finally have a multicaster... Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents; this.earlyApplicationEvents = null; if (earlyEventsToProcess != null) { for (ApplicationEvent earlyEvent : earlyEventsToProcess) { getApplicationEventMulticaster().multicastEvent(earlyEvent); } } }
... ...