@Injectand @Resource和@Autowired注释之间有什么区别?
我们什么时候应该使用它们?
我使用Weld作为CDI实现.当我有空的beans.xml时,我试图组装实例化Weld容器的对象图的集成测试运行良好src/test/java/META-INF/beans.xml.这是一个简单的测试:
public class WeldIntegrationTest {
@Test
public void testInjector() {
new Weld().initialize();
// shouldn't throw exception
}
}
Run Code Online (Sandbox Code Playgroud)
现在,当我跑步时mvn clean install,我总是得到:Missing beans.xml file in META-INF!
我的根文件夹是"src"和"web",其中包含WEB-INF文件夹,但我也尝试使用默认的maven结构并将"web"重命名为"webapp"并将其移至src/main.我尝试了所有合理的位置:
- src/main/java/META-INF/beans.xml
- src/test/java/META-INF/beans.xml
- web/WEB-INF/beans.xml
- src/main/webapp/WEB-INF/beans.xml
- src/main/webapp/META-INF/beans.xml
- src/main/webapp/META-INF/(empty) and src/main/webapp/WEB-INF/beans.xml
Run Code Online (Sandbox Code Playgroud)
到目前为止没有任何作用:/
Weld,JSR-299上下文和依赖注入参考实现,认为自己是Spring和Guice的一种继承者.
CDI受到许多现有Java框架的影响,包括Seam,Guice和Spring.但是,CDI有其独特的特性:比Seam更安全,比Spring更有状态,更少以XML为中心,比Guice更具Web和企业应用程序能力.但是,如果没有JSR-299专家组(EG)提到的框架和许多合作和辛勤工作的灵感,它就不可能是其中任何一个.
http://docs.jboss.org/weld/reference/latest/en-US/html/1.html
与Guice相比,是什么让Weld更有能力进行企业应用?与Guice相比有什么优点或缺点吗?与Weld拦截器相比,你对Guice AOP有什么看法?性能怎么样?
我的选择
最后我决定使用Guice,因为我喜欢干净的编程模型,除了@Inject之外,它几乎没有注释.使用Guice的外部库比使用CDI容易得多.Guice也很简单.
我知道有很多文章解释了如何在Java EE中使用CDI,但我无法弄清楚它实际带来了什么优势.例如,假设我有一个当前使用Foo实例的类.我也许会这样做
Foo myFoo = new Foo();
Run Code Online (Sandbox Code Playgroud)
要么
// Better, FooFactory might return a mock object for testing
Foo myFoo = FooFactory.getFoo();
Run Code Online (Sandbox Code Playgroud)
我一直在读CDI,我可以这样做:
@Inject
Foo myFoo;
Run Code Online (Sandbox Code Playgroud)
但为什么这比以前的工厂方法更好?我假设还有一些其他用例,我不知道,但我无法识别这一点.
如果我理解了下面的响应,那么概念就是DI框架充当集中配置的主对象工厂.这是一个合理的解释吗?
更新
我从那时起开始学习Spring,现在这更有意义了.下面的段落取自Spring in Practice,以一个AccountService类为例,该类反过来使用了一个实例AccountDao.我为长篇报道道歉,但我认为它真正解释了为什么注入资源提供了超过标准初始化的东西.
您可以使用new关键字构造AccountService,但是服务层对象的创建很少是如此简单.它们通常依赖于DAO,邮件发件人,SOAP代理等等.您可以在AccountService构造函数中(或通过静态初始化)以编程方式实例化每个依赖项,但这会导致硬件依赖性和级联更改,因为它们已被换出.
此外,您可以在外部创建依赖项,并通过setter方法或构造函数参数在AccountService上设置它们.这样做可以消除硬内部依赖关系(只要它们通过接口在AccountService中声明),但是你到处都有重复的初始化代码.以下是如何创建DAO并以Spring方式将其连接到AccountService:
<bean id="accountDao" class="com.springinpractice.ch01.dao.jdbc.JdbcAccountDao"/>
<bean id="accountService"
class="com.springinpractice.ch01.service.AccountService">
<property name="accountDao" ref="accountDao"/>
</bean>
Run Code Online (Sandbox Code Playgroud)
如上所述配置bean后,您的程序现在可以AccountService从Spring ApplicationContext 请求一个实例,Spring DI框架将实例化需要实例化的所有内容.
我已经阅读了关于CDI中@Produces注释的内容,但我不明白它的用法.
public class Resources {
// Expose an entity manager using the resource producer pattern
@SuppressWarnings("unused")
@PersistenceContext
@Produces
private EntityManager em; //
@Produces
Logger getLogger(InjectionPoint ip) { //
String category = ip.getMember()
.getDeclaringClass()
.getName();
return Logger.getLogger(category);
}
@Produces
FacesContext getFacesContext() { //
return FacesContext.getCurrentInstance();
}
Run Code Online (Sandbox Code Playgroud)
}
取自:http: //www.jboss.org/jdf/quickstarts/jboss-as-quickstart/guide/GreeterQuickstart/#GreeterQuickstart-
容器如何知道调用生产者方法?如果我注入一个EntityManager,容器如何调用@produces EntityManager?如何调用getLogger生成器方法?
我也没有看到解决所有麻烦的原因.
比方说,我有一个名为接口SocialNetworkService,以及三种实现- TwitterService,FacebookService和FriendFeedService.
现在我希望,只要我的托管bean(或任何Web组件)收到消息,就可以在所有社交网络中共享它.我试过了:
@Inject private List<SocialNetworkService> socialNetworkServices;
Run Code Online (Sandbox Code Playgroud)
但它不起作用(部署错误).(也尝试了@Any限定符 - 相同的结果)
那么,有没有办法注入接口的所有(或某些)实现的列表?
我知道给定注入点不应该有多个可能的bean的规则.我想我可以通过制作一个生成列表和使用的生产者来实现这一目标Instance<SocialNetworkService>,但这对于这项任务来说似乎太多了.
有什么区别
import javax.annotation.ManagedBean;
import javax.enterprise.context.SessionScoped;
Run Code Online (Sandbox Code Playgroud)
和
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
Run Code Online (Sandbox Code Playgroud)
?
我认为有两种通用方法可以获得一个自动创建的CDI托管bean实例BeanManager,只需要一个Bean<T>开始(基于它创建Class<T>):
通过BeanManager#getReference(),更经常以片段形式显示:
Bean<TestBean> bean = (Bean<TestBean>) beanManager.resolve(beanManager.getBeans(TestBean.class));
TestBean testBean1 = (TestBean) beanManager.getReference(bean, bean.getBeanClass(), beanManager.createCreationalContext(bean));
Run Code Online (Sandbox Code Playgroud)通过Context#get(),在片段中不常显示:
Bean<TestBean> bean = (Bean<TestBean>) beanManager.resolve(beanManager.getBeans(TestBean.class));
TestBean testBean2 = beanManager.getContext(bean.getScope()).get(bean, beanManager.createCreationalContext(bean));
Run Code Online (Sandbox Code Playgroud)实际上,它们最终完全相同:返回对当前CDI托管bean实例的代理引用,并自动创建bean实例(如果范围中尚不存在).
但是他们做的有点不同:BeanManager#getReference()总是创建一个全新的代理实例,而Context#get()如果之前已经创建过,则重用现有的代理实例.当在现有TestBean实例的action方法中执行上述代码时,这是显而易见的:
System.out.println(testBean1 == testBean2); // false
System.out.println(testBean1 == this); // false
System.out.println(testBean2 == this); // true
Run Code Online (Sandbox Code Playgroud)
该的javadoc的Context#get()是非常明确的在此:
返回某个上下文类型的现有实例,或通过调用Contextual.create(CreationalContext)创建一个新实例并返回新实例.
而javadoc中的BeanManager#getReference()不够明确在此:
获得某个bean和bean的某个bean类型的上下文引用.
这让我感到困惑.你什么时候使用这一个?对于这两种方式,无论如何都需要一个Bean<T>实例,bean类和bean范围随时可用,这是额外的参数.我无法想象为什么在这种特殊情况下他们需要外部供应.
我可以想象这Context#get()是更高效的内存,因为它不会不必要地创建引用同一个底层bean实例的另一个代理实例,而只是查找并重用现有的代理实例.
这让我想到了以下问题:什么时候BeanManager#getReference() …
我有以下配置:
我在EAR的每个EJB-JAR中都有2个EJB业务服务,它们都是这样开发的:
@Remote
public interface ServiceAItf {
...
}
@Stateless
@Local
public class ServiceAImpl implements ServiceAItf {
...
}
Run Code Online (Sandbox Code Playgroud)
在我的WAR中,我通过远程接口上的显式"InitialContext.lookup"访问EJB组件.
在我的EAR中,我对注入的最佳实践非常困惑,无论是在性能,架构等方面......
我有以下问题:
如您所见,我已在服务实现上声明了注释"@Local",而没有定义本地接口.这是对的吗?至少我在部署时没有错误.但也许我应该使用"@LocalBean"注释?我想"@LocalBean"注释只是允许直接调用实现作为"本地" EJB,但你必须在代码中使用这样的实现:
@Stateless @Local public class ServiceBImpl实现ServiceBItf {@EJB private ServiceAImpl serviceA; ...}
将一个EJB注入另一个EJB的最佳方法是什么? 它的工作原理如下:
@Stateless @Local公共类ServiceBImpl实现ServiceBItf {@EJB private ServiceAItf serviceA; ...}
但是从我注意到的,注入的"serviceA"是远程代理,而它位于同一个EAR文件中的同一个JVM中.所以我认为会对性能产生影响.这就是为什么我试图像这样注入服务:
@Stateless
@Local
public class ServiceBImpl implements ServiceBItf {
@Inject
private ServiceAItf serviceA;
...
}
Run Code Online (Sandbox Code Playgroud)
但它在GF中不起作用,我有以下例外:
WELD-001408 Unsatisfied dependencies for type [...] ... …Run Code Online (Sandbox Code Playgroud) 我是Java EE新手.我想测试JSF,因此制作了一个简单的程序,但无法部署它.我收到以下错误消息:
cannot Deploy onlineshop-war
deploy is failing=Error occurred during deployment: Exception while loading the app : CDI deployment failure:WELD-001408: Unsatisfied dependencies for type Customer with qualifiers @Default
at injection point [BackedAnnotatedField] @Inject private de.java2enterprise.onlineshop.RegisterController.customer
at de.java2enterprise.onlineshop.RegisterController.customer(RegisterController.java:0)
. Please see server.log for more details.
Run Code Online (Sandbox Code Playgroud)
我的代码如下:Customer.java:
package de.java2enterprise.onlineshop.model;
public class Customer {
private String email;
private String password;
}
Run Code Online (Sandbox Code Playgroud)
registerController.java:
package de.java2enterprise.onlineshop;
import java.io.Serializable;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
import javax.inject.Inject;
import de.java2enterprise.onlineshop.model.*;
@Named
@RequestScoped
public class RegisterController {
private static final …Run Code Online (Sandbox Code Playgroud) cdi ×10
java ×6
java-ee ×5
jboss-weld ×3
managed-bean ×3
jsf ×2
spring ×2
annotations ×1
aop ×1
autowired ×1
ejb ×1
maven ×1