advanced cdi in live coding

Post on 21-Feb-2017

687 Views

Category:

Technology

1 Downloads

Preview:

Click to see full reader

TRANSCRIPT

GoingfurtherwithCDI1.2

AntoineSabot-Durand·AntoninStefanutti

AntoninStefanutti

SoftwareEngineerRedHatJBossFuseteam@astefanutgithub.com/astefanutti

AntoineSabot-Durand

RedHatCDIspeclead@antoine_sdnext-presso.comgithub.com/antoinesd

ShouldIstayorshouldIgo?

AtalkaboutadvancedCDI

Mightbehardforbeginners

Don’tneedtobeaCDIguru

@Inject @ProducesEvent<T> @Observes@Qualifier InjectionPoint

ShouldIstayorshouldIgo?

Ifyouknowmostoftheseyoucanstay

Moreconcretely

What’sincluded:

1. Realusecasesfromreallifewithrealusers2. Newapproachtointroduceportableextensionconcepts3. CodeinIDEwithtests

What’snotincluded:

1. IntroductiontoCDI2. Oldcontentonextension3. WorkwithContext(need2morehours)

Toolsusedinthecode1/2

ApacheDeltaspike

1. ApacheDeltaSpikeisagreatCDItoolbox

2. Providehelperstodevelopextension3. Andacollectionofmoduleslike:

1. Security2. Data3. Scheduler

4. Moreinfoondeltaspike.apache.org

Toolsusedinthecode2/2

Arquillian

1. Arquillianisanintegrationtestplatform2. ItintegrateswithJUnit3. Createyourdeploymentinadedicated

method4. Andlaunchyourtestsagainstthecontainer

ofyourchoice5. We’llusethe weld-se-embedded and

weld-ee-embedded container6. TherightsolutiontotestJavaEEcode7. Moreinfoonarquillian.org

Agenda

Slidesavailableatastefanutti.github.io/further-cdi

MeetCDISPIIntroducingCDIExtensionsMetricsCDICamelCDI

MeetCDISPI

SPIcanbesplitin4parts

SPIcanbesplitin4parts

Typemeta-model

SPIcanbesplitin4parts

CDImeta-model

SPIcanbesplitin4parts

CDIentrypoints

SPIcanbesplitin4parts

SPIdedicatedtoextensions

Whyhavingatypemeta-model?

Because @Annotations areconfiguration

buttheyarealsoread-only

Sotoconfigureweneedamutablemeta-model…

… forannotatedtypes

SPIfortypemeta-model

Annotated

TypegetBaseType()Set<Type>getTypeClosure()<TextendsAnnotation>getAnnotation(Class<T>)Set<Annotation>getAnnotations()booleanisAnnotationPresent(Class<?extendsAnnotation>)

AnnotatedMemberX

MembergetJavaMember()booleanisStatic()AnnotatedType<X>getDeclaringType()

AnnotatedParameterX

intgetPosition()AnnotatedCallable<X>getDeclaringCallable()

AnnotatedTypeX

Class<X>getJavaClass()Set<AnnotatedConstructor<X>>getConstructors()Set<AnnotatedMethod<?superX>>getMethods()Set<AnnotatedField<?superX>>getFields()

AnnotatedCallableX

List<AnnotatedParameter<X>>getParameters()

AnnotatedFieldX

FieldgetJavaMember()

AnnotatedConstructorX

Constructor<X>getJavaMember()

AnnotatedMethodX

MethodgetJavaMember()

SPIdedicatedtoCDImeta-modelBeanAttributes

T

Set<Type>getTypes()Set<Annotation>getQualifiers()Class<?extendsAnnotation>getScope()StringgetName()Set<Class<?extendsAnnotation>>getStereotypes()booleanisAlternative()

BeanT

Class<?>getBeanClass()Set<InjectionPoint>getInjectionPoints()booleanisNullable()

InterceptorT

Set<Annotation>getInterceptorBindings()booleanintercepts(InterceptionTypetype)Objectintercept(InterceptionType,T,InvocationContext)

DecoratorT

TypegetDelegateType()Set<Annotation>getDelegateQualifiers()Set<Type>getDecoratedTypes()

ProducerT

Tproduce(CreationalContext<T>)voiddispose(T)Set<InjectionPoint>getInjectionPoints()

InjectionTargetT

voidinject(T,CreationalContext<T>)voidpostConstruct(T)voidpreDestroy(T)

InjectionPoint

TypegetType()Set<Annotation>getQualifiers()Bean<?>getBean()MembergetMember()AnnotatedgetAnnotated()booleanisDelegate()booleanisTransient()

ObserverMethodT

Class<?>getBeanClass()TypegetObservedType()Set<Annotation>getObservedQualifiers()ReceptiongetReception()TransactionPhasegetTransactionPhase()voidnotify(T)

EventMetadata

Set<Annotation>getQualifiers()InjectionPointgetInjectionPoint()TypegetType()

ThisSPIcanbeusedinyourcode(1/2)

InjectionPoint canbeusedtogetinfoaboutwhat’sbeinginjected

@Qualifier@Retention(RetentionPolicy.RUNTIME)public@interfaceHttpParam{@NonbindingpublicStringvalue();}

@Produces@HttpParam("")StringgetParamValue(InjectionPointip,HttpServletRequestreq){returnreq.getParameter(ip.getAnnotated().getAnnotation(HttpParam.class).value());}

@Inject@HttpParam("productId")StringproductId;

ThisSPIcanbeusedinyourcode(2/2)

InjectionPoint containsinfoaboutrequestedtypeat @Inject

classMyMapProducer(){

@Produces<K,V>Map<K,V>produceMap(InjectionPointip){if(valueIsNumber(((ParameterizedType)ip.getType())))returnnewTreeMap<K,V>();returnnewHashMap<K,V>();}

booleanvalueIsNumber(ParameterizedTypetype){Class<?>valueClass=(Class<?>)type.getActualTypeArguments()[1];returnNumber.class.isAssignableFrom(valueClass)}}

SPIprovidingCDIentrypoints

UnmanagedT

Unmanaged(BeanManager,Class<T>)Unmanaged(Class<T>)UnmanagedInstance<T>newInstance()

UnmanagedInstanceT

Tget()UnmanagedInstance<T>produce()UnmanagedInstance<T>inject()UnmanagedInstance<T>postConstruct()UnmanagedInstance<T>preDestroy()UnmanagedInstance<T>dispose()

CDIProvider

CDI<Object>getCDI()

