Guice(三)

 

在不同作用域间注入

你可以安全地将来自大作用域的对象注入到来自小作用域或相同作用域的对象中。例如,你可以将一个作用域为 HTTP 会话的对象注入到作用域为 HTTP 请求的对象中。但是, 较大作用域的对象中注入就是另一件事了。例如,如果你把一个作用域为 HTTP 请求的对象注入到一个单件对象中,最好情况下,你会得到无法在 HTTP 请求中运行的错误信息,最坏情况下,你的单件对象会 引用来自第一 HTTP 请求的对象。在这些时候,你应该注入一个 Provider<T>,然后在需要的时候使用它从较小的作用域中获取对象。这时,你必须确保,在 T 的作用域之外,永远不要调用这个提供者(例如,当目前没有 HTTP 请求且 T 的作用域为 HTTP 请求的时候)。

开发阶段

Guice 明白你的应用开发需要经历不同的阶段。你可以在创建容器时告诉它应用程序运行在哪一个阶段。Guice 目前支持“开发”和“产品”两个阶段。我们发现测试通常属于其中某一个阶段。

在开发阶段,Guice 会 根据需要加载单件对象。这样,你的应用 程序可以快速启动,只加载你正在测试的部分。

在产品阶段,Guice 会在启动时加载全部单件对象。这帮助你尽早捕获错误,提前优化性能。

你的模块也可以使用方法拦截和其他基于当前阶段的绑定。例如,一个拦截器可能会在开发阶段检查你是否在作用域之外使用对象。

拦截方法

Guice 使用 AOP Alliance API 支持简单的方法拦截。你可以在模块中使用 Binder 绑定拦截器。例如,对标注有 @Transactional 的方法 事务 拦截器:

import static com.google.inject.matcher.Matchers.*;

...

binder.bindInterceptor(
any(),                              // Match classes.
annotatedWith(Transactional.class), // Match methods.
new TransactionInterceptor()        // The interceptor.
);

尽量让匹配代码多做些过滤工作,而不是在拦截器中过滤。因为匹配代码只在启动时运行一次。

静态注入

静态字段和方法会增加测试和复用的难度,但有的时候你唯一的选择就是保留一个 Injector 的 静态 引用。
在这些情况下,Guice 支持注入可访问性较少的静态方法。例如,HTTP 会话对象经常需要被串行化,以支持复制机制。但是,如果你的会话对象依赖于一个作用域为容器生命周期的对象,该怎么办呢?我们可以保留一个该对象 的临时 引用,但在反串行化的时候,我们该如何再次找到该对象呢?

我们发现更实用的解决方案是使用静态注入:
@SessionScoped
class User {

@Inject
static AuthorizationService authorizationService;
...
}
Guice 从不自动实施静态注入。你必须使用 Binder 显式请求 Injector 在启动后注入你的静态成员:

binder.requestStaticInjection(User.class);

静态注入是一个 很难避免 的祸害,它会使测试难度加大。如果有办法避开它,你多半会很高兴的。

可选注入

有时你的代码应该在无论绑定是否存在的时候都能工作。在这些情况下,你可以使用 @Inject(optional=true),Guice 会在有绑定可用时,用一个绑定实现覆盖你的缺省实现。例如:

@Inject(optional=true) Formatter formatter = new DefaultFormatter();
如果谁为 Formatter 创建了一个绑定,Guice 会基于该绑定注入实例。否则,如果 Formatter 不能被注入(参见 隐式绑定),Guice 会忽略可选成员。

可选注入只能应用于字段和方法,而不能用于构造 函数。对于方法,如果一个参数的绑定找不到,Guice 就不会注入该方法,即便其他参数的绑定是可用的。

绑定到字符串

只要有可能,我们就尽量避免使用字符串,因为它们容易 错误拼写,对工具不友好,等等。但使用字符串而不是创建定制的标注对于“快而脏”的代码来说仍是有用的。在这些情况下,Guice 提供了 @Named Names。例如,一个到字符串名字的绑定:

import static com.google.inject.name.Names.*;

...

bind(named("bob")).to(10);
会匹配下面的注入点:

@Inject @Named("bob") int score;

Struts 2支持

要在 Struts 2.0.6 或更高版本中安装 Guice Struts 2 插件,只要将 guice-struts2-plugin-1.0.jar 包含在你的 Web 应用的 classpath 中,并在 struts.xml 文件 中选择 Guice 作为你的 ObjectFactory 实现即可:

