使用 Jersey/Glassfish 更正 CDI 注释
Correct CDI annotations with Jersey/Glassfish
由于我正在为有关 CDI 的文档苦苦挣扎,我希望这个问题可以成为一个有用的资源,以便在 Jersey/Glassfish.
中使用正确的 CDI 注释
假设我们有一个应用程序 BookStore
:
package my.bookstore;
import javax.ws.rs.ApplicationPath;
import org.glassfish.jersey.server.ResourceConfig;
@ApplicationPath("/bookstore")
public class BookStore extends ResourceConfig {
public BookStore() {
this.packages("my.bookstore.resource");
}
}
我们想让 Book
个实体可以通过 RESTful 服务访问:
package my.bookstore.entity;
public class Book {
public String isbn;
public String title;
public String author;
public Book(String isbn, String title, String author) {
this.isbn = isbn;
this.title = title;
this.author = author;
}
}
所以我们需要 DAO
来访问数据存储:
package my.bookstore.dao;
import my.bookstore.entity.Book;
import java.util.List;
public interface BookDAO {
public List<Book> getAllBooks();
}
及其实现:
package my.bookstore.dao;
import my.bookstore.entity.Book;
import java.util.List;
import java.util.ArrayList;
public class DefaultBookDAO implements BookDAO {
public List<Book> getAllBooks() {
List<Book> bookList = new ArrayList<>();
list.add(new Book("1234", "Awesome Book", "Some Author"));
return bookList;
}
}
然后我想将 DefaultBookDAO
注入到 RESTful 服务中:
package my.bookstore.resource;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("/books")
public class BookResource {
@Inject
BookDAO dao;
@GET
@Produces(MediaType.APPLICATION_JSON)
public List<Book> getBooks() {
return this.dao.getAllBooks();
}
}
现在,在部署应用程序时我得到:
Unsatisfied dependencies for type BookDAO with qualifiers @Default
因为我需要让 CDI 知道它;但是怎么办?我尝试了 @Named
、@Default
、@Model
、@Singleton
、@Stateless
的各种组合,问题和博客文章等许多资源都有自己的解释。
使此注入在 Jersey/Glassfish 中起作用的正确、简单的 CDI 注释是什么?
由于这是一项服务,您可以用 @Stateless
注释您的 DefaultBookDAO
。
那么你需要一个额外的 class 来实现 AbstractBinder
class。
你的情况应该是这样的:
import org.glassfish.hk2.utilities.binding.AbstractBinder;
public class MyApplicationBinder extends AbstractBinder {
@Override
protected void configure() {
bind(DefaultBookDAO.class).to(BookDAO.class);
}
}
您必须在扩展 ResourceConfig
的 class 中注册此 class,如下所示:
@ApplicationPath("/bookstore")
public class BookStore extends ResourceConfig {
public BookStore() {
register(new MyApplicationBinder());
this.packages("my.bookstore.resource");
}
}
然后 @Inject
应该工作。
另请参阅:
- Jersey docs: Chapter 22. Custom Injection and Lifecycle Management
- Dependency injection with Jersey 2.0
对我来说,您似乎没有将 beans.xml 文件放入您的应用程序中。使用 Glassfish 4(通常使用 Java EE 7)不需要此文件,但是,如果您省略它,则只会考虑使用范围注释进行注释的 bean。因此,由于 DefaultBookDAO 没有被任何注释标记,因此 CDI 不认为它是注入的候选对象。
您有 2 个选项来修复它并使 CDI 机制考虑 DefaultBookDAO:
- 在 DefaultBookDAO class 上放置
@Dependent
注释 - 这不会改变它的范围,因为 @Dependent
是默认范围,但会让 CDI 考虑这个 class
- 在 META-INF 或 WEB-INF(对于网络应用程序)中创建 beans.xml 文件,其值为
bean-discovery-mode="all"
在我看来,第一个选项更清晰 - 您可以轻松区分可以注入和不能注入的代码。但是,如果您想通过省略不必要的注释来提高生产率,请选择第二个选项。它更复杂,但每个模块只需执行一次。
请参阅 this oracle blog post 关于 Java EE 7 中的 beans.xml 以及省略时的默认行为。
由于我正在为有关 CDI 的文档苦苦挣扎,我希望这个问题可以成为一个有用的资源,以便在 Jersey/Glassfish.
中使用正确的 CDI 注释假设我们有一个应用程序 BookStore
:
package my.bookstore;
import javax.ws.rs.ApplicationPath;
import org.glassfish.jersey.server.ResourceConfig;
@ApplicationPath("/bookstore")
public class BookStore extends ResourceConfig {
public BookStore() {
this.packages("my.bookstore.resource");
}
}
我们想让 Book
个实体可以通过 RESTful 服务访问:
package my.bookstore.entity;
public class Book {
public String isbn;
public String title;
public String author;
public Book(String isbn, String title, String author) {
this.isbn = isbn;
this.title = title;
this.author = author;
}
}
所以我们需要 DAO
来访问数据存储:
package my.bookstore.dao;
import my.bookstore.entity.Book;
import java.util.List;
public interface BookDAO {
public List<Book> getAllBooks();
}
及其实现:
package my.bookstore.dao;
import my.bookstore.entity.Book;
import java.util.List;
import java.util.ArrayList;
public class DefaultBookDAO implements BookDAO {
public List<Book> getAllBooks() {
List<Book> bookList = new ArrayList<>();
list.add(new Book("1234", "Awesome Book", "Some Author"));
return bookList;
}
}
然后我想将 DefaultBookDAO
注入到 RESTful 服务中:
package my.bookstore.resource;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("/books")
public class BookResource {
@Inject
BookDAO dao;
@GET
@Produces(MediaType.APPLICATION_JSON)
public List<Book> getBooks() {
return this.dao.getAllBooks();
}
}
现在,在部署应用程序时我得到:
Unsatisfied dependencies for type BookDAO with qualifiers @Default
因为我需要让 CDI 知道它;但是怎么办?我尝试了 @Named
、@Default
、@Model
、@Singleton
、@Stateless
的各种组合,问题和博客文章等许多资源都有自己的解释。
使此注入在 Jersey/Glassfish 中起作用的正确、简单的 CDI 注释是什么?
由于这是一项服务,您可以用 @Stateless
注释您的 DefaultBookDAO
。
那么你需要一个额外的 class 来实现 AbstractBinder
class。
你的情况应该是这样的:
import org.glassfish.hk2.utilities.binding.AbstractBinder;
public class MyApplicationBinder extends AbstractBinder {
@Override
protected void configure() {
bind(DefaultBookDAO.class).to(BookDAO.class);
}
}
您必须在扩展 ResourceConfig
的 class 中注册此 class,如下所示:
@ApplicationPath("/bookstore")
public class BookStore extends ResourceConfig {
public BookStore() {
register(new MyApplicationBinder());
this.packages("my.bookstore.resource");
}
}
然后 @Inject
应该工作。
另请参阅:
- Jersey docs: Chapter 22. Custom Injection and Lifecycle Management
- Dependency injection with Jersey 2.0
对我来说,您似乎没有将 beans.xml 文件放入您的应用程序中。使用 Glassfish 4(通常使用 Java EE 7)不需要此文件,但是,如果您省略它,则只会考虑使用范围注释进行注释的 bean。因此,由于 DefaultBookDAO 没有被任何注释标记,因此 CDI 不认为它是注入的候选对象。
您有 2 个选项来修复它并使 CDI 机制考虑 DefaultBookDAO:
- 在 DefaultBookDAO class 上放置
@Dependent
注释 - 这不会改变它的范围,因为@Dependent
是默认范围,但会让 CDI 考虑这个 class - 在 META-INF 或 WEB-INF(对于网络应用程序)中创建 beans.xml 文件,其值为
bean-discovery-mode="all"
在我看来,第一个选项更清晰 - 您可以轻松区分可以注入和不能注入的代码。但是,如果您想通过省略不必要的注释来提高生产率,请选择第二个选项。它更复杂,但每个模块只需执行一次。
请参阅 this oracle blog post 关于 Java EE 7 中的 beans.xml 以及省略时的默认行为。