BeanManager

ObjectgetReference(Bean<?>,Type,CreationalContext<?>)ObjectgetInjectableReference(InjectionPoint,CreationalContext<?>)Set<Bean<?>>getBeans(Type,Annotation[])Bean<?extendsX>resolve(Set<Bean<?extendsX>>)voidvalidate(InjectionPoint)voidfireEvent(Object,Annotation[])

booleanisQualifier(Class<?extendsAnnotation>)booleanisStereotype(Class<?extendsAnnotation>)booleanareQualifiersEquivalent(Annotation,Annotation)booleanareInterceptorBindingsEquivalent(Annotation,Annotation)ContextgetContext(Class<?extendsAnnotation>)ELResolvergetELResolver()ExpressionFactorywrapExpressionFactory(ExpressionFactory)AnnotatedType<T>createAnnotatedType(Class<T>)InjectionTarget<T>createInjectionTarget(AnnotatedType<T>)InjectionTargetFactory<T>getInjectionTargetFactory(AnnotatedType<T>)BeanAttributes<T>createBeanAttributes(AnnotatedType<T>)Bean<T>createBean(BeanAttributes<T>,Class<X>,ProducerFactory<X>)InjectionPointcreateInjectionPoint(AnnotatedField<?>)

somemethodsskipped

CDIT

Set<CDIProvider>discoveredProvidersCDIProviderconfiguredProvider

CDI<Object>current()voidsetCDIProvider(CDIProviderprovider)BeanManagergetBeanManager()

SPIdedicatedtoextensions

BeforeBeanDiscovery

addQualifier(Class<?extendsAnnotation>)addScope(Class<?extendsAnnotation>,boolean,boolean)addStereotype(Class<?extendsAnnotation>,Annotation[])addInterceptorBinding(Class<?extendsAnnotation>,Annotation[])addAnnotatedType(AnnotatedType<?>)

AfterTypeDiscovery

List<Class<?>>getAlternatives()List<Class<?>>getInterceptors()List<Class<?>>getDecorators()addAnnotatedType(AnnotatedType<?>,String)

AfterDeploymentValidation BeforeShutdown

AfterBeanDiscovery

addBean(Bean<?>)addObserverMethod(ObserverMethod<?>)addContext(Context)AnnotatedType<T>getAnnotatedType(Class<T>,String)Iterable<AnnotatedType<T>>getAnnotatedTypes(Class<T>)

ProcessAnnotatedTypeX

AnnotatedType<X>getAnnotatedType()voidsetAnnotatedType(AnnotatedType<X>)veto()

ProcessBeanX

AnnotatedgetAnnotated()Bean<X>getBean()

ProcessBeanAttributesT

AnnotatedgetAnnotated()BeanAttributes<T>getBeanAttributes()setBeanAttributes(BeanAttributes<T>)veto()

ProcessInjectionPointT,X

InjectionPointgetInjectionPoint()setInjectionPoint(InjectionPoint)

ProcessInjectionTargetX

AnnotatedType<X>getAnnotatedType()InjectionTarget<X>getInjectionTarget()setInjectionTarget(InjectionTarget<X>)

ProcessObserverMethodT,X

AnnotatedMethod<X>getAnnotatedMethod()ObserverMethod<T>getObserverMethod()

ProcessProducerT,X

AnnotatedMember<T>getAnnotatedMember()Producer<X>getProducer()setProducer(Producer<X>)

AlltheseSPIinterfacesareeventscontainingmeta-modelSPI

TheseeventsfiredatboottimecanonlybeobservedinCDIextensions

Forinstance:

A ProcessAnnotatedType<T> eventisfiredforeachtypebeingdiscoveredatboottime

Observing ProcessAnnotatedType<Foo>allowsyoutoprevent Foo tobedeployedasabeanbycallingProcessAnnotatedType#veto()

IntroducingCDIPortableExtensions

Portableextensions

OneofthemostpowerfulfeatureoftheCDIspecification

Notreallypopularized,partlydueto:

1. Theirhighlevelofabstraction2. ThegoodknowledgeonBasicCDIandSPI3. Lackofinformation(CDIisoftenreducedtoabasicDIsolution)

Extensions,whatfor?

Tointegrate3rdpartylibraries,frameworksorlegacycomponents

Tochangeexistingconfigurationorbehavior

ToextendCDIandJavaEE

Thankstothem,JavaEEcanevolvebetweenmajorreleases

Extensions,how?

ObservingSPIeventsatboottimerelatedtothebeanmanagerlifecycle

Checkingwhatmeta-dataarebeingcreated

Modifyingthesemeta-dataorcreatingnewones

Moreconcretely

Serviceprovideroftheservicejavax.enterprise.inject.spi.Extension declaredinMETA-INF/services

Justputthefullyqualifiednameofyourextensionclassinthisfile

importjavax.enterprise.event.Observes;importjavax.enterprise.inject.spi.Extension;

publicclassCdiExtensionimplementsExtension{

voidbeforeBeanDiscovery(@ObservesBeforeBeanDiscoverybbd){}//...

voidafterDeploymentValidation(@ObservesAfterDeploymentValidationadv){}}

InternalStep HappenOnce LooponElements

Beanmanagerlifecycle

DeploymentStart

BeforeBean

Discovery

ScanArchive

ProcessAnnotated

Type

AfterType

Discovery

BeanEligibility

Check

ProcessInjectionPoint

ProcessInjectionTarget

ProcessBean

Attributes

ProcessBean

ProcessProducer

ProcessObserverMethod

AfterBean

Discovery

AfterDeploymentValidation

ApplicationRunning

BeforeShutdown

UndeployApplication

Example:IgnoringJPAentities

ThefollowingextensionpreventsCDItomanageentities

Thisisacommonlyadmittedgoodpractice

publicclassVetoEntityimplementsExtension{

voidvetoEntity(@Observes@WithAnnotations(Entity.class)ProcessAnnotatedType<?>pat){pat.veto();}}

ExtensionsarelaunchedduringbootstrapandarebasedonCDIevents

Oncetheapplicationisbootstrapped,theBeanManagerisinread-onlymode(noruntimebeanregistration)

Youonlyhaveto@Observes built-inCDIeventstocreateyourextensions

Remember

IntegratingDropwizardMetricsinCDI

MetricsCDI

DropwizardMetricsprovides

Differentmetrictypes: Counter , Gauge , Meter , Timer ,…

Differentreporter:JMX,console,SLF4J,CSV,servlet,…