<constant name="struts.objectFactory" value="guice" />
Guice 会注入所有你的 Struts 2 对象,包括动作和拦截器。你甚至可以设置动作类的作用域。你也可以在你的 struts.xml 文件中指定 Guice 的 Module:

<constant name="guice.module" value="mypackage.MyModule"/>

如果你的所有绑定都是隐式的,你就根本不用定义模块了。

一个计数器的例子

例如,我们试图统计一个会话中的请求数目。定义一个在会话中存活的 Counter 对象:

@SessionScoped
public class Counter {

int count = 0;

/** Increments the count and returns the new value. */
public synchronized int increment() {
    return count++;
}
}
接下来,我们可以将我们的计数器注入到动作中:

public class Count {

final Counter counter;

@Inject
public Count(Counter counter) {
    this.counter = counter;
}

public String execute() {
    return SUCCESS;
}

public int getCount() {
    return counter.increment();
}
}
然后在 struts.xml 文件中为动作类创建映射:

<action name="Count"
    class="mypackage.Count">
<result>/WEB-INF/Counter.jsp</result>
</action>     
以及一个用于显示结果的 JSP 页面:

<%@ taglib prefix="s" uri="/struts-tags" %>

<html>  
<body>
    <h1>Counter Example</h1>
    <h3><b>Hits in this session:</b>
      <s:property value="count"/></h3>
</body>
</html>
我们实际上把这个例子做得比需求更复杂,以便展示更多的概念。在现实中,我们不需要使用单独的 Counter 对象,只要把 @SessionScoped 直接应用于我们的动作类即可。

JMX 集成

参见 com.google.inject.tools.jmx.

附录:注入器如何解决注入请求

注入器解决注入请求的过程依赖于已有的绑定和相关类型中的标注。这里是关于如何解决注入请求的一个概要描述:

  1. 观察被注入元素的 Java 类型和可选的“绑定标注”。如果类型是 com.google.inject.Provider<T>,就使用类型 T 解决注入请求。对(类型,标注)对,寻找一个绑定。如果找不到,则跳到步骤4。
  2. 沿着绑定链检查。如果绑定连接到另一个绑定,则沿着这条边继续检查,直到到达一个没有连接到任何后续绑定的绑定为止。现在我们注入请求找到了最明确的显式绑定。
  3. 如果绑定指明一个实例或一个 Provider 实例,所有事情都做完了;使用这个实例来满足请求即可。
  4. 此时,如果注入请求使用了标注类型或值,我们就报告错误。
  5. 否则,检查绑定的 Java 类型;如果找到了 @ImplementedBy 标注,就实例化该类型。 如果找到了 @ProvidedBy 标注,就实例化提供者类并用它来获取想要的对象。否则试图实例化类型本身。
