php cdi_教程:编写自己的CDI扩展
php cdi
今天,我將向您展示如何編寫CDI擴展。
CDI提供了一種擴展功能的簡便方法,例如
- 添加自己的范圍,
- 啟用Java核心類進行擴展,
- 使用注釋元數據進行擴充或修改,
- 以及更多。
在本教程中,我們將實現一個擴展,該擴展將從屬性文件中注入屬性,就像往常一樣,我將在github [更新: sources @ github ]中提供源代碼 。
目標
提供擴展,使我們能夠執行以下操作
@PropertyFile("myProps.txt") public class MyProperties {@Property("version")Integer version;@Property("appname")String appname; }其中版本和應用程序的名字在文件myProps.txt定義。
制備
首先,我們需要CDI API的依賴項
dependencies.compile "javax.enterprise:cdi-api:1.1-20130918"現在我們可以開始了。 那么我們
弄濕
基礎
每個CDI擴展的入口點都是一個實現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擴展的基本步驟。
背景資料
CDI使用Java SE的服務提供商體系結構,這就是為什么我們需要實現標記接口并將文件與實現類的FQN添加在一起的原因。
潛水更深
現在,我們必須選擇正確的事件來收聽。
背景資料
CDI規范定義了幾個在應用程序初始化期間由容器觸發的事件。
例如,在容器以bean發現開始之前,將觸發BeforeBeanDiscovery 。
對于本教程,我們需要監聽ProcessInjectionTarget事件。 對于發現的每個Java類,接口或枚舉,都會觸發此事件,并且可能在運行時由容器實例化該事件。
因此,讓我們添加此事件的觀察者:
ProcessInjectionTarget通過getAnnotatedType方法授予對基礎類的訪問權限,并通過getInjectionTarget授予創建中的實例的訪問權限。 我們使用annotatedType獲取類的注釋,以檢查@PropertyFile是否可用。 如果沒有,我們將直接作為短路返回。
隨后, InjectionTarget用于覆蓋當前行為并從屬性文件中設置值。
public <T> void initializePropertyLoading(final @Observes ProcessInjectionTarget<T> pit) {AnnotatedType<T> at = pit.getAnnotatedType();if(!at.isAnnotationPresent(PropertyFile.class)) {return;}}在本教程中,我們假定屬性文件直接位于類路徑的根目錄中。 基于此假設,我們可以添加以下代碼以從文件中加載屬性
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(); }現在,我們可以將屬性值分配給字段。 但是對于CDI,我們必須以略有不同的方式執行此操作。 我們應該使用InjectionTarget并覆蓋當前的AnnotatedType。 這使CDI可以確保所有事情都可以按正確的順序進行。
為了實現這一點,我們使用了最終的Map <Field,Object> ,我們可以在其中存儲當前分配以供以后在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);}}最后,我們現在將創建一個新的InjectionTarget,以將字段值分配給所有新創建的基礎類實例。
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); 這就是做魔術的全部。 最后,這里是ProperyLoaderExtension的完整代碼。
PropertyLoaderExtension
資料下載
完整的源代碼將在git hub上提供,直到星期一晚上。 jar存檔可在此處PropertyLoaderExtension中找到 。
最后的筆記
本教程說明了如何簡單地向CDI框架添加新功能。 在幾行代碼中,添加了工作屬性加載和注入機制。 在應用程序的生命周期內觸發的事件提供了一種松散耦合且功能強大的方法來添加新功能,攔截bean創建或更改行為。
還可以通過引入一組生產者方法來實現屬性注入,但是這種方法需要每種字段類型使用一個生產者方法。 使用這種通用方法,您只需要添加新的轉換器即可啟用其他類型的值的注入。
翻譯自: https://www.javacodegeeks.com/2014/02/tutorial-writing-your-own-cdi-extension.html
php cdi
總結
以上是生活随笔為你收集整理的php cdi_教程:编写自己的CDI扩展的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 在Spring Boot启动时运行代码
- 下一篇: php cdi_使用CDI的Inject