MetricRegistry objectwhichcollectsallyourappmetrics

AnnotationsforAOPframeworks: @Counted , @Timed ,…

… butdoesnotincludeintegrationwiththeseframeworks

Moreatdropwizard.github.io/metrics

DiscoverhowwecreatedCDIintegrationmoduleforMetrics

Metricsoutofthebox(withoutCDI)classMetricsHelper{publicstaticMetricRegistryregistry=newMetricRegistry();}

classTimedMethodClass{

voidtimedMethod(){Timertimer=MetricsHelper.registry.timer("timer");Timer.Contexttime=timer.time();try{/*...*/}finally{time.stop();}}}

Notethatifa Timer named "timer" doesn’texist, MetricRegistry willcreateadefaultoneandregisterit

1

1

BasicCDIintegrationclassMetricRegistryBean{@Produces@ApplicationScopedMetricRegistryregistry=newMetricRegistry();}

classTimedMethodBean{@InjectMetricRegistryregistry;

voidtimedMethod(){Timertimer=registry.timer("timer");Timer.Contexttime=timer.time();try{/*...*/}finally{time.stop();}}}

WecouldhavealotmorewithadvancedCDIfeatures

OurgoalstoachievefullCDIintegration

Produceandinjectmultiplemetricsofthesametype

ApplyMetricswithprovidedannotations

Accesssame Metric throughinjector MetricRegistry getter

GOAL1Produceandinjectmultiplemetricsofthesametype

What’stheproblemwithmultipleMetricsofthesametype?

Thiscodecreateadeploymenterror(ambiguousdependency)

@ProducesTimertimer=newTimer(newSlidingTimeWindowReservoir(1L,MINUTES));

@ProducesTimertimer=newTimer(newSlidingTimeWindowReservoir(1L,HOURS));

@InjectTimertimer;

Thistimerthatonlykeepsmeasurementoflastminuteisproducedasabeanoftype Timer

Thistimerthatonlykeepsmeasurementoflasthourisproducedasabeanoftype Timer

Thisinjectionpointisambiguoussince2eligiblebeansexist

1

2

3

1

2

3

Solvingtheambiguity

Wecouldusetheprovided @Metric annotationtoqualifyourbeans

@Produces@Metric(name="myTimer")Timertimer=newTimer(newSlidingTimeWindowReservoir(1L,MINUTES));

@Produces@Metric(name="mySecondTimer")Timertimer=newTimer(newSlidingTimeWindowReservoir(1L,HOURS));

@Inject@Metric(name="myTimer")Timertimer;

Thatwon’tworkoutoftheboxsince @Metric isnotaqualifier

Howtomake @Metric aqualifier?

Byobserving BeforeBeanDiscovery lifecycleeventinanextension

publicinterfaceBeforeBeanDiscovery{

addQualifier(Class<?extendsAnnotation>qualifier);addQualifier(AnnotatedType<?extendsAnnotation>qualifier);addScope(Class<?extendsAnnotation>scopeType,booleannormal,booleanpassivation);addStereotype(Class<?extendsAnnotation>stereotype,Annotation...stereotypeDef);addInterceptorBinding(AnnotatedType<?extendsAnnotation>bindingType);addInterceptorBinding(Class<?extendsAnnotation>bindingType,Annotation...bindingTypeDef);addAnnotatedType(AnnotatedType<?>type);addAnnotatedType(AnnotatedType<?>type,Stringid);}

Thismethodistheoneweneedtodeclare @Metric asqualifier

Anduse addQualifier() methodintheevent

1

1

InternalStep HappenOnce LooponElements

BeforeBeanDiscovery isfirstinlifecycle

DeploymentStart

BeforeBean

Discovery

ScanArchive

ProcessAnnotated

Type

AfterType

Discovery

BeanEligibility

Check

ProcessInjectionPoint

ProcessInjectionTarget

ProcessBean

Attributes

ProcessBean

ProcessProducer

ProcessObserverMethod

AfterBean

Discovery

AfterDeploymentValidation

ApplicationRunning

BeforeShutdown

UndeployApplication

Ourfirstextension

ACDIextensionisaclassimplementingthe Extension taginterface

org.cdi.further.metrics.MetricsExtension

publicclassMetricsExtensionimplementsExtension{

voidaddMetricAsQualifier(@ObservesBeforeBeanDiscoverybdd){bdd.addQualifier(Metric.class);}}

Extensionisactivatedbyaddingthisfileto META-INF/services

javax.enterprise.inject.spi.Extension

org.cdi.further.metrics.MetricsExtension

Goal1achieved Wecannowwrite:

@Produces@Metric(name="myTimer")Timertimer=newTimer(newSlidingTimeWindowReservoir(1L,MINUTES));

@Produces@Metric(name="mySecondTimer")Timertimer=newTimer(newSlidingTimeWindowReservoir(1L,HOURS));

@Inject@Metric(name="myTimer")Timertimer;

Andhavethe Timer injectionpointssatisfied

GOAL2ApplyMetricswithprovidedannotations

Goal2indetail Wewanttobeabletowrite:

