日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

功能扩展

發(fā)布時(shí)間:2025/7/14 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 功能扩展 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

在進(jìn)入函數(shù)prepareBeanFactory前,Spring已經(jīng)完成了對(duì)配置的解析,而ApplicationContext在功能上的擴(kuò)展也由此展開------也就是對(duì)BeanFactory進(jìn)行各種功能上的填充。

功能填充對(duì)BeanFactory

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {//設(shè)置BeanFactory的ClassLoader為當(dāng)前的Context的ClassLoader beanFactory.setBeanClassLoader(getClassLoader());//設(shè)置beanFactory的表達(dá)式語(yǔ)言處理器,Spring3增加了表達(dá)式語(yǔ)言的支持。默認(rèn)可以使用#{bean.xxxx}的形式來(lái)調(diào)用相關(guān)屬性值beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));//為BeanFactory增加了一個(gè)默認(rèn)的propertyEditor,這個(gè)主要是對(duì)bean的屬性等設(shè)置管理的一個(gè)工具beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));//添加BeanPostProcessorbeanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));//設(shè)置了幾個(gè)自動(dòng)裝配的接口beanFactory.ignoreDependencyInterface(EnvironmentAware.class);beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);beanFactory.ignoreDependencyInterface(MessageSourceAware.class);beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);//設(shè)置了幾個(gè)自動(dòng)裝配的特殊規(guī)則beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);beanFactory.registerResolvableDependency(ResourceLoader.class, this);beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);beanFactory.registerResolvableDependency(ApplicationContext.class, this);beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));// 增加對(duì)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()));}// 添加默認(rèn)的系統(tǒng)環(huán)境beanif (!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());}}

上面的函數(shù)主要進(jìn)行了幾個(gè)方面的擴(kuò)展:

(1)增加對(duì)SPEL語(yǔ)言的支持;

(2)增加對(duì)屬性編輯器的支持;

(3)增加一些內(nèi)置類,比如EnvironmentAware、MessageSourceAware的信息注入;

(4)設(shè)置了依賴功能可忽略的接口;

(5)注冊(cè)一些固定依賴的屬性;

(6)增加AspectJ的支持;

(7)將相關(guān)環(huán)境變量及屬性注冊(cè)以單例模式注冊(cè);

接下來(lái)我們對(duì)上述步驟進(jìn)行詳細(xì)的分析:

增加對(duì)SPEL語(yǔ)言的支持

Spring表達(dá)式語(yǔ)言全稱為“Spring Expression Language”,縮寫為SpEL,類似于Struts2中使用的OGNL表達(dá)式語(yǔ)言,能在運(yùn)行時(shí)構(gòu)建復(fù)雜表達(dá)式、存取對(duì)象圖屬性、對(duì)象方法調(diào)用等,并且能與Spring功能完美整合,比如能用來(lái)配置bean定義。SpEL是單獨(dú)模塊,只依賴于core模塊,不依賴與其他模塊,可以單獨(dú)使用。

SpEL使用#{...}來(lái)作為定界符,所有在大括號(hào)中的字符都會(huì)被認(rèn)為是SpEL,使用的方式如下:

<bean id="hero" class="com.joe.test.Hero/> <bean><property name= "instrument" value="#{hero}"/> </bean>

相當(dāng)于:

<bean id="hero" class="com.joe.test.Hero/> <bean><property name= "instrument" ref="hero"/> </bean>

當(dāng)然上面的例子只是最簡(jiǎn)單的使用方式,SpEL的功能非常強(qiáng)大,使用好可以大大的提高開發(fā)效率。

在源碼中通過beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver())注冊(cè)語(yǔ)言解析器,就可以對(duì)SpEL進(jìn)行解析了,那么在注冊(cè)解析器后Spring又是在什么時(shí)候調(diào)用這個(gè)解析器進(jìn)行解析的呢?

  之前在講述到Spring在bean進(jìn)行初始化的時(shí)候會(huì)有屬性填充這一步,而在這一步中Spring會(huì)調(diào)用AbstractAutowireCapableFactory類的applyPropertyValues函數(shù)完成此功能。就在這個(gè)函數(shù)中會(huì)通過構(gòu)造BeanDefinitionValuesResolver類型實(shí)例valueResolver來(lái)進(jìn)行屬性值的解析。同時(shí),也就是在這個(gè)步驟中一般通過AbstractBeanFactory中的evaluateBeanDefinitionString方法來(lái)完成SpEL的解析:

