官术网_书友最值得收藏!

What does it mean to be a bean?

According to the CDI specification:

A bean comprises the following attributes:

  • A (non-empty) set of bean types
  • A (non-empty) set of qualifiers
  • A scope
  • Optionally, a bean EL name
  • A set of interceptor bindings
  • A bean implementation

Furthermore, a bean may or may not be an alternative.

Bean types

In most cases, beans acquire references to other beans through dependency injection. The point at which a bean is injected will specify the type of that bean and a set of qualifiers. With the help of the bean type and qualifiers, Weld determines the implementation of a bean to provide for injection.

A bean type can be a class or interface that is visible to clients that wish to inject it. For instance, an EJB Session Bean implementation is not visible to clients, but its @Local interface is visible.

Note

EJB remote interfaces are not bean types of a Session Bean, and therefore they cannot be injected directly. They must be injected by defining a resource.

public class CandyStore extends CommonStore
implements Store<Candy> {
  ...
}

In this Java class, there are four bean types defined: CandyStore, CommonStore, Store<Candy>, and the implicit type java.lang.Object. An interesting point to note is that a parameterized type is considered a bean type by CDI, but only if it contains an actual type parameter and not a wildcard.

We are able to restrict which bean types are valid for any given Java class with the @Typed annotation by providing a defined set of bean types that can be accepted. We can restrict the types from the previous example to only Store<Candy> and the implicit java.lang.Object type, with the following:

@Typed(Store.class)
public class CandyStore extends CommonStore
implements Store<Candy> {
  ...
}

Qualifiers

A qualifier allows us to disambiguate a type without the need to leave type-safety and revert to string-based names, which we all know are fodder for runtime errors. All we need for defining a qualifier is to create an annotation that is annotated with @Qualifier.

@Qualifier
@Target( { TYPE, METHOD, PARAMETER, FIELD } )
@Retention( RUNTIME )
public @interface User {}

Here, we've defined a qualifier called User. Specifying RUNTIME retention informs the Java VM that we want the annotation information recorded in the class file of any bean that specifies this qualifier, so that it may be read at runtime. The values of TYPE, METHOD, PARAMETER, and FIELD specify valid locations within a bean where the qualifier may be placed.

Note

The @Retention values are found in java.lang.annotation.RetentionPolicy and the @Target values are found in java.lang.annotation.ElementType.

With our qualifier annotation, we are now able to disambiguate an injection point. The following injection point has a bean type of Account and a qualifier of @User:

@Inject
@User
Account userAccount;

The Weld container searches for a bean that matches the same bean type and all the qualifiers and each injection point that has been defined. If Weld doesn't find exactly one match, an error is reported during startup that there is an ambiguous injection point, which is Weld's way of telling you that there are too many beans that match the bean type and qualifiers.

To inform Weld that a bean has a specific qualifier, we annotate the bean class with it. The following bean would match the injection point from the previous code snippet:

@User
public class UserAccount implements Account {
  ...
}
Note

Any bean or injection point that does not explicitly specify a qualifier will have the default qualifier @Default assigned to it.

Scope

In the previous examples, we've utilized the CDI scopes that are provided for us, but what is a scope? A scope is the means by which a bean specifies its lifecycle and the visibility of its instances.

For instance, @SessionScoped binds a bean to a user session and is shared across all requests that execute in the context of that session.

Note

Once a bean is bound to its context, it cannot be removed from that context. The bean will remain in that context until the time the context is destroyed by the container. It's especially important to keep this in mind when developing beans that will hold large amounts of data and for how long that data needs to be retained.

Expression Language (EL)

A bean can be referenced from non-Java code if it supports Unified EL expressions, such as with JSF and JSP pages, but it requires an EL name to be defined.

The @Named annotation specifies the EL name for a bean, as follows:

@Named("book")
public class HistoryBook implements Serializable {
  ...
}

We can now access the bean in a JSF page:

<h:outputText value="#{book.isbn}" />

If we aren't particular about what EL name a bean is given, we can specify @Named without any value and it will default to the unqualified class name, with the first character converted to lower case. In the previous example, this would give us an EL name of historyBook.

Alternatives

If we need to vary which implementation is chosen depending on the deployment environment or some other factor, we can create an alternative bean that can be activated when needed.

For instance, if we want to create a mock or dummy implementation that is only used in testing environments, we can write the following:

@Alternative
public class DummyLogger extends LoggerImpl {
  ...
}

It's general practice to only annotate a bean with @Alternative when there is at least one other implementation of an interface it implements or any of its bean types, otherwise there wouldn't be anything for it to be an alternative of.

Alternatives are chosen by selecting an alternative in the CDI descriptor file, beans.xml, of the JAR or WAR that uses it.

This topic will be covered in greater detail in Chapter 2, Dependency Injection and Lookup.

主站蜘蛛池模板: 揭阳市| 陆丰市| 青海省| 定西市| 深泽县| 白城市| 锡林郭勒盟| 长岭县| 马尔康县| 曲水县| 兴业县| 多伦县| 堆龙德庆县| 色达县| 靖江市| 深泽县| 滨州市| 江西省| 察隅县| 阜平县| 扬中市| 阳谷县| 比如县| 韩城市| 泾源县| 石柱| 前郭尔| 石景山区| 乌兰察布市| 海城市| 平遥县| 阳高县| 阳江市| 石狮市| 政和县| 衡水市| 合水县| 长沙县| 怀宁县| 右玉县| 蒙山县|