我正在尝试将Spring上下文中定义的bean注入CDI托管组件,但我没有成功.不注入bean,而是每次执行注入时都会创建一个新实例.我的环境是使用JBoss Weld的Tomcat 7.
Spring ApplicationContext是直截了当的:
<beans>
...
<bean id="testFromSpring" class="test.Test" />
...
</bean>
Run Code Online (Sandbox Code Playgroud)
CDI托管bean看起来像这样:
@javax.inject.Named("testA")
public class TestA {
@javax.inject.Inject
private Test myTest = null;
...
public Test getTest() {
return this.myTest;
}
}
Run Code Online (Sandbox Code Playgroud)
这是我的 faces-config.xml
<faces-config xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd" version="2.0">
<application>
<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
</application>
</faces-config>
Run Code Online (Sandbox Code Playgroud)
但是,当我test从JSF页面访问该属性时,Test每次访问时都会创建一个新实例.这是一个简单的例子:
<html>
...
<p>1: <h:outputText value="#{testFromSpring}" /></p>
<p>2: <h:outputText value="#{testA.test}" /></p>
...
Run Code Online (Sandbox Code Playgroud)
我得到以下输出:
1: test.Test@44d79c75
2: test.Test@53f336eb
Run Code Online (Sandbox Code Playgroud)
刷新后:
1: test.Test@44d79c75
2: test.Test@89f2ac63
Run Code Online (Sandbox Code Playgroud)
我可以看到第一个输出是正确的.无论我多久刷新一次页面,都会testFromSpring返回Spring上下文中定义的bean的值.但是第二个输出清楚地表明,每次调用组件getTest上的方法时test,Test …
由于JPA 2.0不支持注入EntityListener(JPA 2.1将),因此决定使用JNDI查找来获取BeanManager并通过它获取登录用户.我定义了一个EntityListener类似的:
public class MyEntityListener {
public static BeanManager getBeanManager() {
try {
InitialContext initialContext = new InitialContext();
return (BeanManager) initialContext.lookup("java:comp/BeanManager");
} catch (NamingException e) {
e.printStackTrace();
return null;
}
}
public Object getBeanByName(String name) {
BeanManager bm = getBeanManager();
Bean bean = bm.getBeans(name).iterator().next();
CreationalContext ctx = bm.createCreationalContext(bean);
return bm.getReference(bean, bean.getClass(), ctx);
}
@PrePersist
@PreUpdate
public void onPreInsertOrUpdate(MyEntity entity) {
User loggedInUser = (User) getBeanByName("loggedInUser");
entity.setUpdatedUser(loggedInUser);
entity.setUpdatedTimestamp(new Date());
}
}
Run Code Online (Sandbox Code Playgroud)
用户在会话范围内管理为:
@SessionScoped
public class UserManager …Run Code Online (Sandbox Code Playgroud) 我正在尝试使用启动ejb在启动时做一些事情.但我的豆子从未被召唤过.
这是我的豆子:
import javax.annotation.PostConstruct;
import javax.ejb.Startup;
import javax.inject.Singleton;
@Singleton
@Startup
public class StartupBean {
@PostConstruct
public void doSomething(){
System.out.println("why??");
}
}
Run Code Online (Sandbox Code Playgroud)
我正在使用jboss 7.1.1.
我究竟做错了什么?你可以在bitbucket找到我的源代码:https://bitbucket.org/cremersstijn/jee/src/9e22ed2b798a/simple-startup-bean
我正在使用WELD-SE进行依赖注入的Java SE环境中进行编程.因此,类的依赖关系看起来像这样:
public class ProductionCodeClass {
@Inject
private DependencyClass dependency;
}
Run Code Online (Sandbox Code Playgroud)
在为这个类编写单元测试时,我正在创建一个模拟器DependencyClass,因为我不想为我运行的每个测试启动一个完整的CDI环境,我手动"注入"模拟:
import static TestSupport.setField;
import static org.mockito.Mockito.*;
public class ProductionCodeClassTest {
@Before
public void setUp() {
mockedDependency = mock(DependencyClass.class);
testedInstance = new ProductionCodeClass();
setField(testedInstance, "dependency", mockedDependency);
}
}
Run Code Online (Sandbox Code Playgroud)
setField()我使用我在测试中使用的工具在类中编写的静态导入方法:
public class TestSupport {
public static void setField(
final Object instance,
final String field,
final Object value) {
try {
for (Class classIterator = instance.getClass();
classIterator != null;
classIterator = classIterator.getSuperclass()) {
try {
final Field declaredField …Run Code Online (Sandbox Code Playgroud) 是否有可以推荐的CDI/Weld现有或即将出版的书籍?
我正在寻找与Seam in Action类似的东西,这是Seam的一个很好的参考,但现在看起来有点过时了.
如何在CDI bean中定义会话@SessionScoped?
这个注释是否仅在从Servlet容器调用时才有效,其中会话以HttpSession?的形式定义好?
如果不是,那么EJB如何@Inject @SessionScoped MyBean myBean能够知道会话到底是什么?我的意思是,这个EJB的方法可以由独立客户端,RESTful WS或其他视图调用.
在这种情况下会发生什么?如果注释没有意义,它应该MyBean为每个请求注入新的实例,还是应该在所有请求中保留相同的实例?
作为CDI的新手,我想知道替代品和限定符之间的实际区别.
在Weld参考文献中,它声明:
4.3.限定符注释
如果我们有多个实现特定bean类型的bean,则注入点可以使用限定符注释准确指定应注入哪个bean.
但在解释替代品时,据说:
4.7.备择方案
替代方案是bean,其实现特定于特定客户端模块或部署方案.
如果我理解正确,@ Qualifier定义了目标bean的哪些实现被注入到注入点.
另一方面,@ Alternative描述了在部署期间依赖于客户关于标准的Alternatice(我的意思是"@default")是否被注入注入点的愿望.
这是正确的 ?
根据Glassfish 4.0 wiki,Glassfish 4.0应包含JSR349 Bean Validation 1.1: GF4 wiki链接
根据JSR349规范,CDI Injection应该开箱即用:Bean Validation 1.1.CDI集成
所以我相应地更改了我的pom.xml:
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
<scope>provided</scope>
</dependency>
Run Code Online (Sandbox Code Playgroud)
并尝试将CDI Bean注入ConstraintValidator:
public class UniqueEmaiValidator implements ConstraintValidator<UniqueEmail, String> {
@Inject
private UserAccountService accountService;
@Override
public void initialize(UniqueEmail constraintAnnotation) {
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
return !accountService.userExistsByEmail(value);
}
}
Run Code Online (Sandbox Code Playgroud)
但是,在测试应用程序(使用arquillian-glassfish-remote-3.1 1.0.0.CR4运行Arquillian 1.1.1.)时,验证将始终失败,因为它userAccountService为null,因此NullPointerException最终会抛出 .
我错过了什么使Bean Validation 1.1工作?
编辑:
A)可以确认它不是由Arquillian远程测试引起的 - 也会抛出NPEx.在服务器上运行时
B)在GlassFish Server Open Source Edition 4.0上运行(build 89)
C)我使用Hibernate Validator的5.0.1.FINAL显式重新构建了bean-validation.jar.的mvn package输出: …
我添加了一个PhaseListener到faces-config.xml:
<lifecycle>
<phase-listener>com.project.NotificationListener</phase-listener>
</lifecycle>
Run Code Online (Sandbox Code Playgroud)
这个类似乎是正确的,因为它非常简单.
public class NotificationListener implements PhaseListener {
@Inject
private MyCDIStuff stuff;
@Override
public PhaseId getPhaseId() {
return PhaseId.RENDER_RESPONSE;
}
@Override
public void beforePhase(PhaseEvent event) {
this.stuff.doStuff();
}
}
Run Code Online (Sandbox Code Playgroud)
'beforePhase'方法被正确调用,但MyCDIStuff对象为null.我尝试使用@Singleton最可能不正确的类的注释,并且它也没有使注入工作.
有没有办法注入CDI托管bean PhaseListener?
注入任何服务时,我有两个选择:
(现场注射)
@Inject
private MyService myService;
Run Code Online (Sandbox Code Playgroud)
或(构造函数注入)
private MyService myService;
@Inject
public ClassWhereIWantToInject(MyService mySerivce){
this.myService = myService;
}
Run Code Online (Sandbox Code Playgroud)
为什么Constructor注射比Filed注射更好?