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的一个实例:
@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注释添加到任何类,实现一个特定的服务接口。
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。
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对象的方法:
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.