@Timed("timer")voidtimedMethod(){//...}

Andhavethetimer "timer" activatedduringmethodinvocation

Thesolutionistobuildandinterceptorandbinditto @Timed

1

Goal2stepbystep

Createaninterceptorforthetimertechnicalcode

Make @Timed (providedbyMetrics)avalidinterceptorbinding

Programmaticallyadd @Timed asaninterceptorbinding

Usethemagic

Preparinginterceptorcreation

Weshouldfindthetechnicalcodethatwillwrapthebusinesscode

classTimedMethodBean{

@InjectMetricRegistryregistry;

voidtimedMethod(){Timertimer=registry.timer("timer");Timer.Contexttime=timer.time();try{//Businesscode}finally{time.stop();}}}

Creatingtheinterceptor

Interceptorcodeishighlightedbelow

@InterceptorclassTimedInterceptor{@InjectMetricRegistryregistry;@AroundInvokeObjecttimedMethod(InvocationContextcontext)throwsException{Timertimer=registry.timer(context.getMethod().getAnnotation(Timed.class).name());Timer.Contexttime=timer.time();try{returncontext.proceed();}finally{time.stop();}}}

InCDIaninterceptorisabean,youcaninjectotherbeansinit

Herethebusinessoftheapplicationiscalled.Allthecodearoundisthetechnicalone.

1

2

1

2

Activatingtheinterceptor@Interceptor@Priority(Interceptor.Priority.LIBRARY_BEFORE)classTimedInterceptor{

@InjectMetricRegistryregistry;

@AroundInvokeObjecttimedMethod(InvocationContextcontext)throwsException{Timertimer=registry.timer(context.getMethod().getAnnotation(Timed.class).name());Timer.Contexttime=timer.time();try{returncontext.proceed();}finally{time.stop();}}}

Givinga @Priority toaninterceptoractivatesandordersit

1

1

Addabindingtotheinterceptor@Timed@Interceptor@Priority(Interceptor.Priority.LIBRARY_BEFORE)classTimedInterceptor{

@InjectMetricRegistryregistry;

@AroundInvokeObjecttimedMethod(InvocationContextcontext)throwsException{Timertimer=registry.timer(context.getMethod().getAnnotation(Timed.class).name());Timer.Contexttime=timer.time();try{returncontext.proceed();}finally{time.stop();}}}

We’lluseMetrics @Timed annotationasinterceptorbinding

1

1

Backoninterceptorbinding

Aninterceptorbindingisanannotationusedin2places:

1. Ontheinterceptorclasstobindittothisannotation2. Onthemethodsorclassestobeinterceptedbythisinterceptor

Aninterceptorbindingshouldhavethe @InterceptorBindingannotationorshouldbedeclaredprogrammatically

Iftheinterceptorbindingannotationhasmembers:

1. Theirvaluesaretakenintoaccounttoresolveinterceptor2. Unlessmembersareannotatedwith @NonBinding

@Timed sourcecodeisnotaninterceptorbinding

@Documented@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.TYPE,ElementType.CONSTRUCTOR,ElementType.METHOD,ElementType.ANNOTATION_TYPE})

public@interfaceTimed{

Stringname()default"";

booleanabsolute()defaultfalse;}

Lackof @InterceptorBinding annotation

Noneofthemembershavethe @NonBinding annotation,so @Timed(name="timer1") and@Timed(name="timer2") willbe2differentinterceptorbindings

1

2

2

1

2

Therequired @Timed sourcecodetomakeitaninterceptorbinding

@Documented@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.TYPE,ElementType.CONSTRUCTOR,ElementType.METHOD,ElementType.ANNOTATION_TYPE})@InterceptorBindingpublic@interfaceTimed{

@NonBindingStringname()default"";

@NonBindingbooleanabsolute()defaultfalse;}

Howtoobtaintherequired@Timed ?

Wecannottouchthecomponentsource/binary!

Usingthe AnnotatedType SPI

ThankstoDeltaSpikewecaneasilycreatetherequired AnnotatedType

AnnotatedTypecreateTimedAnnotatedType()throwsException{AnnotationnonBinding=newAnnotationLiteral<Nonbinding>(){};returnnewAnnotatedTypeBuilder().readFromType(Timed.class).addToMethod(Timed.class.getMethod("name"),nonBinding).addToMethod(Timed.class.getMethod("absolute"),nonBinding).create();}

Thiscreatesaninstanceof @NonBinding annotation

Itwouldhavebeenpossiblebutfarmoreverbosetocreatethis AnnotatedType withoutthehelpofDeltaSpike.The AnnotatedTypeBuilder isinitializedfromtheMetrics @Timed annotation.

@NonBinding isaddedtobothmembersofthe @Timed annotation

123

3

1

2

3

Thisextensionwilldothejob

Weobserve BeforeBeanDiscovery toaddanewinterceptorbinding

publicclassMetricsExtensionimplementsExtension{

voidaddTimedBinding(@ObservesBeforeBeanDiscoverybdd)throwsException{AnnotationnonBinding=newAnnotationLiteral<Nonbinding>(){};

bdd.addInterceptorBinding(newAnnotatedTypeBuilder<Timed>().readFromType(Timed.class).addToMethod(Timed.class.getMethod("name"),nonBinding).addToMethod(Timed.class.getMethod("absolute"),nonBinding).create());}}

Goal2achieved Wecannowwrite:

