从我在网上看到的情况来看,Guice + Jersey整合的最新技术水平自2008年以来一直停滞不前,似乎两支球队都陷入了僵局.问题的关键在于JAX-RS注释执行字段和方法注入,这与Guice自己的依赖注入不能很好地协作.
我发现的一些例子远远不足以阐明:
Iqbalyusuf 在Google App Engine上发布关于Jersey + Guice的帖子Java遭受了大量的样板(手动获取和调用注入器).我希望绑定和注入应该通过Guice注释在幕后发生.
Jonathan Curran的文章使用Jersey,Guice和JSR-250创建一个RESTful服务给了我希望,因为它更新(2010),但没有比显示如何在Guice ServletModule中启动Jersey服务更进一步.但是,没有任何实例依赖注入的例子.我想这是留给读者的练习.Curran的帖子实际上可能是连接Guice和Jersey的正确的第一步,所以我打算从那开始.
令人着迷的詹姆斯斯特拉坎写道:
JAX-RS适用于依赖注入框架,如Spring,Guice,GuiceyFruit或JBossMC - 你基本上可以选择你喜欢的任何一个.
但是,从实践者的角度来看,我没有看到任何证据.
我发现缺少的是关于如何组合JAX-RS和Guice注释的实际示例和解释.例如:
有没有人有一些非平凡的应用程序的例子,最好是源代码,它结合了Jersey和Guice,而不会在这个过程中牺牲一个或另一个?无论如何我都会坚持这条道路,但泽西和吉斯的名单上的点点滴滴让我觉得我正在重复在我面前的其他人的工作.
Java EE 6的一个优点是新的依赖注入框架 - 带有Weld参考实现的CDI - 它促使我们以一种与实现无关的方式开始内部迁移到JSR-330,其明确的目标是能够拥有核心jar被冻结,然后能够添加额外的罐子,提供新的模块替换核心jar中的功能.
我现在正在与Weld一起完成上述工作,坦率地说,封面背后有太多的魔力.无论是工作还是不工作,默认情况下它不会提供很多帮助,因此您可以调查错误并修复它.
我希望有切换开关可以轻松实现以下功能:
换句话说,我需要更详细地看待决策过程.出于某种原因,Guice并不需要这样做,也许是因为魔法少得多,也许是因为错误消息非常好.
您如何调试Weld应用程序,以及它有多大帮助?
Jersey通常使用HK2依赖注入,但我想使用Jersey和Dagger 2.Dagger和HK2都实现了JSR 330,我已经把它作为证据证明这应该是可能的而不需要太多努力.我找到了使泽西与CDI(例如Weld),Spring DI和Guice合作的方法,但我在Dagger上找不到任何东西.
提供一些上下文:我在SE环境中运行Grizzly-Jersey服务器,而不是在EE容器中运行.我的Maven项目有com.google.dagger:dagger
和org.glassfish.jersey.containers:jersey-container-grizzly2-http
依赖,但不是 org.glassfish.jersey.inject:jersey-hk2
,因为我想用Dagger取代HK2.
资源类看起来像这样:
@Path("/example")
public final class ExampleResource {
private final Dependency dependency;
@Inject
public ExampleResource(final Dependency dependency) {
this.dependency = Objects.requireNonNull(dependency);
}
@GET
@Produces(MediaType.APPLICATION_JSON)
public Example getExample() {
return this.dependency.giveExample();
}
}
Run Code Online (Sandbox Code Playgroud)
并且Dagger组件可以例如定义如下:
@Component
public interface Application {
public ExampleResource exampleEndpoint();
public XyzResource xyzEndpoint();
// etc.
}
Run Code Online (Sandbox Code Playgroud)
这样主要方法看起来类似于:
public final class Main {
public static void main(final String[] args) {
final Application application = DaggerApplication.create();
final URI baseUri = …
Run Code Online (Sandbox Code Playgroud) 我们有一种情况,我们以Map的形式为我们正在运行的程序提供外部配置.我发现JSR-330依赖注入提供了一种更清晰的方式来在代码中使用该配置映射,而不是传递映射或使用JNDI来获取它.
@Inject @Named("server.username") String username;
Run Code Online (Sandbox Code Playgroud)
让JSR-330实现自动填写此字段.
使用Guice,我可以设置值
bindConstant().annotatedWith(Names.named(key)).to(value);
Run Code Online (Sandbox Code Playgroud)
我希望能够在Weld中做同样的事情(将"server.username"绑定到例如"foobar")并且我理解该机制最有可能是beans.xml,但我更喜欢简单的"将此地图提供给Weld" ,请"代码替代.这样做有什么好办法?
编辑2013-10-16:在调查Dagger,它在编译时工作而不是运行时,我发现我们通常每个程序有10-20个,我们可以使用@Provider
每个配置字符串的方法,然后在配置中查找地图.这允许方法特定的行为(包括默认值),提供javadoc的能力,以及将所有这些方法放在同一个类中的能力.它也可以与Weld开箱即用.我正在考虑在博客文章中写一个更全面的解释.
Per Spring 3文档,IoC容器,@Named
注释是与注释等效的标准@Component
.
从@Repository
,@Service
和@Controller
,都是@Component
,我试图@Named
在我的Spring MVC应用程序中使用它们.它工作正常.但我发现替换@Controller
似乎有一个bug.在控制器类中,最初是
@Controller
public class MyController{
...
}
Run Code Online (Sandbox Code Playgroud)
它工作正常.当我改变@Controller
到@Named
@Named
public class MyController{
...
}
Run Code Online (Sandbox Code Playgroud)
它失败了,错误:
"找不到带URI的HTTP请求的映射......".
但如果我@RequestMapping
按照以下方式加入课堂
@Named
@RequestMapping
public class MyController{
...
}
Run Code Online (Sandbox Code Playgroud)
它会按预期工作.
对于@Repository
和@Service
,我可以简单地替换它们@Named
没有问题.但更换@Controller
需要额外的工作.我在配置中缺少什么?
我们决定将依赖注入和JSR-330注释用于我们未来的模块化工作,并且对基于Guice 2 SVN的第一个可交付成果非常满意.
现在我们需要确保并通过单元测试记录我们需要的构造,在编程时配置时也可以在Spring中工作(我们需要与Guice相同的重构支持,因此没有XML文件).我有一个问题,@Provider
和@Inject @Named("foo") String
,但我已清楚@Inject
工作有:
ApplicationContext ctx = new AnnotationConfigApplicationContext(LIBL_Object.class,
CORE_Provider.class);
this.object = ctx.getBean(LIBL_Object.class);
Run Code Online (Sandbox Code Playgroud)
其中LIBL_Object是被注入的基类成,但正如我在Spring希望CORE_Provider不登记.
CORE_Provider的实现是
package qa.jsr330.core;
import javax.inject.Provider;
public class CORE_Provider implements Provider<ProvidedInterface> {
@Override
public ProvidedInterface get() {
return new CORE_Provided();
}
}
Run Code Online (Sandbox Code Playgroud)
我希望它注入
package qa.jsr330.core;
import javax.inject.Inject;
public class LIBL_Object {
private ProvidedInterface provided;
public ProvidedInterface getProvided() {
return provided;
}
@Inject
public void setProvided(ProvidedInterface provided) {
this.provided = provided;
}
// Other stuff omitted.
}
Run Code Online (Sandbox Code Playgroud)
我们还发现,我们可以使用@Named标记非常清楚地传递配置值.此代码如下所示: …
JSR-330根据包指定了某些命名约定,例如:
javax.inject.Inject
javax.inject.Scope
Run Code Online (Sandbox Code Playgroud)
Guice是JSR-330的参考实现.但是,在使用它时,您会注意到它不符合规范.例如:
com.google.inject.Inject
com.google.inject.Scope
Run Code Online (Sandbox Code Playgroud)
到目前为止我看到的任何参考实现都没有发生这种情况.是什么让Google Guice如此特别,以至于他们可以忽略他们正在实施的规范?
我@Inject
在Spring的工作中有一些奇怪的行为.这个例子效果很好:
@Controller
@RequestMapping("/")
public class HomeController {
@Autowired
private SomeBean someBean;
@RequestMapping(method = GET)
public String showHome() {
System.out.println(someBean.method());
return "home";
}
}
Run Code Online (Sandbox Code Playgroud)
但是,如果我取代@Autowired
用@Inject
,showHome
方法将抛出NullPointerException
,因为someBean
是null
.与二传手注射相同的事情.但是使用构造函数注入@Autowired
并且@Inject
运行良好.
为什么会这样?
我正在使用Spring 4.3.1.我的依赖关系pom.xml
看起来像这样:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
<dependencies>
Run Code Online (Sandbox Code Playgroud) 我需要做一些处理来确定JSR-330带注释类的依赖关系,使用反射.
我完全了解所有符合JSR-330标准的IoC容器,如Spring,Guice或PicoContainer.但是,我需要的不是解决和注入依赖关系,而是要识别它们.
这基本上意味着我需要实现JSR-330实现,至少在涉及反射类"解析"时.
JSR-330规范的一部分我觉得实现起来有点麻烦:
使用@Inject注释的方法将覆盖使用@Inject注释的另一个方法,每个实例的每个注入请求只会注入一次.不会注入没有@Inject批注的方法,该方法将覆盖使用@Inject注释的方法.
这意味着子类可以重新定义其基类的自动装配合同,以及挂钩注入流(通过多态).
我的问题出现了:给定一个类层次结构,是否有一种简单的方法可以检查层次结构中某个部分的方法是否在层次结构的下方被覆盖?
在我的例子中,我最简单的方法是从层次结构的叶子中递归:
private List<Method> getInjectableMethods(final Class<?> clazz) {
// recursive stop condition
if(clazz == null) {
return emptyList();
}
// recursively get injectable methods from superclass
final List<Method> allInjectableMethods = newLinkedList(getInjectableMethods(clazz.getSuperclass()));
final List<Method> injectableMethods = newArrayList();
// any overridden method will be present in the final list only if it is injectable in clazz
for (final Method method : clazz.getDeclaredMethods()) {
removeIf(allInjectableMethods, Methods.Predicates.overriddenBy(method));
if (isInjectable(method)) {
injectableMethods.add(method);
}
}
allInjectableMethods.addAll(injectableMethods);
return allInjectableMethods;
} …
Run Code Online (Sandbox Code Playgroud) 有没有人遇到过需要有一个只有在满足所有组子句时才应用的约束。换句话说,对于
@NotNull(groups= {Group1.class, Group2.class})
private Integer value;
Run Code Online (Sandbox Code Playgroud)
当任一组有效时应用非空约束。
如果我想在两个组都有效时应用约束怎么办?
拥有自定义组不是一种选择,因为在我的应用程序中有许多此类组的组合。
java ×10
jsr330 ×10
cdi ×2
guice ×2
jboss-weld ×2
jersey ×2
spring ×2
spring-mvc ×2
annotations ×1
dagger-2 ×1
java-ee-6 ×1
jax-rs ×1
jsr299 ×1
overriding ×1
reflection ×1