protected Object evaluateBeanDefinitionString(@Nullable String value, @Nullable BeanDefinition beanDefinition) {if (this.beanExpressionResolver == null) {return value;}Scope scope = null;if (beanDefinition != null) {String scopeName = beanDefinition.getScope();if (scopeName != null) {scope = getRegisteredScope(scopeName);}}return this.beanExpressionResolver.evaluate(value, new BeanExpressionContext(this, scope));}

  當(dāng)調(diào)用這個(gè)方法的時(shí)候會(huì)時(shí)候會(huì)首先判斷是否存在語(yǔ)言解析器,如果存在則調(diào)用語(yǔ)言解析器的方法進(jìn)行解析,解析的過程是在Spring的expression包內(nèi),我們通過evaluateBeanDefinitionString方法的調(diào)用層次來(lái)可以看出,應(yīng)用語(yǔ)言解析器的調(diào)用主要是在解析依賴注入bean的時(shí)候,以及在完成bean的初始化和屬性獲取后進(jìn)行屬性填充的時(shí)候。

增加屬性注冊(cè)編輯器

在Spring依賴注入的時(shí)候可以把普通的屬性注入進(jìn)來(lái),但是想Date類型就無(wú)法被識(shí)別。例如:

public class User {private Date date;public Date getDate() {return date;}public void setDate(Date date) {this.date = date;}@Overridepublic String toString() {return "date: " + date;}public static void main(String[] args){ApplicationContext ap = new ClassPathXmlApplicationContext("spring.xml");User user = (User) ap.getBean("user");System.out.println(user.toString());} } <bean id="user" class="com.joe.mytag.application.User"><property name="date" value="2019-01-03"></property></bean>

運(yùn)行測(cè)試方法:

Caused by: org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type 'java.lang.String' to required type 'java.util.Date' for property 'date'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'java.util.Date' for property 'date': no matching editors or conversion strategy foundat org.springframework.beans.AbstractNestablePropertyAccessor.convertIfNecessary(AbstractNestablePropertyAccessor.java:603)at org.springframework.beans.AbstractNestablePropertyAccessor.convertForProperty(AbstractNestablePropertyAccessor.java:615)at org.springframework.beans.BeanWrapperImpl.convertForProperty(BeanWrapperImpl.java:216)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.convertForProperty(AbstractAutowireCapableBeanFactory.java:1579)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1538)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1280)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553)... 11 more

發(fā)現(xiàn)報(bào)錯(cuò),發(fā)現(xiàn)是轉(zhuǎn)型失敗。因?yàn)樵赨ser中的data屬性是Date的,但是XML中配置的卻是String類型的,所以報(bào)錯(cuò)。

Spring針對(duì)此類問題提供了兩種解決方法:

(1)使用自定義屬性編輯器

  使用自定義的屬性編輯器,通過繼承PropertyEditorSupport,重寫了setAsText方法,具體的步驟如下:

首先編寫自定義的屬性編輯器

public class DatePropertyEditor extends PropertyEditorSupport {private String format = "yyyy-MM-dd";public void setFormat(String format) {this.format = format;}@Overridepublic void setAsText(String text) throws IllegalArgumentException {System.out.println("text:" + text);SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);try {Date date = simpleDateFormat.parse(text);this.setValue(date);}catch (Exception e){e.printStackTrace();}} }

再將自定義的屬性編輯器注冊(cè)到Spring中:

<bean class="com.joe.mytag.application.DatePropertyEditor" id ="date"><property name="format" value="yyyy-MM-dd"/></bean><bean class="org.springframework.beans.factory.config.CustomEditorConfigurer"><property name="customEditors"><map><entry key="java.util.Date"><ref bean="date"/></entry></map></property></bean>

在上述配置文件中引入類型為org.springframework.beans.factory.config.CustomEditorConfigurer的bean,并在屬性customEditors中假如到自定義的屬性編輯器中,其中key為屬性編輯器所對(duì)應(yīng)的類型。通過這樣的配置,當(dāng)Spring在注入bean的屬性的時(shí)候一旦遇到了java.util.Date類型的屬性會(huì)自動(dòng)調(diào)用自定義的DatePropertyEditor解析器進(jìn)行解析,并用解析結(jié)果代替配置屬性進(jìn)行注入。

但是,上述例子沒有成功。目前還不知道怎么回事?

(2)注冊(cè)Spring自帶的屬性編輯器CustomDateEditor

  通過注冊(cè)Spring自帶的屬性編輯器CustomDateEditor,具體的步驟如下:

定義屬性編輯器:

