问题
Is this possible:
@Inject
@MessageTransport(MessageTransportType.SMS)
public static MessageSender messageSender;
I'm getting a NPE when i'm trying to access this static variable. So I wonder, if it is not possible in general.
Thanks in advance.
回答1:
Not done in general because a static variable cannot have a scope, i.e. it's just one for the whole class (read application) and therefore it doesn't make sense since every instance would try to set it to a new value based on the current scope.
回答2:
It's not possible currently, but it's not impossible in theory.
The other answer suggests that it's not possible, but the explanation describes the way injection worked in Seam 2. I'll try to describe it from memory. Some pseudocode:
@Name("a")
class A() {
@In
B b;
void something() {
b.doTheThing();
}
}
Seam 2 supported injection via BijectionInterceptor. For interceptors to work Seam created proxy instances of components. Here, when the a.something
method is called, it would be intercepted, and the proxified b
instance would indeed be injected right in the a
's instance field b
. If the context in which B
resides is not active in that moment, then the injection would fail, and the a.something
method call would fail too.
Now let's look at the analogous example for CDI:
class A() {
@Inject
B b;
void something() {
b.doTheThing();
}
}
In CDI there are still proxies. But the injection is done differently. CDI introduces the notion of contextual references. It's what is stored in the a.b
field. When a.something
is called nothing interesting happens. There could be no B
instance in any context, and the a.something
method would still be called just fine. But when it comes to calling the b.doTheThing
method - that's when CDI starts looking for the actual B
instance. That's when there is a possibility of getting a ContextNotActiveException
for example.
So it's seems possible. I've found some interesting notes at the old Weld site, which could explain as to why this is not implemented yet:
Static injection
Injection for static members has a couple of problems:
- A class can be shared between multiple applications, and the Java EE spec does not define rules for this.
- Outside Java EE, it's difficult to define exactly when a static member is injected.
Nevertheless, there are a couple of great usecases for this:
- logger injection,
- injection for entity classes, and
- injection into objects with a passivating scope.
So we do need to support something here. Perhaps it would be enough to say:
- no static injection in shared libraries, and
- static fields are injected before the very first instance of a bean is instantiated (but then static injection would not be supported for non-bean classes).
There is an open CDI issue dedicated to static injection: CDI-51.
回答3:
Obviously you shouldn't do it, but sometimes I suppose you have to since sometimes there are objects instantiated by something else (for example using ServiceLoader
) in some library and you'd like to inject them. Here's a hack you can do:
class StaticallyInjected {
private static MyBean bean;
void inject (@Observes @Initialized (ApplicationScoped.class) Object x,
MyBean bean) {
StaticallyInjected.bean = bean;
}
}
来源:https://stackoverflow.com/questions/19225179/is-it-possible-to-inject-a-cdi-bean-into-a-static-variable-in-java-ee-6