On 13 Aug 2009, at 15:19, Kenneth Saks wrote:
On Aug 13, 2009, at 7:43 AM, Pete Muir wrote:
> Here we need to address a slightly different aspect of managed bean
> lifecycles when CDI is enabled. This has the most impact on EJBs, as
> they are currently the only other direct instantiator of managed
> beans.
>
> After speaking to Gavin yesterday, and closely reading the latest CDI
> spec, I've noticed that CDI now expects EJB to delegate EJB instance
> creation to CDI, when CDI is enabled in the application. The reason
> for this is to allow EJBs to support constructor injection. IMO there
> are three extremely strong reasons why we need to support this:
>
> 1) Constructor injection is a (very) good thing, because it allows
> you
> to make a class fully immutable. This will make EJBs a more
> attractive
> programming model.
> 2) For a developer, it makes adding EJB services to your EJB (or
> removing them) more transparent as constructor injections don't have
> to be altered
> 3) it's required by the 330 and 299 specs
>
> CDI provides an SPI specifically for this purpose with
> InjectionTarget.produce(), so I propose we add a requirement that Web
> Beans integrators have their EJB container call
> injectionTarget.produce() when CDI is enabled in an application to
> create a bean instance.
>
> Clearly, an integrator wouldn't want to hardcode this into their EJB
> container, so a logical way to implement this would be for the EJB
> container to provide a (non-portable) SPI that defines lifecycle
> control for bean instances, along with a default implementation. The
> SPI could look something like this - default implementation also
> described:
I think we'll also need to somehow capture the association to the
actual EJB component
(e.g. the corresponding org.jboss.webbeans.ejb.spi.EjbDescriptor),
since that can't
necessarily be derived from the bean class type alone.
Yes, this would allow us to actually use the Bean instance rather than
a generic InjectionTarget. We will need therefore to a Web Beans (not
CDI) SPI for this:
/**
* Provides bean management above that which
* is required by the spec
*/
interface WebBeansManager {
....
/**
* Create an InjectionTarget for a session bean
*
* @param descriptor the container provided
* EjbDescriptor to create the session
* bean injection target
*/
InjectionTarget createInjectionTarget(EjbDescriptor descriptor);
}
WDYT?
>
> * newInstance() - create a new bean instance as required by EJB spec
> * inject() - perform Java EE style injection
> * postConstruct() - call the @PostConstruct method
> * preDestroy() - call the @PreDestroy method
I agree we need newInstance() and inject(), but I'd rather not
delegate
the top-level postConstruct()/preDestroy() operations through the
SPI since it complicates
the case where there are EJB style (ejb-jar.xml / @Interceptors) and/
or CDI style interceptors
associated with the EJB component.
Ok. This is clearly up to an integrator, if you can pass the 299 TCK
like this, it will work great.
Let's add a web beans provided interceptor that the EJB container
will register after any
EJB-style interceptors. That can handle all interceptors that are
specified via
CDI-style metadata.
I was just talking with Carlo about how to do this. Since we are now
doing such deep integration, I would prefer to switch to using an SPI
to specify the interceptors to apply to a session bean. Of course, the
EJB container could choose to use an interceptor to attach them
(essentially moving the built in SPI to the container). I guess such
an SPI would look like [1]:
interface EjbServices {
...
void registerInterceptors(EjbDescriptor<?> descriptor,
Collection<Interceptor<?>> interceptors);
}
This would completely remove the Web Beans built in EJB interceptor
(more flexible for integrators).
[1] An alternative would be to make EjbDescriptor have a
registerInterceptors method, but that means it is no longer just a
descriptor, but something that can affect the EJB container. I don't
like this so much.