public class DatePropertyEditorRegister implements PropertyEditorRegistrar {@Overridepublic void registerCustomEditors(PropertyEditorRegistry propertyEditorRegistry) {propertyEditorRegistry.registerCustomEditor(Date.class,new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"),true));} }

注冊(cè)到Spring中:

<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer"><property name="propertyEditorRegistrars"><list><bean class="com.joe.mytag.application.DatePropertyEditorRegister"/></list></property></bean>

運(yùn)行上述的例子:

一月 03, 2019 4:32:02 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh 信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@5910e440: startup date [Thu Jan 03 16:32:02 CST 2019]; root of context hierarchy 一月 03, 2019 4:32:02 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 信息: Loading XML bean definitions from class path resource [spring.xml] date: Thu Jan 03 00:00:00 CST 2019

  通過在配置文件中將自定義的DatePropertyEditorRegister注冊(cè)進(jìn)入org.springframework.beans.factory.config.CustomEditorConfigurer的propertyEditorRegisters屬性中,可以跟第一個(gè)例子一樣的效果。

了解了自定義的屬性編輯器之后,但是,本節(jié)圍繞的核心代碼beanFactory.addPropertyEditorRegistrar(new ResourcesEditorRegistrar(this,getEnvironment()))并無(wú)聯(lián)系,因?yàn)樵谧?cè)自定義屬性編輯器的時(shí)候使用的是PropertyEditorRegistry的registerCustomEditor方法,而這里使用的是ConfigurableListableBeanFactory的addPropertyEditorRegistrar方法,來(lái)探索一下ResourcesEditorRegistrar的內(nèi)部實(shí)現(xiàn),其中我們最關(guān)心的就是registerCustomEditors方法:

protected void registerCustomEditors(PropertyEditorRegistry registry) {PropertyEditorRegistrySupport registrySupport =(registry instanceof PropertyEditorRegistrySupport ? (PropertyEditorRegistrySupport) registry : null);if (registrySupport != null) {registrySupport.useConfigValueEditors();}if (!this.propertyEditorRegistrars.isEmpty()) {for (PropertyEditorRegistrar registrar : this.propertyEditorRegistrars) {try {registrar.registerCustomEditors(registry);}catch (BeanCreationException ex) {Throwable rootCause = ex.getMostSpecificCause();if (rootCause instanceof BeanCurrentlyInCreationException) {BeanCreationException bce = (BeanCreationException) rootCause;String bceBeanName = bce.getBeanName();if (bceBeanName != null && isCurrentlyInCreation(bceBeanName)) {if (logger.isDebugEnabled()) {logger.debug("PropertyEditorRegistrar [" + registrar.getClass().getName() +"] failed because it tried to obtain currently created bean '" +ex.getBeanName() + "': " + ex.getMessage());}onSuppressedException(ex);continue;}}throw ex;}}}if (!this.customEditors.isEmpty()) {this.customEditors.forEach((requiredType, editorClass) ->registry.registerCustomEditor(requiredType, BeanUtils.instantiateClass(editorClass)));}}

?在doRegisterEditor函數(shù)中,可以看到咋之前提到的自定義屬性中使用的關(guān)鍵代碼:registry.registerCustomEditor(requiredTypr editor),回過頭來(lái)看ResourceEditorRegistrar類的registerCustomEditor方法的核心功能,其實(shí)無(wú)非就是注冊(cè)了一系列的常用類型的屬性編輯器。那么注冊(cè)后,一旦某個(gè)實(shí)體bean中存在一些Class類型的屬性,那么Spring會(huì)調(diào)用ClassEditor將配置文件中定義的String類型轉(zhuǎn)換為Class類型并進(jìn)行賦值。

?添加ApplicationContextAwareProcessor處理器

?  了解了屬性編輯器的使用后,接下來(lái)我們繼續(xù)通過AbstractApplicationContext的prepareBeanFactory方法的主線來(lái)進(jìn)行函數(shù)跟蹤。對(duì)于BeanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this))其實(shí)主要目的就是注冊(cè)個(gè)BeanPostProcessor,而真正的邏輯還是在ApplicationContextAwareProcessor中。

?  ApplicationContextAwareProcessor實(shí)現(xiàn)BeanPostProcessor接口,在bean實(shí)例化的時(shí)候,也就是Spring激活bean的init-method的前后,會(huì)調(diào)用BeanPostProcessor的postProcessBeforeInitialization方法和postProcessAfterInitialization方法,同樣,對(duì)于ApplicationContextAwareProcessor我們也關(guān)心著兩個(gè)方法。

  對(duì)于postProcessAfterInitialization方法,在ApplicationContextAwareProcessor中并沒有做過多邏輯處理。

public Object postProcessAfterInitialization(Object bean, String beanName) {return bean;}

那么,重點(diǎn)看一下postProcessBeforeInitialization方法:

