php cdi_教程:编写自己的CDI扩展
php cdi
今天,我將向您展示如何編寫CDI擴(kuò)展。
CDI提供了一種擴(kuò)展功能的簡便方法,例如
- 添加自己的范圍,
- 啟用Java核心類進(jìn)行擴(kuò)展,
- 使用注釋元數(shù)據(jù)進(jìn)行擴(kuò)充或修改,
- 以及更多。
在本教程中,我們將實(shí)現(xiàn)一個(gè)擴(kuò)展,該擴(kuò)展將從屬性文件中注入屬性,就像往常一樣,我將在github [更新: sources @ github ]中提供源代碼 。
目標(biāo)
提供擴(kuò)展,使我們能夠執(zhí)行以下操作
@PropertyFile("myProps.txt") public class MyProperties {@Property("version")Integer version;@Property("appname")String appname; }其中版本和應(yīng)用程序的名字在文件myProps.txt定義。
制備
首先,我們需要CDI API的依賴項(xiàng)
dependencies.compile "javax.enterprise:cdi-api:1.1-20130918"現(xiàn)在我們可以開始了。 那么我們
弄濕
基礎(chǔ)
每個(gè)CDI擴(kuò)展的入口點(diǎn)都是一個(gè)實(shí)現(xiàn)javax.enterprise.inject.spi.Extension的類
package com.coderskitchen.propertyloader;import javax.enterprise.inject.spi.Extension; public class PropertyLoaderExtension implements Extension { // More code later }另外,我們必須將此類的全限定名添加到META-INF / services目錄中名為javax.enterprise.inject.spi.Extension的文件中。
javax.enterprise.inject.spi.Extension
com.coderskitchen.propertyloader.PropertyLoaderExtension這些是編寫CDI擴(kuò)展的基本步驟。
背景資料
CDI使用Java SE的服務(wù)提供商體系結(jié)構(gòu),這就是為什么我們需要實(shí)現(xiàn)標(biāo)記接口并將文件與實(shí)現(xiàn)類的FQN添加在一起的原因。
潛水更深
現(xiàn)在,我們必須選擇正確的事件來收聽。
背景資料
CDI規(guī)范定義了幾個(gè)在應(yīng)用程序初始化期間由容器觸發(fā)的事件。
例如,在容器以bean發(fā)現(xiàn)開始之前,將觸發(fā)BeforeBeanDiscovery 。
對(duì)于本教程,我們需要監(jiān)聽ProcessInjectionTarget事件。 對(duì)于發(fā)現(xiàn)的每個(gè)Java類,接口或枚舉,都會(huì)觸發(fā)此事件,并且可能在運(yùn)行時(shí)由容器實(shí)例化該事件。
因此,讓我們添加此事件的觀察者:
ProcessInjectionTarget通過getAnnotatedType方法授予對(duì)基礎(chǔ)類的訪問權(quán)限,并通過getInjectionTarget授予創(chuàng)建中的實(shí)例的訪問權(quán)限。 我們使用annotatedType獲取類的注釋,以檢查@PropertyFile是否可用。 如果沒有,我們將直接作為短路返回。
隨后, InjectionTarget用于覆蓋當(dāng)前行為并從屬性文件中設(shè)置值。
public <T> void initializePropertyLoading(final @Observes ProcessInjectionTarget<T> pit) {AnnotatedType<T> at = pit.getAnnotatedType();if(!at.isAnnotationPresent(PropertyFile.class)) {return;}}在本教程中,我們假定屬性文件直接位于類路徑的根目錄中。 基于此假設(shè),我們可以添加以下代碼以從文件中加載屬性
PropertyFile propertyFile = at.getAnnotation(PropertyFile.class); String filename = propertyFile.value(); InputStream propertiesStream = getClass().getResourceAsStream("/" + filename); Properties properties = new Properties(); try {properties.load(propertiesStream);assignPropertiesToFields(at.getFields, properties); // Implementation follows } catch (IOException e) {e.printStackTrace(); }現(xiàn)在,我們可以將屬性值分配給字段。 但是對(duì)于CDI,我們必須以略有不同的方式執(zhí)行此操作。 我們應(yīng)該使用InjectionTarget并覆蓋當(dāng)前的AnnotatedType。 這使CDI可以確保所有事情都可以按正確的順序進(jìn)行。
為了實(shí)現(xiàn)這一點(diǎn),我們使用了最終的Map <Field,Object> ,我們可以在其中存儲(chǔ)當(dāng)前分配以供以后在InjectionTarget中使用 。 映射是在方法AssignPropertiesToFields中完成的。
private <T> void assignPropertiesToFields(Set<AnnotatedField<? super T>> fields, Properties properties) {for (AnnotatedField<? super T> field : fields) {if(field.isAnnotationPresent(Property.class)) {Property property = field.getAnnotation(Property.class);String value = properties.getProperty(property.value());Type baseType = field.getBaseType();fieldValues.put(memberField, value);}}最后,我們現(xiàn)在將創(chuàng)建一個(gè)新的InjectionTarget,以將字段值分配給所有新創(chuàng)建的基礎(chǔ)類實(shí)例。
final InjectionTarget<T> it = pit.getInjectionTarget();InjectionTarget<T> wrapped = new InjectionTarget<T>() {@Overridepublic void inject(T instance, CreationalContext<T> ctx) {it.inject(instance, ctx);for (Map.Entry<Field, Object> property: fieldValues.entrySet()) {try {Field key = property.getKey();key.setAccessible(true);Class<?> baseType = key.getType();String value = property.getValue().toString();if (baseType == String.class) {key.set(instance, value);} else if (baseType == Integer.class) {key.set(instance, Integer.valueOf(value));} else {pit.addDefinitionError(new InjectionException("Type " + baseType + " of Field " + key.getName() + " not recognized yet!"));}} catch (Exception e) {pit.addDefinitionError(new InjectionException(e));}}}@Overridepublic void postConstruct(T instance) {it.postConstruct(instance);}@Overridepublic void preDestroy(T instance) {it.dispose(instance);}@Overridepublic void dispose(T instance) {it.dispose(instance);}@Overridepublic Set<InjectionPoint> getInjectionPoints() {return it.getInjectionPoints();}@Overridepublic T produce(CreationalContext<T> ctx) {return it.produce(ctx);}};pit.setInjectionTarget(wrapped); 這就是做魔術(shù)的全部。 最后,這里是ProperyLoaderExtension的完整代碼。
PropertyLoaderExtension
資料下載
完整的源代碼將在git hub上提供,直到星期一晚上。 jar存檔可在此處PropertyLoaderExtension中找到 。
最后的筆記
本教程說明了如何簡單地向CDI框架添加新功能。 在幾行代碼中,添加了工作屬性加載和注入機(jī)制。 在應(yīng)用程序的生命周期內(nèi)觸發(fā)的事件提供了一種松散耦合且功能強(qiáng)大的方法來添加新功能,攔截bean創(chuàng)建或更改行為。
還可以通過引入一組生產(chǎn)者方法來實(shí)現(xiàn)屬性注入,但是這種方法需要每種字段類型使用一個(gè)生產(chǎn)者方法。 使用這種通用方法,您只需要添加新的轉(zhuǎn)換器即可啟用其他類型的值的注入。
翻譯自: https://www.javacodegeeks.com/2014/02/tutorial-writing-your-own-cdi-extension.html
php cdi
總結(jié)
以上是生活随笔為你收集整理的php cdi_教程:编写自己的CDI扩展的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 在Spring Boot启动时运行代码
- 下一篇: php cdi_使用CDI的Inject