@Timed("timer")voidtimedMethod(){//Businesscode}

AndhaveaMetricsTimer appliedtothemethod

Interceptorshouldbeenhancedtosupport @Timed onaclass

Otherinterceptorshouldbedevelopedforothermetrics

Ourgoals1. ApplyametricwiththeprovidedannotationinAOPstyle

@Timed("timer")voidtimedMethod(){//...}

2. Registerautomaticallyproducedcustommetrics@Produces@Metric(name="myTimer")Timertimer=newTimer(newSlidingTimeWindowReservoir(1L,MINUTES));//...@Timed("myTimer")voidtimedMethod(){/*...*/}

AnnotationsprovidedbyMetrics

1

1

1

1

GOAL3AccesssameMetricthrough@InjectorMetricRegistry getter

Goal3indetail WhenWriting:

@Inject@Metric(name="myTimer")Timertimer1;

@InjectMetricRegistryregistry;

Timertimer2=registry.timer("myTimer");

… Wewantthat timer1==timer2

Goal3indetail@Produces@Metric(name="myTimer")Timertimer=newTimer(newSlidingTimeWindowReservoir(1L,TimeUnit.MINUTES));

@Inject@Metric(name="myTimer")Timertimer;

@InjectMetricRegistryregistry;

Timertimer=registry.timer("myTimer");

Produced Timer shouldbeaddedtoMetricRegistrywhenproduced

Whenretrievedfromregistrya Metric shouldbeidenticaltotheproducedinstanceandviceversa

Thereare2 Metric :the com.codahale.metrics.Metric interfaceandthe com.codahale.metrics.annotation.Metric annotation

1

2

1

2

Goal3stepbystep

Weneedtowriteanextensionthatwill:

1. Changehowa Metric instanceisproducedbylookingitupintheregistryfirstandproducing(andregistering)itonlyifit’snotfound.We’lldothisby:1. observingthe ProcessProducer lifecycleevent2. decoratingMetric Producer toaddthisnewbehavior

2. Produceall Metric instancesattheendofboottimetohavetheminregistryforruntime1. we’lldothisbyobserving AfterDeploymentValidation event

InternalStep HappenOnce LooponElements

Sowewill @Observes these2eventstoaddourfeatures

DeploymentStart

BeforeBean

Discovery

ScanArchive

ProcessAnnotated

Type

AfterType

Discovery

BeanEligibility

Check

ProcessInjectionPoint

ProcessInjectionTarget

ProcessBean

Attributes

ProcessBean

ProcessProducer

ProcessObserverMethod

AfterBean

Discovery

AfterDeploymentValidation

ApplicationRunning

BeforeShutdown

UndeployApplication

Customizing Metric producingprocess

Wefirstneedtocreateourimplementationofthe Producer<X> SPI

classMetricProducer<XextendsMetric>implementsProducer<X>{

finalProducer<X>decorate;

finalStringmetricName;

MetricProducer(Producer<X>decorate,StringmetricName){this.decorate=decorate;this.metricName=metricName;}

//...

Customizing Metric producingprocess(continued)//...publicXproduce(CreationalContext<X>ctx){MetricRegistryreg=BeanProvider.getContextualReference(MetricRegistry.class,false);if(!reg.getMetrics().containsKey(metricName))reg.register(metricName,decorate.produce(ctx));

return(X)reg.getMetrics().get(metricName);}

publicvoiddispose(Xinstance){}

publicSet<InjectionPoint>getInjectionPoints(){returndecorate.getInjectionPoints();}}

Producemethodwillbeusedbythecontaineratruntimetodecoratedeclaredproducerwithourlogic

BeanProvider isaDeltaSpikehelperclasstoeasilyretrieveabeanorbeaninstance

Ifmetricnameisnotintheregistry,theoriginalproduceriscalledanditsresultisaddedtoregistry

12

3

1

2

3

We’lluseour MetricProducer ina ProcessProducer observer

Thiseventallowustosubstitutetheoriginalproducerbyours

publicinterfaceProcessProducer<T,X>{

AnnotatedMember<T>getAnnotatedMember();

Producer<X>getProducer();

voidsetProducer(Producer<X>producer);

voidaddDefinitionError(Throwablet);}

Getsthe AnnotatedMember associatedtothe @Produces fieldormethod

Getsthedefaultproducer(usefultodecorateit)

Overridestheproducer

1

2

3

1

2

3

Customizing Metric producingprocess(end)

Here’stheextensioncodetodothisproducerdecoration

publicclassMetricsExtensionimplementsExtension{//...<XextendsMetric>voiddecorateMetricProducer(@ObservesProcessProducer<?,X>pp){Stringname=pp.getAnnotatedMember().getAnnotation(Metric.class).name();pp.setProducer(newMetricProducer<>(pp.getProducer(),name));}//...}

Weretrievemetricnamefromthe name() memberin @Metric

Wereplacetheoriginalproducerbyourproducer(whichdecoratestheformer)

12

1

2

Producingallthe Metric instancesattheendofboottime

Wedothatbyobservingthe AfterDeploymentValidation event

publicclassMetricsExtensionimplementsExtension{//...voidregisterProducedMetrics(@ObservesAfterDeploymentValidationadv){List<Metric>metrics=BeanProvider.getContextualReferences(Metric.class,true);}//...}

getContextualReferences() isamethodinDeltaSpike BeanProvider helperclass.Itcreatesthelistofbeaninstancesforagivenbeantype(ignoringqualifiers)

1

1

Goal3achieved

Wecannowwrite:

@Produces@Metric(name="myTimer")Timertimer=newTimer(newSlidingTimeWindowReservoir(1L,TimeUnit.MINUTES));

@InjectMetricRegistryregistry;

@Inject@Metric("myTimer")Metrictimer;

Andbesurethat registry.getMetrics().get("myTimer") andtimer arethesameobject(ourcustom Timer )

CompleteextensioncodepublicclassMetricsExtensionimplementsExtension{

voidaddMetricAsQualifier(@ObservesBeforeBeanDiscoverybdd){bdd.addQualifier(Metric.class);}

voidaddTimedBinding(@ObservesBeforeBeanDiscoverybdd)throwsException{AnnotationnonBinding=newAnnotationLiteral<Nonbinding>(){};bdd.addInterceptorBinding(newAnnotatedTypeBuilder<Timed>().readFromType(Timed.class).addToMethod(Timed.class.getMethod("name"),nonBinding).addToMethod(Timed.class.getMethod("absolute"),nonBinding).create());}

<Textendscom.codahale.metrics.Metric>voiddecorateMetricProducer(@ObservesProcessProducer<?,T>pp){if(pp.getAnnotatedMember().isAnnotationPresent(Metric.class)){Stringname=pp.getAnnotatedMember().getAnnotation(Metric.class).name();pp.setProducer(newMetricProducer(pp.getProducer(),name));}}

voidregisterProducedMetrics(@ObservesAfterDeploymentValidationadv){List<com.codahale.metrics.Metric>metrics=BeanProvider.getContextualReferences(com.codahale.metrics.Metric.class,true);}}

HowtouseCDIasdependencyinjectioncontainerforanintegrationframework(ApacheCamel)

CamelCDI

AboutApacheCamel

Open-sourceintegrationframeworkbasedonknownEnterpriseIntegrationPatterns

ProvidesavarietyofDSLstowriteroutingandmediationrules

ProvidessupportforbeanbindingandseamlessintegrationwithDIframeworks

DiscoverhowwecreatedCDIintegrationmoduleforCamel

Cameloutofthebox(withoutCDI)publicstaticvoidmain(String[]args){CamelContextcontext=newDefaultCamelContext();context.addRoutes(newRouteBuilder(){publicvoidconfigure(){from("file:target/input?delay=1000").log("Sendingmessage[${body}]toJMS...").to("sjms:queue:output");}});PropertiesComponentproperties=newPropertiesComponent();properties.setLocation("classpath:camel.properties");context.addComponent("properties",properties);//Registersthe"properties"component

SjmsComponentcomponent=newSjmsComponent();component.setConnectionFactory(newActiveMQConnectionFactory("vm://broker?broker.persistent=false"));jms.setConnectionCount(Integer.valueOf(context.resolvePropertyPlaceholders("{{jms.maxConnections}}")));context.addComponent("sjms",jms);//Registersthe"sjms"component

context.start();}

ThisroutewatchesadirectoryeverysecondandsendsnewfilescontenttoaJMSqueue

1

1

WhyCDI?

BasicCDIintegration(1/3)1. CamelcomponentsandroutebuilderasCDIbeans2. BindtheCamelcontextlifecycletothatoftheCDIcontainer

classFileToJmsRouteBeanextendsRouteBuilder{

@Overridepublicvoidconfigure(){from("file:target/input?delay=1000").log("Sendingmessage[${body}]toJMS...").to("sjms:queue:output");}}

BasicCDIintegration(2/3)classPropertiesComponentFactoryBean{

@Produces@ApplicationScopedPropertiesComponentpropertiesComponent(){PropertiesComponentproperties=newPropertiesComponent();properties.setLocation("classpath:camel.properties");returnproperties;}}

classJmsComponentFactoryBean{

@Produces@ApplicationScopedSjmsComponentsjmsComponent(PropertiesComponentproperties)throwsException{SjmsComponentjms=newSjmsComponent();jms.setConnectionFactory(newActiveMQConnectionFactory("vm://broker?broker.persistent=false"));jms.setConnectionCount(Integer.valueOf(properties.parseUri("{{jms.maxConnections}}")));returncomponent;}}

BasicCDIintegration(3/3)@ApplicationScopedclassCamelContextBeanextendsDefaultCamelContext{

@InjectCamelContextBean(FileToJmsRouteBeanroute,SjmsComponentjms,PropertiesComponentproperties){addComponent("properties",properties);addComponent("sjms",jms);addRoutes(route);}@PostConstructvoidstartContext(){super.start();}@PreDestroyvoidpreDestroy(){super.stop();}}

WecouldhavealotmorewithadvancedCDIfeatures

Ourgoals1. Avoidassemblingandconfiguringthe CamelContext manually2. AccessCDIbeansfromtheCamelDSLautomatically

.to("sjms:queue:output");//Lookupbyname(sjms)andtype(Component)

context.resolvePropertyPlaceholders("{{jms.maxConnections}}");//Lookupbyname(properties)andtype(Component)

3. SupportCamelannotationsinCDIbeans@PropertyInject(value="jms.maxConnections",defaultValue="10")intmaxConnections;

StepstointegrateCamelandCDI

Managethecreationandtheconfigurationofthe CamelContextbean

Bindthe CamelContext lifecycletothatoftheCDIcontainer

ImplementtheCamelregistrySPItolookupCDIbeanreferences

Useacustom InjectionTarget forCDIbeanscontainingCamelannotations

Usethemagic

Howtoachievethis?

Weneedtowriteanextensionthatwill:

1. Declarea CamelContext beanbyobservingthe AfterBeanDiscoverylifecycleevent

2. Instantiatethebeansoftype RouteBuilder andaddthemtotheCamelcontext

3. Start(resp.stop)theCamelcontextwhentheAfterDeploymentValidation eventisfired(resp.the BeforeShutdownevent)

4. CustomizetheCamelcontexttoquerythe BeanManager tolookupCDIbeansbynameandtype

5. DetectCDIbeanscontainingCamelannotationsbyobservingtheProcessAnnotatedType eventandmodifyhowtheygetinjectedbyobservingthe ProcessInjectionTarget lifecycleevent

InternalStep HappenOnce LooponElements

Sowewill @Observes these5eventstoaddourfeatures

DeploymentStart

BeforeBean

Discovery

ScanArchive

ProcessAnnotated

Type

AfterType

Discovery

BeanEligibility

Check

ProcessInjectionPoint

ProcessInjectionTarget

ProcessBean

Attributes

ProcessBean

ProcessProducer

ProcessObserverMethod

AfterBean

Discovery

AfterDeploymentValidation

ApplicationRunning

BeforeShutdown

UndeployApplication

Addingthe CamelContext bean

Automaticallyadda CamelContext beaninthedeploymentarchive

Howtoaddabeanprogrammatically?

Declaringabeanprogrammatically

Weneedtoimplementthe Bean SPI

publicinterfaceBean<T>extendsContextual<T>,BeanAttributes<T>{

Class<?>getBeanClass();Set<InjectionPoint>getInjectionPoints();Tcreate(CreationalContext<T>creationalContext);//Contextual<T>voiddestroy(Tinstance,CreationalContext<T>creationalContext);Set<Type>getTypes();//BeanAttributes<T>Set<Annotation>getQualifiers();Class<?extendsAnnotation>getScope();StringgetName();Set<Class<?extendsAnnotation>>getStereotypes();booleanisAlternative();}

Implementingthe Bean SPIclassCamelContextBeanimplementsBean<CamelContext>{

publicClass<?extendsAnnotation>getScope(){returnApplicationScoped.class;}

publicSet<Annotation>getQualifiers(){returnCollections.<Annotation>singleton(newAnnotationLiteral<Default>(){});}publicSet<Type>getTypes(){returnCollections.<Type>singleton(CamelContext.class);}

publicCamelContextcreate(CreationalContext<CamelContext>creational){returnnewDefaultCamelContext();}publicvoiddestroy(CamelContextinstance,CreationalContext<CamelContext>creational){}

publicClass<?>getBeanClass(){returnDefaultCamelContext.class;}

publicSet<InjectionPoint>getInjectionPoints(){returnCollections.emptySet();}

publicSet<Class<?extendsAnnotation>>getStereotypes(){returnCollections.emptySet();}publicStringgetName(){returnnull;}//Onlycalledfor@NamedbeanpublicbooleanisAlternative(){returnfalse;}publicbooleanisNullable(){returnfalse;}}

Addingaprogrammaticbeantothedeployment

Thenaddthe CamelContextBean beanprogrammaticallybyobservingthe AfterBeanDiscovery lifecycleevent

publicclassCamelExtensionimplementsExtension{

voidaddCamelContextBean(@ObservesAfterBeanDiscoveryabd){abd.addBean(newCamelContextBean());}}

InstantiateandassembletheCamelcontext

Instantiatethe CamelContext beanandthe RouteBuilder beansintheAfterDeploymentValidation lifecycleevent

publicclassCamelExtensionimplementsExtension{//...voidconfigureContext(@ObservesAfterDeploymentValidationadv,BeanManagerbm){CamelContextcontext=getReference(bm,CamelContext.class);for(Bean<?>bean:bm.getBeans(RoutesBuilder.class))context.addRoutes(getReference(bm,RouteBuilder.class,bean));}<T>TgetReference(BeanManagerbm,Class<T>type){returngetReference(bm,type,bm.resolve(bm.getBeans(type)));}<T>TgetReference(BeanManagerbm,Class<T>type,Bean<?>bean){return(T)bm.getReference(bean,type,bm.createCreationalContext(bean));}}

ManagedtheCamelcontextlifecycle

Start(resp.stop)theCamelcontextwhentheAfterDeploymentValidation eventisfired(resp.the BeforeShutdown )

publicclassCamelExtensionimplementsExtension{//...voidconfigureContext(@ObservesAfterDeploymentValidationadv,BeanManagerbm){CamelContextcontext=getReference(bm,CamelContext.class);for(Bean<?>bean:bm.getBeans(RoutesBuilder.class)context.addRoutes(getReference(bm,RouteBuilder.class,bean);context.start();}voidstopCamelContext(@ObservesBeforeShutdownbs,BeanManagerbm){CamelContextcontext=getReference(bm,CamelContext.class);context.stop();}}

Firstgoalachieved

Wecangetridofthefollowingcode:

@ApplicationScopedclassCamelContextBeanextendsDefaultCamelContext{@InjectCamelContextBean(FileToJmsRouteBeanroute,SjmsComponentjms,PropertiesComponentproperties){addComponent("properties",propertiesComponent);addComponent("sjms",sjmsComponent);addRoutes(route);}@PostConstructvoidstartContext(){super.start();}@PreDestroyvoidstopContext(){super.stop();}}

Secondgoal:AccessCDIbeansfromtheCamelDSL

HowtoretrieveCDIbeansfromtheCamelDSL?

.to("sjms:queue:output");//Lookupbyname(sjms)andtype(Component)context.resolvePropertyPlaceholders("{{jms.maxConnections}}");//Lookupbyname(properties)andtype(Component)

//Andalso....bean(MyBean.class);//LookupbytypeandDefaultqualifier.beanRef("beanName");//Lookupbyname

ImplementtheCamelregistrySPIandusethe BeanManager tolookupforCDIbeancontextualreferencesbynameandtype

ImplementtheCamelregistrySPIclassCamelCdiRegistryimplementsRegistry{privatefinalBeanManagerbm;

CamelCdiRegistry(BeanManagerbm){this.bm=bm;}

public<T>TlookupByNameAndType(Stringname,Class<T>type){returngetReference(bm,type,bm.resolve(bm.getBeans(name)));}public<T>Set<T>findByType(Class<T>type){returngetReference(bm,type,bm.resolve(bm.getBeans(type)));}publicObjectlookupByName(Stringname){returnlookupByNameAndType(name,Object.class);}<T>TgetReference(BeanManagerbm,Typetype,Bean<?>bean){return(T)bm.getReference(bean,type,bm.createCreationalContext(bean));}}

Addthe CamelCdiRegistry totheCamelcontext

classCamelContextBeanimplementsBean<CamelContext>{privatefinalBeanManagerbm;

CamelContextBean(BeanManagerbm){this.bm=bm;}//...publicCamelContextcreate(CreationalContext<CamelContext>creational){returnnewDefaultCamelContext(newCamelCdiRegistry(bm));}}

publicclassCamelExtensionimplementsExtension{//...voidaddCamelContextBean(@ObservesAfterBeanDiscoveryabd,BeanManagerbm){abd.addBean(newCamelContextBean(bm));}}

Secondgoalachieved1/3

Wecandeclarethe sjms componentwiththe @Named qualifier

classJmsComponentFactoryBean{

@Produces@Named("sjms")@ApplicationScopedSjmsComponentsjmsComponent(PropertiesComponentproperties){SjmsComponentjms=newSjmsComponent();jms.setConnectionFactory(newActiveMQConnectionFactory("vm://broker?..."));jms.setConnectionCount(Integer.valueOf(properties.parseUri("{{jms.maxConnections}}")));returncomponent;}}

Secondgoalachieved2/3

Declarethe properties componentwiththe @Named qualifier

classPropertiesComponentFactoryBean{

@Produces@Named("properties")@ApplicationScopedPropertiesComponentpropertiesComponent(){PropertiesComponentproperties=newPropertiesComponent();properties.setLocation("classpath:camel.properties");returnproperties;}}

Secondgoalachieved3/3

Andgetridofthecoderelatedtothe properties and sjmscomponentsregistration

@ApplicationScopedclassCamelContextBeanextendsDefaultCamelContext{@InjectCamelContextBean(FileToJmsRouteBeanroute,SjmsComponentjms,PropertiesComponentproperties){addComponent("properties",propertiesComponent);addComponent("sjms",sjmsComponent);addRoutes(route);}@PostConstructvoidstartContext(){super.start();}@PreDestroyvoidstopContext(){super.stop();}}

Thirdgoal:SupportCamelannotationsinCDIbeans

CamelprovidesasetofDIframeworkagnosticannotationsforresourceinjection

@PropertyInject(value="jms.maxConnections",defaultValue="10")intmaxConnections;

//Butalso...@EndpointInject(uri="jms:queue:foo")Endpointendpoint;

@BeanInject("foo")FooBeanfoo;

Howtosupportcustomannotationsinjection?

Howtosupportcustomannotationsinjection?

Createacustom InjectionTarget thatusesthedefaultCamelbeanpostprocessor DefaultCamelBeanPostProcessor

publicinterfaceInjectionTarget<T>extendsProducer<T>{voidinject(Tinstance,CreationalContext<T>ctx);voidpostConstruct(Tinstance);voidpreDestroy(Tinstance);}

HookitintotheCDIinjectionmechanismbyobservingtheProcessInjectionTarget lifecycleevent

OnlyforbeanscontainingCamelannotationsbyobservingtheProcessAnnotatedType lifecycleandusing @WithAnnotations

Createacustom InjectionTargetclassCamelInjectionTarget<T>implementsInjectionTarget<T>{

finalInjectionTarget<T>delegate;

finalDefaultCamelBeanPostProcessorprocessor;

CamelInjectionTarget(InjectionTarget<T>target,finalBeanManagerbm){delegate=target;processor=newDefaultCamelBeanPostProcessor(){publicCamelContextgetOrLookupCamelContext(){returngetReference(bm,CamelContext.class);}};}publicvoidinject(Tinstance,CreationalContext<T>ctx){processor.postProcessBeforeInitialization(instance,null);delegate.inject(instance,ctx);}//...}

CalltheCameldefaultbeanpost-processorbeforeCDIinjection

1

1

Registerthecustom InjectionTarget

Observethe ProcessInjectionTarget lifecycleeventandsettheInjectionTarget

publicinterfaceProcessInjectionTarget<X>{AnnotatedType<X>getAnnotatedType();InjectionTarget<X>getInjectionTarget();voidsetInjectionTarget(InjectionTarget<X>injectionTarget);voidaddDefinitionError(Throwablet);}

Todecorateitwiththe CamelInjectionTarget

classCamelExtensionimplementsExtension{

<T>voidcamelBeansPostProcessor(@ObservesProcessInjectionTarget<T>pit,BeanManagerbm){pit.setInjectionTarget(newCamelInjectionTarget<>(pit.getInjectionTarget(),bm));}}

ButonlyforbeanscontainingCamelannotationsclassCamelExtensionimplementsExtension{finalSet<AnnotatedType<?>>camelBeans=newHashSet<>();

voidcamelAnnotatedTypes(@Observes@WithAnnotations(PropertyInject.class)ProcessAnnotatedType<?>pat){camelBeans.add(pat.getAnnotatedType());}

<T>voidcamelBeansPostProcessor(@ObservesProcessInjectionTarget<T>pit,BeanManagerbm){if(camelBeans.contains(pit.getAnnotatedType()))pit.setInjectionTarget(newCamelInjectionTarget<>(pit.getInjectionTarget(),bm));}}

DetectallthetypescontainingCamelannotationswith @WithAnnotations

Decoratethe InjectionTarget correspondingtothesetypes

1

2

1

2

Thirdgoalachieved1/2

Insteadofinjectingthe PropertiesComponent beantoresolveaconfigurationproperty

classJmsComponentFactoryBean{

@Produces@Named("sjms")@ApplicationScopedSjmsComponentsjmsComponent(PropertiesComponentproperties){SjmsComponentjms=newSjmsComponent();jms.setConnectionFactory(newActiveMQConnectionFactory("vm://broker?..."));jms.setConnectionCount(Integer.valueOf(properties.parseUri("{{jms.maxConnections}}")));returncomponent;}}

Thirdgoalachieved2/2

Wecandirectlyrelyonthe @PropertyInject CamelannotationinCDIbeans

classJmsComponentFactoryBean{

@PropertyInject("jms.maxConnections")intmaxConnections;

@Produces@Named("sjms")@ApplicationScopedSjmsComponentsjmsComponent(){SjmsComponentcomponent=newSjmsComponent();jms.setConnectionFactory(newActiveMQConnectionFactory("vm://broker?..."));component.setConnectionCount(maxConnections);returncomponent;}}

Bonusgoal:CamelDSLAOP

AOPinstrumentationoftheCamelDSL

from("file:target/input?delay=1000").log("Sendingmessage[${body}]toJMS...").to("sjms:queue:output");

WithCDIobservers

from("file:target/input?delay=1000").to("sjms:queue:output").id("joinpoint");}voidadvice(@Observes@NodeId("joinpoint")Exchangeexchange){logger.info("Sendingmessage[{}]toJMS...",exchange.getIn().getBody());}

Howtoachievethis?

WecancreateaCDIqualifiertoholdtheCamelnodeidmetadata:

@Qualifier@Retention(RetentionPolicy.RUNTIME)public@interfaceNodeId{Stringvalue();}

Andcreateanextensionthatwill:

1. DetecttheCDIbeanscontainingobservermethodswiththe @NodeIdqualifierbyobservingthe ProcessObserverMethod eventandcollecttheCamelprocessornodestobeinstrumented

2. CustomizetheCamelcontextbyprovidinganimplementationoftheCamel InterceptStrategy interfacethatwillfireaCDIeventeachtimean Exchange isprocessedbytheinstrumentednodes

DetecttheCamelDSLAOPobservermethods

Observethe ProcessObserverMethod lifecycleevent

publicinterfaceProcessObserverMethod<T,X>{AnnotatedMethod<X>getAnnotatedMethod();ObserverMethod<T>getObserverMethod();voidaddDefinitionError(Throwablet);}

Andcollecttheobservermethodmetadata

classCamelExtensionimplementsExtension{finalSet<NodeId>joinPoints=newHashSet<>();

voidpointcuts(@ObservesProcessObserverMethod<Exchange,?>pom){for(Annotationqualifier:pom.getObserverMethod().getObservedQualifiers())if(qualifierinstanceofNodeId)joinPoints.add(NodeId.class.cast(qualifier));}}

InstrumenttheCamelcontext

InterceptmatchingnodesandfireaCDIevent

voidconfigureCamelContext(@ObservesAfterDeploymentValidationadv,finalBeanManagermanager){context.addInterceptStrategy(newInterceptStrategy(){publicProcessorwrapProcessorInInterceptors(CamelContextcontext,ProcessorDefinition<?>definition,Processortarget,ProcessornextTarget)throwsException{if(definition.hasCustomIdAssigned()){for(finalNodenode:joinPoints){if(node.value().equals(definition.getId())){returnnewDelegateAsyncProcessor(target){publicbooleanprocess(Exchangeexchange,AsyncCallbackcallback){manager.fireEvent(exchange,node);returnsuper.process(exchange,callback);}};}}}returntarget;}});}

Bonusgoalachieved

WecandefinejoinpointsintheCamelDSL

from("file:target/input?delay=1000").to("sjms:queue:output").id("joinpoint");}

AndadvisethemwithCDIobservers

voidadvice(@Observes@NodeId("joinpoint")Exchangeexchange){List<MessageHistory>history=exchange.getProperty(Exchange.MESSAGE_HISTORY,List.class);logger.info("Sendingmessage[{}]to[{}]...",exchange.getIn().getBody(String.class),history.get(history.size()-1).getNode().getLabel());}

Conclusion

References

CDISpecification-cdi-spec.org

Slidessources-github.com/astefanutti/further-cdi

MetricsCDIsources-github.com/astefanutti/metrics-cdi

CamelCDIsources-github.com/astefanutti/camel-cdi

SlidesgeneratedwithAsciidoctor,PlantUMLandDZSlidesbackend

Originalslidetemplate-DanAllen&SarahWhite

AntoineSabot-DurandAntoninStefanutti@antoine_sd@astefanut

Annexes

CompletelifecycleeventsApplication lifecycle

BeforeBeanDiscovery

AfterTypeDiscovery

AfterBeanDiscovery

AfterDeploymentValidation

Type Discovery

ProcessAnnotatedType<X>

yes

whiletypesindeploymentarchive?

no

Bean Discovery

For each discovered types during type discovery

ProcessInjectionPoint<T,X>

ProcessInjectionTarget<X>

ProcessBeanAttributes<T>

ProcessManagedBean<X>

For each producer methods / fields of enabled beans

ProcessInjectionPoint<T,X>

ProcessProducer<T,X>

ProcessBeanAttributes<T>

ProcessProducerMethod<T,X>ProcessProducerField<T,X>

For each observer methods of enabled beans

ProcessInjectionPoint<T,X>

ProcessObserverMethod<T,X>

top related