import javax.enterprise.inject.spi.Extension; class MyExtension implements Extension { ... }接下來,咱們須要註冊擴展做爲服務提供者經過建立一個文件META-INF/services/javax.enterprise.inject.spi.Extension,其中包含咱們的擴展類的完整名稱:
@Inject MyBean(MyExtension myExtension) { myExtension.doSomething(); }像Bean同樣,extension能夠有Observer方法。一般,觀察者方法觀察容器生命週期事件的方法。
import javax.enterprise.inject.spi.Extension; class MyExtension implements Extension { void beforeBeanDiscovery(@Observes BeforeBeanDiscovery bbd) { Logger.global.debug("beginning the scanning process"); } <T> void processAnnotatedType(@Observes ProcessAnnotatedType<T> pat) { Logger.global.debug("scanning type: " + pat.getAnnotatedType().getJavaClass().getName()); } void afterBeanDiscovery(@Observes AfterBeanDiscovery abd) { Logger.global.debug("finished the scanning process"); } }事實上,擴展能夠作不少事情不只僅是觀察。擴展容許修改容器的元模型等等。這裏有一個很簡單的例子:
import javax.enterprise.inject.spi.Extension; class MyExtension implements Extension { <T> void processAnnotatedType(@Observes @WithAnnotations({Ignore.class}) ProcessAnnotatedType<T> pat) { /* tell the container to ignore the type if it is annotated @Ignore */ if ( pat.getAnnotatedType().isAnnotationPresent(Ignore.class) ) pat.veto(); } }New in CDI 1.1
<T> void processAnnotatedType(@Observes ProcessAnnotatedType<T> pat, BeanManager beanManager) { ... }
public interface BeanManager { public Object getReference(Bean<?> bean, Type beanType, CreationalContext<?> ctx); public Object getInjectableReference(InjectionPoint ij, CreationalContext<?> ctx); public <T> CreationalContext<T> createCreationalContext(Contextual<T> contextual); public Set<Bean<?>> getBeans(Type beanType, Annotation... qualifiers); public Set<Bean<?>> getBeans(String name); public Bean<?> getPassivationCapableBean(String id); public <X> Bean<? extends X> resolve(Set<Bean<? extends X>> beans); public void validate(InjectionPoint injectionPoint); public void fireEvent(Object event, Annotation... qualifiers); public <T> Set<ObserverMethod<? super T>> resolveObserverMethods(T event, Annotation... qualifiers); public List<Decorator<?>> resolveDecorators(Set<Type> types, Annotation... qualifiers); public List<Interceptor<?>> resolveInterceptors(InterceptionType type, Annotation... interceptorBindings); public boolean isScope(Class<? extends Annotation> annotationType); public boolean isNormalScope(Class<? extends Annotation> annotationType); public boolean isPassivatingScope(Class<? extends Annotation> annotationType); public boolean isQualifier(Class<? extends Annotation> annotationType); public boolean isInterceptorBinding(Class<? extends Annotation> annotationType); public boolean isStereotype(Class<? extends Annotation> annotationType); public Set<Annotation> getInterceptorBindingDefinition(Class<? extends Annotation> bindingType); public Set<Annotation> getStereotypeDefinition(Class<? extends Annotation> stereotype); public boolean areQualifiersEquivalent(Annotation qualifier1, Annotation qualifier2); public boolean areInterceptorBindingsEquivalent(Annotation interceptorBinding1, Annotation interceptorBinding2); public int getQualifierHashCode(Annotation qualifier); public int getInterceptorBindingHashCode(Annotation interceptorBinding); public Context getContext(Class<? extends Annotation> scopeType); public ELResolver getELResolver(); public ExpressionFactory wrapExpressionFactory(ExpressionFactory expressionFactory); public <T> AnnotatedType<T> createAnnotatedType(Class<T> type); public <T> InjectionTarget<T> createInjectionTarget(AnnotatedType<T> type); public <T> InjectionTargetFactory<T> getInjectionTargetFactory(AnnotatedType<T> annotatedType); public <X> ProducerFactory<X> getProducerFactory(AnnotatedField<? super X> field, Bean<X> declaringBean); public <X> ProducerFactory<X> getProducerFactory(AnnotatedMethod<? super X> method, Bean<X> declaringBean); public <T> BeanAttributes<T> createBeanAttributes(AnnotatedType<T> type); public BeanAttributes<?> createBeanAttributes(AnnotatedMember<?> type); public <T> Bean<T> createBean(BeanAttributes<T> attributes, Class<T> beanClass, public <T, X> Bean<T> createBean(BeanAttributes<T> attributes, Class<X> beanClass, ProducerFactory<X> producerFactory); public InjectionPoint createInjectionPoint(AnnotatedField<?> field); public InjectionPoint createInjectionPoint(AnnotatedParameter<?> parameter); public <T extends Extension> T getExtension(Class<T> extensionClass); }
任何bean或其餘Java EE組件,可經過@Inject得到BeanManager的一個實例: java
@Inject BeanManager beanManager;另外,一個BeanManager參考可用CDI經過靜態方法調用得到的。
CDI.current().getBeanManager()Java EE組件可能得到的實例BeanManager從JNDI查找名稱Java:comp / BeanManager。
BeanManager manager = CDI.current().getBeanManager();那上面代碼的CDI從哪裏得到?能夠直接使用CDI類以編程方式查找CDI bean
CDI.select(Foo.class).get()
import javax.enterprise.inject.spi.CDI; ... //獲取一個BeanManager BeanManager beanManager = CDI.current().getBeanManager(); //CDI採用AnnotatedType對象來讀取一個類的註解 AnnotatedType<SomeFrameworkComponent> type = beanManager.createAnnotatedType(SomeFrameworkComponent.class); //extensions使用的InjectionTarget在CDI容器中委託實例化,依賴注入 和生命週期回調 InjectionTarget<SomeFrameworkComponent> it = beanManager.createInjectionTarget(type); //每一個實例都須要它本身的CDI CreationalContext(CDI創造上下文) CreationalContext ctx = beanManager.createCreationalContext(null); //實例化的框架組件,並注入其依賴關係 SomeFrameworkComponent instance = it.produce(ctx); //調用構造函數 it.inject(instance, ctx); //調用初始化方法,並完成字段方式的注入 it.postConstruct(instance); //call the @PostConstruct method ... //摧毀的框架組件實例和清理依賴對象 it.preDestroy(instance); //call the @PreDestroy method it.dispose(instance); //it is now safe to discard the instance ctx.release(); //clean up dependent objects
public interface BeanAttributes<T> { public Set<Type> getTypes(); public Set<Annotation> getQualifiers(); public Class<? extends Annotation> getScope(); public String getName(); public Set<Class<? extends Annotation>> getStereotypes(); public boolean isAlternative(); }Bean接口擴展了BeanAttributes接口並定義全部容器須要管理的Bean實例。
public interface Bean<T> extends Contextual<T>, BeanAttributes<T> { public Class<?> getBeanClass(); public Set<InjectionPoint> getInjectionPoints(); public boolean isNullable(); }有一個簡單的方法在應用程序來找出bean:
Set<Bean<?>> allBeans = beanManager.getBeans(Obect.class, new AnnotationLiteral<Any>() {});Bean接口用便攜擴展爲新的Bean提供支持,除了那些CDI規範定義的.例如咱們可使用Bean接口容許對象管理由另外一個框架注入bean。
import javax.enterprise.inject.spi.Extension; import javax.enterprise.event.Observes; import java.lang.annotation.Annotation; import java.lang.reflect.Type; import javax.enterprise.inject.spi.InjectionPoint; ... public class SecurityManagerExtension implements Extension { void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { //use this to read annotations of the class AnnotatedType<SecurityManager> at = bm.createAnnotatedType(SecurityManager.class); //use this to instantiate the class and inject dependencies final InjectionTarget<SecurityManager> it = bm.createInjectionTarget(at); abd.addBean( new Bean<SecurityManager>() { @Override public Class<?> getBeanClass() { return SecurityManager.class; } @Override public Set<InjectionPoint> getInjectionPoints() { return it.getInjectionPoints(); } @Override public String getName() { return "securityManager"; } @Override public Set<Annotation> getQualifiers() { Set<Annotation> qualifiers = new HashSet<Annotation>(); qualifiers.add( new AnnotationLiteral<Default>() {} ); qualifiers.add( new AnnotationLiteral<Any>() {} ); return qualifiers; } @Override public Class<? extends Annotation> getScope() { return ApplicationScoped.class; } @Override public Set<Class<? extends Annotation>> getStereotypes() { return Collections.emptySet(); } @Override public Set<Type> getTypes() { Set<Type> types = new HashSet<Type>(); types.add(SecurityManager.class); types.add(Object.class); return types; } @Override public boolean isAlternative() { return false; } @Override public boolean isNullable() { return false; } @Override public SecurityManager create(CreationalContext<SecurityManager> ctx) { SecurityManager instance = it.produce(ctx); it.inject(instance, ctx); it.postConstruct(instance); return instance; } @Override public void destroy(SecurityManager instance,CreationalContext<SecurityManager> ctx) { it.preDestroy(instance); it.dispose(instance); ctx.release(); } } ); } }
import java.lang.reflect.Type; import javax.enterprise.inject.spi.Extension; import java.lang.annotation.Annotation; ... public class QualifiedNameExtension implements Extension { <X> void processAnnotatedType(@Observes ProcessAnnotatedType<X> pat) { /* wrap this to override the annotations of the class */ final AnnotatedType<X> at = pat.getAnnotatedType(); /* Only wrap AnnotatedTypes for classes with @Named packages */ Package pkg = at.getJavaClass().getPackage(); if ( !pkg.isAnnotationPresent(Named.class) ) { return; } AnnotatedType<X> wrapped = new AnnotatedType<X>() { class NamedLiteral extends AnnotationLiteral<Named>implements Named { @Override public String value() { Package pkg = at.getJavaClass().getPackage(); String unqualifiedName = ""; if (at.isAnnotationPresent(Named.class)) { unqualifiedName = at.getAnnotation(Named.class).value(); } if (unqualifiedName.isEmpty()) { unqualifiedName = Introspector.decapitalize(at.getJavaClass().getSimpleName()); } final String qualifiedName; if ( pkg.isAnnotationPresent(Named.class) ) { qualifiedName = pkg.getAnnotation(Named.class).value() + '.' + unqualifiedName; } else { qualifiedName = unqualifiedName; } return qualifiedName; } } private final NamedLiteral namedLiteral = new NamedLiteral(); @Override public Set<AnnotatedConstructor<X>> getConstructors() { return at.getConstructors(); } @Override public Set<AnnotatedField<? super X>> getFields() { return at.getFields(); } @Override public Class<X> getJavaClass() { return at.getJavaClass(); } @Override public Set<AnnotatedMethod<? super X>> getMethods() { return at.getMethods(); } @Override public <T extends Annotation> T getAnnotation(final Class<T> annType) { if (Named.class.equals(annType)) { return (T) namedLiteral; } else { return at.getAnnotation(annType); } } @Override public Set<Annotation> getAnnotations() { Set<Annotation> original = at.getAnnotations(); Set<Annotation> annotations = new HashSet<Annotation>(); boolean hasNamed = false; for (Annotation annotation : original) { if (annotation.annotationType().equals(Named.class)) { annotations.add(getAnnotation(Named.class)); hasNamed = true; } else { annotations.add(annotation); } } if (!hasNamed) { Package pkg = at.getJavaClass().getPackage(); if (pkg.isAnnotationPresent(Named.class)) { annotations.add(getAnnotation(Named.class)); } } return annotations; } @Override public Type getBaseType() { return at.getBaseType(); } @Override public Set<Type> getTypeClosure() { return at.getTypeClosure(); } @Override public boolean isAnnotationPresent(Class<? extends Annotation> annType) { if (Named.class.equals(annType)) { return true; } return at.isAnnotationPresent(annType); } }; pat.setAnnotatedType(wrapped); } }
這是第二個例子,將@Alternative註釋添加到任何類,實現一個特定的服務接口。 express
import javax.enterprise.inject.spi.Extension; import java.lang.annotation.Annotation; ... class ServiceAlternativeExtension implements Extension { <T extends Service> void processAnnotatedType(@Observes ProcessAnnotatedType<T> pat) { final AnnotatedType<T> type = pat.getAnnotatedType(); /* if the class implements Service, make it an @Alternative */ AnnotatedType<T> wrapped = new AnnotatedType<T>() { class AlternativeLiteral extends AnnotationLiteral<Alternative> implements Alternative {} private final AlternativeLiteral alternativeLiteral = new AlternativeLiteral(); @Override public <X extends Annotation> X getAnnotation(final Class<X> annType) { return (X) (annType.equals(Alternative.class) ? alternativeLiteral : type.getAnnotation(annType)); } @Override public Set<Annotation> getAnnotations() { Set<Annotation> annotations = new HashSet<Annotation>(type.getAnnotations()); annotations.add(alternativeLiteral); return annotations; } @Override public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) { return annotationType.equals(Alternative.class) ? true : type.isAnnotationPresent(annotationType); } /* remaining methods of AnnotatedType */ ... } pat.setAnnotatedType(wrapped); } }
AnnotatedType 不是惟一一個能被extension.包裝的. 編程
public interface BeanAttributes<T> { public Set<Type> getTypes(); public Set<Annotation> getQualifiers(); public Class<? extends Annotation> getScope(); public String getName(); public Set<Class<? extends Annotation>> getStereotypes(); public boolean isAlternative(); }
BeanAttributes接口暴露bean的屬性。對於每一個已經啓用的bean容器都會Fire ProcessBeanAttributes event,這個事件容許修改bean的屬性或徹底veto(否決)bean。 api
public interface ProcessBeanAttributes<T> { public Annotated getAnnotated(); public BeanAttributes<T> getBeanAttributes(); public void setBeanAttributes(BeanAttributes<T> beanAttributes); public void addDefinitionError(Throwable t); public void veto(); }
BeanManager提供了兩建立BeanAttributes對象的方法: app
public <T> BeanAttributes<T> createBeanAttributes(AnnotatedType<T> type); public BeanAttributes<?> createBeanAttributes(AnnotatedMember<?> type);
lastName=King 框架
portable extension 的工做方式就是封裝InjectionTarget,而後在 inject() 方法中對field進行賦值。import javax.enterprise.event.Observes; import javax.enterprise.inject.spi.Extension; import javax.enterprise.inject.spi.InjectionPoint; public class ConfigExtension implements Extension { <X> void processInjectionTarget(@Observes ProcessInjectionTarget<X> pit) { /* wrap this to intercept the component lifecycle */ final InjectionTarget<X> it = pit.getInjectionTarget(); final Map<Field, Object> configuredValues = new HashMap<Field, Object>(); /* use this to read annotations of the class and its members */ AnnotatedType<X> at = pit.getAnnotatedType(); /* read the properties file */ String propsFileName = at.getJavaClass().getSimpleName() + ".properties"; InputStream stream = at.getJavaClass().getResourceAsStream(propsFileName); if (stream!=null) { try { Properties props = new Properties(); props.load(stream); for (Map.Entry<Object, Object> property : props.entrySet()) { String fieldName = property.getKey().toString(); Object value = property.getValue(); try { Field field = at.getJavaClass().getDeclaredField(fieldName); field.setAccessible(true); if ( field.getType().isAssignableFrom( value.getClass() ) ) { configuredValues.put(field, value); } else { /* TODO: do type conversion automatically */ pit.addDefinitionError( new InjectionException("field is not of type String: " + field ) ); } } catch (NoSuchFieldException nsfe) { pit.addDefinitionError(nsfe); } finally { stream.close(); } } } catch (IOException ioe) { pit.addDefinitionError(ioe); } } InjectionTarget<X> wrapped = new InjectionTarget<X>() { @Override public void inject(X instance, CreationalContext<X> ctx) { it.inject(instance, ctx); /* set the values onto the new instance of the component */ for (Map.Entry<Field, Object> configuredValue: configuredValues.entrySet()) { try { configuredValue.getKey().set(instance, configuredValue.getValue()); } catch (Exception e) { throw new InjectionException(e); } } } @Override public void postConstruct(X instance) { it.postConstruct(instance); } @Override public void preDestroy(X instance) { it.dispose(instance); } @Override public void dispose(X instance) { it.dispose(instance); } @Override public Set<InjectionPoint> getInjectionPoints() { return it.getInjectionPoints(); } @Override public X produce(CreationalContext<X> ctx) { return it.produce(ctx); } }; pit.setInjectionTarget(wrapped); } }
public interface ProcessInjectionPoint<T, X> { public InjectionPoint getInjectionPoint(); public void setInjectionPoint(InjectionPoint injectionPoint); public void addDefinitionError(Throwable t); }An extension may either completely override the injection point metadata or alter it by wrapping the InjectionPoint object obtained from ProcessInjectionPoint.getInjectionPoint()
public interface AfterTypeDiscovery { public List<Class<?>> getAlternatives(); public List<Class<?>> getInterceptors(); public List<Class<?>> getDecorators(); public void addAnnotatedType(AnnotatedType<?> type, String id); }This event exposes a list of enabled alternatives, interceptors and decorators. Extensions may manipulate these collections directly to add, remove or change the order of the enabled records.
public interface Context { public Class<? extends Annotation> getScope(); public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext); public <T> T get(Contextual<T> contextual); boolean isActive(); }例如,咱們可能會實現上下文添加一個業務流程範圍CDI,或將支持conversation做用域添加到一個應用程序,該應用程序使用Wicket。
import javax.enterprise.context.spi.Context; public interface AlterableContext extends Context { public void destroy(Contextual<?> contextual); }AlterableContext CDI 1.1中引入的。銷燬方法容許應用程序從一個上下文刪除上下文對象的實例。
Over. dom