我的部分问题是使用适当的词汇表,所以我提前道歉可能是一个简单的术语问题.
假设我有一个Person接口,以及一个PersonBean实现该接口的类.
假设我在某处(注释@Produces)有一个返回a 的生成器方法Person.在内部它返回一个新的PersonBean,但这既不在这里也不在那里.
最后,假设我有另一个CDI bean,其注入点定义如下:
@Inject
private Person person;
Run Code Online (Sandbox Code Playgroud)
假设我已经将我的所有beans.xml文件都放在适当的位置,并且已经引导了Weld或其他符合CDI-1.0标准的环境,因为这一切都将导致模糊的定义错误.这是有道理的:Weld将找到我PersonBean作为注入的候选者(它可以只调用构造函数)并且将找到我的producer方法的输出作为注入的候选者.
我想要做的是以某种方式强制Person在此应用程序中生成实例始终路由生成器方法.
我知道我可以在某处创建一些限定符,并使生成器方法生成Person由该限定符限定的实例.如果我这样做,并改变我的注射点以包括限定符,那么显然这些合格的注射剂只有一个来源(即我的生产者方法),所以瞧,问题解决了.
但是假设我不想发明一些虚假的限定词.(我不是说这是事实;只是想更深入地了解这些问题.)我有什么选择?我有吗?我想我可以把@Typed(Object.class)在PersonBean做出这等,这是不看作是一个Person由CDI ....
欢迎任何想法,包括指向文档,或更好地理解这一点.谢谢.
JAX-RS 2.0的一个目标是整合CDI并用旧的替代@Context普通@Inject注射.但是如果我看一下JSR 339,就没有提到.那么CDI整合究竟是什么呢?将JAX-RS与CDI而不是Google Guice一起使用是否有任何优势?
我想我理解CDI是如何工作的,为了深入研究它,我想尝试用一些真实世界的例子.我被困在一件事情,我需要你的帮助才能让我理解.在这方面,我非常感谢你的帮助.
我有自己的工作流框架使用Java反射API和XML配置开发,其中基于特定类型的"source"和"eventName",我加载适当的Module类并在其上调用"process"方法.一切都在我们的项目中运作良好.
我对CDI功能很兴奋,并希望尝试使用工作流框架,我计划注入Module类,而不是使用Reflection等加载它们...
只是为了给你一个想法,我会尽量在这里保持简单.
"Message.java"是一种带有"Source"和"eventName"的Transfer Object,因此我们可以适当地加载模块.
public class Message{
private String source;
private String eventName;
}
Run Code Online (Sandbox Code Playgroud)
模块配置如下
<modules>
<module>
<source>A</source>
<eventName>validate</eventName>
<moduleClass>ValidatorModule</moduleClass>
</module>
<module>
<source>B</source>
<eventName>generate</eventName>
<moduleClass>GeneratorModule</moduleClass>
</module>
</modules>
Run Code Online (Sandbox Code Playgroud)
ModuleLoader.java
public class ModuleLoader {
public void loadAndProcess(Message message){
String source=message.getSource();
String eventName=message.getEventName();
//Load Module based on above values.
}
}
Run Code Online (Sandbox Code Playgroud)
题
现在,如果我想通过CDI实现相同的注入模块(在ModuleLoader类中),我可以使用@Produce方法编写Factory类,这可以做到这一点.但我的问题是,
a)如何将Message Object传递给@Produce方法,以便根据eventName和source进行查找?
你能给我一些建议吗?
提前致谢.
我已经创建了JAX-RS服务,我想在其中注入一个应用程序范围的bean.问题是没有注入豆子.这是怎么造成的,我该如何解决?
JAX-RS服务:
@Path("room")
public class RoomService {
@Inject
GameController gc;
public RoomService() {}
@Path("create")
@GET
@Produces("application/json")
public String create() {
Room r = new Room();
gc.addRoom(r); // gc is null
return r.toJson();
}
}
Run Code Online (Sandbox Code Playgroud)
应用程序作用域bean
import java.util.ArrayList;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Named;
import pepuch.multuplayergameserver.entity.Game;
import pepuch.multuplayergameserver.entity.Room;
@Named
@ApplicationScoped
public class GameController {
private Game game;
public GameController() {
this.game = new Game(new ArrayList<Room>());
}
public boolean addRoom(Room room) {
if (!game.getRooms().contains(room)) {
return game.getRooms().add(room);
}
return false;
}
}
Run Code Online (Sandbox Code Playgroud) <h:form ...
<p:dataTable value="#{myBean.list}" var="data" ...
<p:column ...
<h:commandButton action="#{controller.method(data.id)}" />
</p:column>
</p:dataTable>
</h:form>
Run Code Online (Sandbox Code Playgroud)
@ApplicationScoped
public class Controller {
public String method(final Long dataId) {
/* Do business */
return URL_WITH_REDIRECT;
}
}
Run Code Online (Sandbox Code Playgroud)
(使用此处@ViewScoped描述的CDI注释)
@ApplicationScoped
public class Producer {
@Named @ViewScoped @Producer
public MyBean getMyBean() {
final MyBean bean = new MyBean();
bean.list = new ArrayList<Data>(); // where Data has a Long id field
/* Do business and populate list */
return bean;
} …Run Code Online (Sandbox Code Playgroud) 我最近将一个简单的Java EE 6项目迁移到了Java EE 7.详细地说,这意味着我只是将依赖关系更改javax:javaee-api:6.0为javax:javaee-api:7.0并将其部署到Glassfish 4而不是Glassfish 3.
之后应用程序不再起作用,因为CDI无法注入带注释的依赖项.
我用@ApplicationScoped注释了一个类.使用@Inject,我将这个类的实例注入到几个@RequestScopded JAX-RS服务中:
@ApplicationScoped
public class MySingleton {
MySingleton() {
System.out(this + " created.");
}
}
@RequestScoped
public class MyRS {
@Inject MySingleton mySingleton;
public void someMethod() {
// do something with mySingleton
}
}
Run Code Online (Sandbox Code Playgroud)
基本上这很好用.Howeger,至少当我在WebSphere 8.5中运行它时,MySingleton的构造函数被调用两次,导致输出像
my.package.MySingleton_$$_javassist_26@cddebf9b created.
my.package.MySingleton@e51e26d1 created.
Run Code Online (Sandbox Code Playgroud)
我打算在构造函数中做一些昂贵的初始化,显然会执行两次.
我相信其中一个构造函数调用是为实际的"worker"实例生成某种代理.但是如何避免我的初始化代码执行两次?在MySingleton的所有方法中进行延迟初始化的"解决方案"并不是很有吸引力.
我在Vaadin上下文中使用CDI,但这对我的问题无关紧要:在构造函数中注入对象或者直接作为成员变量注入更好吗?特别是如果必须进一步配置这些对象以使组件工作.
以下显示了两种不同的CDI可能性:
@UIScoped
public class MyMenuBar extends CustomComponent {
@Inject @New private Label label;
@Inject @New private MenuBar menuBar;
@PostConstruct
private void init() {
//set label text, define menu entries
setCompositionRoot(menuBar);
}
}
@UIScoped
public class MyMenuBar extends CustomComponent {
private Label label;
private MenuBar menuBar;
@Inject
public MyMenuBar(@New Label label, @New MenuBar menuBar) {
//set label text, define menu entries
setCompositionRoot(menuBar);
}
}
Run Code Online (Sandbox Code Playgroud)
有最好的做法吗?为什么一个人更喜欢一个选项?或者这仅仅是个人选择的问题?
我的代码库中有以下场景:
//this bean, which will be injected,
//is not annotated
public class HelperUtil {
//only default constructor with no args
public void doThis(String _in) {
//...
}
public void doThat() {
//...
}
}
Run Code Online (Sandbox Code Playgroud)
在下面的课程中我们进行注射:
@Named
@Stateless
public class BusinessManager {
@PersistenceContext(unitName = "default")
private EntityManager em;
@Inject
private HelperUtil helperUtil ;
//...
}
Run Code Online (Sandbox Code Playgroud)
Q1: 何时HelperUtil通过调用默认构造函数实际初始化实例?当注入它的第一个客户端(例如BusinessManager)在应用服务器(在我的情况下JBoss)启动时被实例化(并且由于它被注释为将由容器初始化),它是否已完成@Stateless?
Q2: 在上面的展览中,只要没有客户端以外的客户端通过直接调用构造函数而不是通过?获取实例来请求实例,它将HelperUtil保持不变?singletonDI
问题3: 使用DI的优势是什么?@Inject在这种情况下直接调用构造函数(HelperUtil helper = new HelperUtil();)?
我对会话作用域CDI bean的生命周期有疑问.
据我所知,会话范围内的CDI bean是在会话开始时由容器构造的,并在会话结束时销毁.在销毁bean之前,调用@PreDestroy方法,如https://docs.oracle.com/javaee/6/tutorial/doc/gmgkd.html所述.它还说要在这种方法中释放资源.
在我构建的JSF应用程序中,我遇到内存泄漏,因为bean似乎没有被销毁,因此不会调用@PreDestroy方法来释放垃圾收集器的一些引用.所以我构建了一个简单的应用程序来测试行为.我的经验是会话bean在会话结束时不会被破坏,而且当需要内存空间时它甚至不会被破坏.我不敢相信我是第一个遇到这种情况的人,但我没有找到任何有关此行为的信息.
所以我的问题是:在上下文过期之后,不应该销毁CDI bean - 因此调用@PreDestroy方法吗?如果不是,在需要空间时,它至少应该被破坏吗?
我的测试应用:
我不允许发布图片,但大纲是eclipse生成的非常基本的jsf webapp.我也有beans.xml文件.
Test.java:
package com.test;
import java.io.Serializable;
import java.util.ArrayList;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
@SessionScoped
@Named
public class Test implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private String test;
private ArrayList<ComplexType> cps;
private ArrayList<ComplexType> cps_2;
@PostConstruct
public void init() {
System.out.println("test postconstruct..");
test = "Cdi Test";
}
@PreDestroy
public void cleanUp() {
cps …Run Code Online (Sandbox Code Playgroud) cdi ×10
java ×4
java-ee ×4
glassfish ×2
jax-rs ×2
jsf ×2
weld ×2
constructor ×1
destroy ×1
glassfish-4 ×1
guice ×1
java-ee-7 ×1
jboss ×1
jsr299 ×1
managed-bean ×1
vaadin ×1
view-scope ×1