<think> 根据用户的问题,用户希望了解Jersey与Guice的使用、集成等相关信息。结合引用内容,其中引用[4]提到了Jersey在构建RESTful Web服务中的应用,而Guice是一个轻量级的依赖注入框架。因此,我将围绕Jersey如何与Guice集成进行回答。 首先,Jersey是JAX-RS的参考实现,用于构建RESTful Web服务。Guice是Google开发的依赖注入框架。集成两者可以实现依赖注入,使代码更模块化和可测试。 步骤: 1. 添加依赖:在项目中添加Jersey和Guice相关的依赖。通常包括`jersey-guice`模块。 2. 配置Guice:创建Guice的`ServletModule`来配置绑定。 3. 配置Jersey:在web.xml中配置Jersey的Servlet,并指定使用Guice作为依赖注入的提供者。 具体示例: - 在Maven项目中,添加依赖: ```xml <dependency> <groupId>org.glassfish.jersey.ext</groupId> <artifactId>jersey-guice</artifactId> <version>2.34</version> <!-- 根据实际版本调整 --> </dependency> <dependency> <groupId>com.google.inject</groupId> <artifactId>guice</artifactId> <version>4.2.3</version> </dependency> ``` - 创建Guice模块,例如`MyModule`: ```java public class MyModule extends ServletModule { @Override protected void configureServlets() { // 绑定资源类 bind(MyResource.class); // 配置Jersey,指定资源包 serve("/*").with(GuiceContainer.class); } } ``` - 在web.xml中配置Guice的监听器和Jersey的Servlet容器: ```xml <listener> <listener-class>com.google.inject.servlet.GuiceServletContextListener</listener-class> </listener> <filter> <filter-name>guiceFilter</filter-name> <filter-class>com.google.inject.servlet.GuiceFilter</filter-class> </filter> <filter-mapping> <filter-name>guiceFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> ``` - 编写资源类,使用`@Inject`进行依赖注入: ```java @Path("/example") public class MyResource { private final MyService service; @Inject public MyResource(MyService service) { this.service = service; } @GET @Produces(MediaType.TEXT_PLAIN) public String get() { return service.getMessage(); } } ``` 这样,Jersey就可以通过Guice来管理依赖关系。当请求到达`/example`时,Guice会注入`MyService`的实例。 注意事项: - 确保所有资源类都在Guice模块中绑定,或者使用`@Singleton`等注解管理作用域。 - 如果需要扫描资源类,可以配置`jersey.config.server.provider.packages`。 通过以上步骤,用户就可以在Jersey项目中集成Guice进行依赖管理了。 </think>以下是关于Jersey与Guice集成使用的方法和关键信息: ### 一、集成方案 1. **核心依赖** 在Maven项目中添加依赖: ```xml <dependency> <groupId>org.glassfish.jersey.ext</groupId> <artifactId>jersey-guice</artifactId> <version>3.1.0</version> <!-- 与Jersey主版本保持一致 --> </dependency> <dependency> <groupId>com.google.inject</groupId> <artifactId>guice</artifactId> <version>5.1.0</version> </dependency> ``` 2. **初始化配置** 在`ResourceConfig`中启用Guice集成: ```java public class MyApplication extends ResourceConfig { public MyApplication() { // 创建Guice注入器 Injector injector = Guice.createInjector(new MyModule()); // 注册Guice与Jersey的桥接 register(new AbstractBinder() { @Override protected void configure() { requestInjection(injector::injectMembers); } }); // 注册资源类 packages("com.example.resources"); } } ``` 3. **Guice模块配置** 定义依赖绑定规则: ```java public class MyModule extends AbstractModule { @Override protected void configure() { // 单例绑定示例 bind(UserService.class).to(UserServiceImpl.class).in(Singleton.class); // 命名绑定示例 bind(String.class).annotatedWith(Names.named("apiKey")).toInstance("SECRET_KEY"); } } ``` 4. **资源类注入** 在Jersey资源类中使用`@Inject`: ```java @Path("/users") public class UserResource { private final UserService userService; @Inject public UserResource(UserService userService) { this.userService = userService; } @GET @Produces(MediaType.APPLICATION_JSON) public List<User> getUsers() { return userService.getAllUsers(); } } ``` --- ### 二、关键特性 1. **作用域支持** - 默认使用`@RequestScoped`(每个HTTP请求新实例) - 支持`@Singleton`, `@SessionScoped`等Guice作用域 ```java @Singleton public class AuditService { ... } ``` 2. **AOP拦截器** 结合Guice AOP实现日志/权限控制: ```java public class LoggingInterceptor implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) { System.out.println("Before: " + invocation.getMethod().getName()); return invocation.proceed(); } } ``` 在模块中配置: ```java bindInterceptor(Matchers.any(), Matchers.annotatedWith(Logged.class), new LoggingInterceptor()); ``` 3. **路径参数校验** 使用Jersey的路径正则约束(如引用[4]所述): ```java @GET @Path("{id: \\d+}") // 只匹配数字ID public User getById(@PathParam("id") long id) { ... } ``` --- ### 、部署注意事项 1. **Servlet容器配置** 在`web.xml`中初始化Guice过滤器: ```xml <filter> <filter-name>guiceFilter</filter-name> <filter-class>com.google.inject.servlet.GuiceFilter</filter-class> </filter> <filter-mapping> <filter-name>guiceFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> ``` 2. **与Spring对比** 相比Spring Boot的自动配置(如引用[3]),Guice更轻量: | 特性 | Guice | Spring Boot | |------------|----------------|-------------------| | 启动速度 | 更快 | 较慢 | | 配置方式 | 代码驱动 | 注解+自动配置 | | 包大小 | ~500KB | ~3MB+ | --- ### 四、典型应用场景 1. 微服务架构中的轻量级REST服务(替代Spring) 2. 需要精细控制依赖注入逻辑的应用 3. 高并发服务(依赖注入性能优于Spring) > 参考实现:Netflix Eureka的HTTP客户端使用Jersey实现(如引用[1]),其内部服务通常结合Guice管理依赖[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值