時間:2023-03-15來源:系統城裝機大師作者:佚名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
public void refresh() throws BeansException, IllegalStateException { synchronized ( this .startupShutdownMonitor) { // 1. 初始化前的預處理 this .prepareRefresh(); // 2. 刷新Bean工廠 ConfigurableListableBeanFactory beanFactory = this .obtainFreshBeanFactory(); // 3. BeanFactory的預處理配置 this .prepareBeanFactory(beanFactory); try { // 4. BeanFactory的后置處理 this .postProcessBeanFactory(beanFactory); // 5. 執行BeanFactory后置處理器 this .invokeBeanFactoryPostProcessors(beanFactory); // 6. 注冊Bean的后置處理器 this .registerBeanPostProcessors(beanFactory); // 7. 初始化MessageSource this .initMessageSource(); // 8. 初始化事件派發器 this .initApplicationEventMulticaster(); // 9. 子類的多態onRefresh this .onRefresh(); // 10. 注冊監聽器 this .registerListeners(); // 11. 初始化所有剩下的單例Bean this .finishBeanFactoryInitialization(beanFactory); // 12. 完成容器的創建工作 this .finishRefresh(); } catch (BeansException var9) { if ( this .logger.isWarnEnabled()) { this .logger.warn( "Exception encountered during context initialization - cancelling refresh attempt: " + var9); } this .destroyBeans(); this .cancelRefresh(var9); throw var9; } finally { // 13. 清除緩存 this .resetCommonCaches(); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
protected void prepareRefresh() { //設置容器啟動時間 this .startupDate = System.currentTimeMillis(); //設置容器關閉狀態為false this .closed.set( false ); //設置容器激活狀態為true this .active.set( true ); if ( this .logger.isDebugEnabled()) { if ( this .logger.isTraceEnabled()) { this .logger.trace( "Refreshing " + this ); } else { this .logger.debug( "Refreshing " + this .getDisplayName()); } } //1.1初始化屬性資源 this .initPropertySources(); //1.2校驗 this .getEnvironment().validateRequiredProperties(); this .earlyApplicationEvents = new LinkedHashSet(); } |
初始化方法是個模壓方法,由子類重寫
1 2 |
protected void initPropertySources() { } |
Web容器GenericWebApplicationContext重寫了此方法
1 2 3 4 5 6 7 8 |
protected void initPropertySources() { //獲取環境信息 ConfigurableEnvironment env = getEnvironment(); //判斷是否是web配置環境 if (env instanceof ConfigurableWebEnvironment) { ((ConfigurableWebEnvironment) env).initPropertySources( this .servletContext, null ); } } |
最終由StandardServletEnvironment進行初始化
1 2 3 4 |
public void initPropertySources( @Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) { //使用web容器工具初始化 WebApplicationContextUtils.initServletPropertySources(getPropertySources(), servletContext, servletConfig); } |
把 Servlet 的一些初始化參數放入IOC容器中
1 2 3 4 5 6 7 8 9 10 11 |
public static void initServletPropertySources(MutablePropertySources sources, @Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) { Assert.notNull(sources, "'propertySources' must not be null" ); String name = "servletContextInitParams" ; if (servletContext != null && sources.contains(name) && sources.get(name) instanceof StubPropertySource) { sources.replace(name, new ServletContextPropertySource(name, servletContext)); } name = "servletConfigInitParams" ; if (servletConfig != null && sources.contains(name) && sources.get(name) instanceof StubPropertySource) { sources.replace(name, new ServletConfigPropertySource(name, servletConfig)); } } |
通過占位符解析器校驗資源集合
1 2 3 |
public void validateRequiredProperties() throws MissingRequiredPropertiesException { this .propertyResolver.validateRequiredProperties(); } |
這里的解析器作為常量在環境被實例化時就被創建出來的,PropertySourcesPropertyResolver是占位符解析器,將數據源中占位符替換成目標值
校驗是否有需要被占位符修飾的屬性,如果有但是資源中找不到對應屬性的key就會拋出異常
1 2 3 4 5 6 7 8 9 10 11 |
public void validateRequiredProperties() { MissingRequiredPropertiesException ex = new MissingRequiredPropertiesException(); for (String key : this .requiredProperties) { if ( this .getProperty(key) == null ) { ex.addMissingRequiredProperty(key); } } if (!ex.getMissingRequiredProperties().isEmpty()) { throw ex; } } |
案例: 資源文件
1 2 3 4 |
name=zhansan age=${name}, 10 encoding=utf- 8 name2=${name} |
測試代碼
1 2 3 4 5 6 7 8 |
@Test public void test1() throws Exception { //省略propertySources PropertyResolver propertyResolver = new PropertySourcesPropertyResolver(getPropertySources()); System.out.println(propertyResolver.getProperty( "age" )); System.out.println(propertyResolver.getProperty( "encoding" )); System.out.println(propertyResolver.resolvePlaceholders( "must be encoding ${encoding}" )); //輸出must be encoding gbk } |
輸出結果
10,zhansan
utf-8
must be encoding utf-8
1 2 3 4 5 |
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { //2.1刷新Bean工廠 refreshBeanFactory(); return getBeanFactory(); } |
將容器刷新標識改為true,并且設置了工廠序列化id
1 2 3 4 5 6 7 |
protected final void refreshBeanFactory() throws IllegalStateException { if (! this .refreshed.compareAndSet( false , true )) { throw new IllegalStateException( "GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once" ); } this .beanFactory.setSerializationId(getId()); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { // 設置BeanFactory的類加載器、表達式解析器等 beanFactory.setBeanClassLoader(getClassLoader()); beanFactory.setBeanExpressionResolver( new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); beanFactory.addPropertyEditorRegistrar( new ResourceEditorRegistrar( this , getEnvironment())); // 3.1 添加Aware執行器 beanFactory.addBeanPostProcessor( new ApplicationContextDProcessor( this )); beanFactory.ignoreDependencyInterface(EnvironmentAware. class ); beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware. class ); beanFactory.ignoreDependencyInterface(ResourceLoaderAware. class ); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware. class ); beanFactory.ignoreDependencyInterface(MessageSourceAware. class ); beanFactory.ignoreDependencyInterface(ApplicationContextAware. class ); // 3.2 自動注入的支持 beanFactory.registerResolvableDependency(BeanFactory. class , beanFactory); beanFactory.registerResolvableDependency(ResourceLoader. class , this ); beanFactory.registerResolvableDependency(ApplicationEventPublisher. class , this ); beanFactory.registerResolvableDependency(ApplicationContext. class , this ); // 3.3 添加監聽器執行器 beanFactory.addBeanPostProcessor( new ApplicationListenerDetector( this )); // Detect a LoadTimeWeaver and prepare for weaving, if found. 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()); } } |
ApplicationContextDProcessor實現了BeanPostProcessor的postProcessBeforeInitialization接口,在所有Bean初始化前會執行當前方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { //判斷Bean是Aware的子類 if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware || bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware || bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){ return bean; } AccessControlContext acc = null ; if (System.getSecurityManager() != null ) { acc = this .applicationContext.getBeanFactory().getAccessControlContext(); } if (acc != null ) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { invokeAwareInterfaces(bean); return null ; }, acc); } else { //回調執行Aware接口 invokeAwareInterfaces(bean); } return bean; } |
如果當前Bean是Aware的子類,那么將Bean強轉成Aware類型,通過回調將信息設置到Bean中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
private void invokeAwareInterfaces(Object bean) { 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); } } |
如果過容器中有多個相同接口的實現類,那么在自動注入的時候會注入注冊的實現類
1 2 3 4 |
beanFactory.registerResolvableDependency(BeanFactory. class , beanFactory); beanFactory.registerResolvableDependency(ResourceLoader. class , this ); beanFactory.registerResolvableDependency(ApplicationEventPublisher. class , this ); beanFactory.registerResolvableDependency(ApplicationContext. class , this ); |
ApplicationListenerDetector主要作用是添加和銷毀監聽器,實現了BeanPostProcessor的postProcessAfterInitialization(Bean實例化之后)方法和DestructionAwareBeanPostProcessor的postProcessBeforeDestruction(Bean銷毀之前)方法
詳情:https://www.jb51.net/article/277948.htm
這是個模壓方法,由子類AnnotationConfigServletWebServerApplicationContext實現
1 2 |
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { } |
AnnotationConfigServletWebServerApplicationContext首先調了父類 ServletWebServerApplicationContext 的 postProcessBeanFactory 方法
1 2 3 4 5 6 7 8 9 10 11 |
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { //4.1后置處理Bean工廠 super .postProcessBeanFactory(beanFactory); if ( this .basePackages != null && this .basePackages.length > 0 ) { //basePackages為空不會執行 this .scanner.scan( this .basePackages); } if (! this .annotatedClasses.isEmpty()) { this .reader.register(ClassUtils.toClassArray( this .annotatedClasses)); } } |
父類ServletWebServerApplicationContext首先向Bean工廠中注入了一個執行器
1 2 3 4 5 6 7 |
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { //4.1.1注入執行器 beanFactory.addBeanPostProcessor( new WebApplicationContextServletContextAwareProcessor( this )); beanFactory.ignoreDependencyInterface(ServletContextAware. class ); //4.1.2注冊作用域 registerWebApplicationScopes(); } |
WebApplicationContextServletContextAwareProcessor繼承了ServletContextAwareProcessor
ServletContextAwareProcessor繼承了BeanPostProcessor實現了postProcessBeforeInitialization(Bean初始化前執行)
1 2 3 4 5 6 7 8 9 10 11 |
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { //注入ServletContext if (getServletContext() != null && bean instanceof ServletContextAware) { ((ServletContextAware) bean).setServletContext(getServletContext()); } //注入ServletConfig if (getServletConfig() != null && bean instanceof ServletConfigAware) { ((ServletConfigAware) bean).setServletConfig(getServletConfig()); } return bean; } |
1 2 3 4 5 6 |
// 所在類及方法:ServletWebServerApplicationContext#registerWebApplicationScopes private void registerWebApplicationScopes() { ExistingWebApplicationScopes existingScopes = new ExistingWebApplicationScopes(getBeanFactory()); WebApplicationContextUtils.registerWebApplicationScopes(getBeanFactory()); existingScopes.restore(); } |
ExistingWebApplicationScopes是ServletWebServerApplicationContext類中的一個靜態類
源碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
public static class ExistingWebApplicationScopes { static { Set<String> scopes = new LinkedHashSet<>(); scopes.add(WebApplicationContext.SCOPE_REQUEST); scopes.add(WebApplicationContext.SCOPE_SESSION); SCOPES = Collections.unmodifiableSet(scopes); } // 這是構造方法,大概就是根據SCOPES獲取beanFactory中已經注冊的scope,然后放入scopes // 需要注意的是,在上面的方法中,第二行才在向beanFactory中注冊,也就是這時的beanFactory里面沒有request和session這兩個scop // 所以這里就完成了beanFactory的賦值。建議打斷點進去看看 public ExistingWebApplicationScopes(ConfigurableListableBeanFactory beanFactory) { this .beanFactory = beanFactory; for (String scopeName : SCOPES) { Scope scope = beanFactory.getRegisteredScope(scopeName); if (scope != null ) { this .scopes.put(scopeName, scope); } } } // 由于上面的方法并沒有值存入scopes,所以這里也就沒執行里面的內容 public void restore() { this .scopes.forEach((key, value) -> { if (logger.isInfoEnabled()) { logger.info( "Restoring user defined scope " + key); } this .beanFactory.registerScope(key, value); }); } } |
WebApplicationContextUtils.registerWebApplicationScopes(),這個方法就是向beanFactory注冊web的scope了,源碼如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory) { registerWebApplicationScopes(beanFactory, null ); } public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory, @Nullable ServletContext sc) { // 注冊作用域 beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope()); // 注冊request SCOP beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope()); // 注冊session SCOP if (sc != null ) { ServletContextScope appScope = new ServletContextScope(sc); beanFactory.registerScope(WebApplicationContext.SCOPE_APPLICATION, appScope); // 注冊application SCOP // Register as ServletContext attribute, for ContextCleanupListener to detect it. sc.setAttribute(ServletContextScope. class .getName(), appScope); } // 添加依賴項 beanFactory.registerResolvableDependency(ServletRequest. class , new RequestObjectFactory()); beanFactory.registerResolvableDependency(ServletResponse. class , new ResponseObjectFactory()); beanFactory.registerResolvableDependency(HttpSession. class , new SessionObjectFactory()); beanFactory.registerResolvableDependency(WebRequest. class , new WebRequestObjectFactory()); if (jsfPresent) { FacesDependencyRegistrar.registerFacesDependencies(beanFactory); } } |
以上就是Spring refresh()源碼解析的詳細內容
2023-03-15
Keil uVision5 5.38官方下載、安裝及注冊超詳細圖文教程2023-03-11
Jmeter如何將每次測試的結果保存到文件中2023-03-11
Jmeter測試時遇到的各種亂碼問題及解決mediaDevices 的介紹 我們這里用到getUserMedia 的 api 把獲取到的 stream 用一個 video 來展示 樣式部分 陰影的設置 完整代碼...
2023-03-09