Dependency injection
or
inversion of control
is by now a familiar concept to most Java developers. Dependency injection allows a component to obtain a reference to another component by having the container "inject" the other component to a setter method or instance variable. In all dependency injection implementations that we have seen, injection occurs when the component is constructed, and the reference does not subsequently change for the lifetime of the component instance. For stateless components, this is reasonable. From the point of view of a client, all instances of a particular stateless component are interchangeable. On the other hand, Seam emphasizes the use of stateful components. So traditional dependency injection is no longer a very useful construct. Seam introduces the notion of
bijection
as a generalization of injection. In contrast to injection, bijection is:
-
contextual
- bijection is used to assemble stateful components from various different contexts (a component from a "wider" context may even have a reference to a component from a "narrower" context)
-
bidirectional
- values are injected from context variables into attributes of the component being invoked, and also
outjected
from the component attributes back out to the context, allowing the component being invoked to manipulate the values of contextual variables simply by setting its own instance variables
-
dynamic
- since the value of contextual variables changes over time, and since Seam components are stateful, bijection takes place every time a component is invoked
In essence, bijection lets you alias a context variable to a component instance variable, by specifying that the value of the instance variable is injected, outjected, or both. Of course, we use annotations to enable bijection.
The @In
annotation specifies that a value should be injected, either into an instance variable:
@Name("loginAction")
@Stateless
@Interceptors(SeamInterceptor.class)
public class LoginAction implements Login {
@In User user;
...
}
or into a setter method:
@Name("loginAction")
@Stateless
@Interceptors(SeamInterceptor.class)
public class LoginAction implements Login {
User user;
@In
public void setUser(User user) {
this.user=user;
}
...
}
By default, Seam will do a priority search of all contexts, using the name of the property or instance variable that is being injected. You may wish to specify the context variable name explicitly, using, for example, @In("currentUser")
.
If you want Seam to create an instance of the component when there is no existing component instance bound to the named context variable, you should specify @In(create=true)
. If the value is optional (it can be null), specify @In(required=false)
.
For some components, it can be repetitive to have to specify @In(create=true)
everywhere they are used. In such cases, you can annotate the component @AutoCreate
, and then it will always be created, whenever needed, even without the explicit use of create=true
.
You can even inject the value of an expression:
@Name("loginAction")
@Stateless
@Interceptors(SeamInterceptor.class)
public class LoginAction implements Login {
@In("#{user.username}") String username;
...
}
(There is much more information about component lifecycle and injection in the next chapter.)
The @Out
annotation specifies that an attribute should be outjected, either from an instance variable:
@Name("loginAction")
@Stateless
@Interceptors(SeamInterceptor.class)
public class LoginAction implements Login {
@Out User user;
...
}
or from a getter method:
@Name("loginAction")
@Stateless
@Interceptors(SeamInterceptor.class)
public class LoginAction implements Login {
User user;
@Out
public User getUser() {
return user;
}
...
}
An attribute may be both injected and outjected:
@Name("loginAction")
@Stateless
@Interceptors(SeamInterceptor.class)
public class LoginAction implements Login {
@In @Out User user;
...
}
or:
@Name("loginAction")
@Stateless
@Interceptors(SeamInterceptor.class)
public class LoginAction implements Login {
User user;
@In
public void setUser(User user) {
this.user=user;
}
@Out
public User getUser() {
return user;
}
...
}