public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {AccessControlContext acc = null;if (System.getSecurityManager() != null &&(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {acc = this.applicationContext.getBeanFactory().getAccessControlContext();}if (acc != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {invokeAwareInterfaces(bean);return null;}, acc);}else {invokeAwareInterfaces(bean);}return bean;} private void invokeAwareInterfaces(Object bean) {if (bean instanceof Aware) {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);}}}

  postProcessBeforeInitialization方法中調(diào)用了invokeAwareInterfaces方法。從第二段代碼invokeAwareInterfaces方法中,我們或許可以或多或少的了解Spring的用意,實(shí)現(xiàn)這些Aware接口的bean在被初始化之后,可以取得一些對(duì)應(yīng)的資源。

設(shè)置忽略依賴

當(dāng)Spring將ApplicationContextAwareProcessor注冊(cè)后,那么在invokeAwareInterfaces方法中調(diào)用的Aware類已經(jīng)不是普通的bean了,如ResourceLoaderAware、ApplicationEventPublisherAware等,那么當(dāng)然需要在Spring做bean的依賴注入的時(shí)候忽略它們,而ignoreDependencyInterface的作用正是如此。

注冊(cè)依賴

Spring中有了忽略依賴的功能,當(dāng)然也必不可少地會(huì)有注冊(cè)依賴的功能。

     beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);beanFactory.registerResolvableDependency(ResourceLoader.class, this);beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);beanFactory.registerResolvableDependency(ApplicationContext.class, this);

當(dāng)注冊(cè)了依賴解析后,例如當(dāng)注冊(cè)了對(duì)BeanFactory.class的解析依賴后,當(dāng)bean的屬性注入的時(shí)候,一旦檢測(cè)到屬性為BeanFactory類型便會(huì)將beanFactory的實(shí)例注入進(jìn)去。

參考:《Spring源碼深度解析》?郝佳?編著:

轉(zhuǎn)載于:https://www.cnblogs.com/Joe-Go/p/10211419.html

總結(jié)

以上是生活随笔為你收集整理的功能扩展的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 天堂网视频 | 四虎最新网址在线观看 | 在线a网站 | 亚洲高h| 欧美不卡影院 | 大牛影视剧免费播放在线 | 依人成人综合网 | 91视频成人 | 中文字幕丰满孑伦无码专区 | 偷拍一区二区三区 | 欧美污视频 | 337p亚洲欧洲色噜噜噜 | 日本欧美色图 | 四虎影视成人 | 中文在线不卡视频 | 色涩综合 | 色五夜 | 三级a毛片 | 久久综合色鬼 | 欧美男优 | 在线免费黄色 | 国产原创在线视频 | 日韩黄色免费电影 | 国产精品观看 | 日韩精品在线视频免费观看 | 青青草华人在线视频 | 成人a v视频 | 中文字幕在线观看免费 | 91偷拍视频| 午夜精品成人 | 91在线一区二区三区 | 大香伊人久久 | 欧美熟妇另类久久久久久多毛 | 日韩成人av毛片 | 国产黄色片子 | 婷婷综合国产 | japanese24hdxxxx中文字幕 | 野花社区视频在线观看 | 亚洲精品一二三四 | 午夜插插 | 人人草人人看 | 欧美成人aaaaⅴ片在线看 | 久热久 | 2025韩国大尺度电影 | 一本到高清 | 貂蝉被到爽流白浆在线观看 | 国产在成人精品线拍偷自揄拍 | 国产黄色美女视频 | 亚洲男人第一网站 | 高中男男gay互囗交观看 | 欧美乱妇视频 | av小说免费在线观看 | 自拍偷拍亚洲精品 | 夫妻淫语绿帽对白 | 国产免费一区 | 日韩成人在线一区 | 国产精品久久亚洲7777 | 亚洲男性天堂 | 亚洲欧美日韩免费 | 黄色a一级片 | 进去里在线观看 | 精品人伦一区二区三区 | 日日日干干干 | 76少妇精品导航 | 瑟瑟视频在线免费观看 | 可以免费看av | 小优视频污| 日本天堂在线视频 | 日韩色黄大片 | 在线天堂1| 午夜国产福利视频 | 国产精品美女久久久久久 | 欧美另类videossexo高潮 | 生活片毛片| 亚洲成人精品视频 | 亚洲+小说+欧美+激情+另类 | 丁香五香天堂网 | 18深夜在线观看免费视频 | 国语对白一区二区 | 午夜不卡福利 | 色中文| 成人影片网址 | 男男gay羞辱feet贱奴vk | 国产1区在线| www性 | 国产成人免费观看 | 久久久久久国产精品免费播放 | 欧美日本亚洲韩国国产 | 精品国产69 | 波多野结衣欧美 | 日本乱码一区二区 | 久久久久亚洲av成人网人人网站 | 最新免费av网站 | 视频在线观看一区 | 91爱在线观看 | 欧美黑人一区二区 | 亚洲五码在线 | 国产亚洲久一区二区 | 欧美极品一区二区 |