标签: cdi

用CDI/Weld注入通用豆类

我刚刚来自我的小型JavaSE/Guice世界,目前正在发现"由容器携带"-EE6的路径.在使用Glassfish3.1遇到麻烦之后,我刚刚切换到JBoss,现在面临的问题不应该是一个问题.

作为基础结构辅助类,我试图为任何类型的实体创建通用存储库/ DAO.以一种非常简单的方式,这可能看起来像这样.

public class Repository<E, K extends Serializable & Comparable<K>> {

    private final Instance<EntityManager> entityManagerInstance;

    protected final Class<E> getDomainObjectClass() {
        return domainObjectClass;
    }

    private final Class<E> domainObjectClass;

    protected final EntityManager getEntityManager() {
            return entityManagerInstance.get();
    }

    @Inject
    public Repository(Instance<EntityManager> entityManageryProvider, Provider<E> domainObjectProvider) {
            //This is a dirty hack, sadly :(
            domainObjectClass = (Class<E>)domainObjectProvider.get().getClass();
            this.entityManagerInstance = entityManageryProvider;
    }

    public final void persist(E domainObject) {
        final EntityManager em = getEntityManager();
        em.persist(domainObject);
    }

    public final Collection<E> getAllEntities() {
            final EntityManager em = getEntityManager(); …
Run Code Online (Sandbox Code Playgroud)

genericdao cdi java-ee-6 jboss-weld

7
推荐指数
1
解决办法
5597
查看次数

WELD-001408注入EntityManager时不满意的依赖关系

我有@Statelessbean实现两个接口(远程和本地).我还添加@LocalBean了用于通过无接口视图访问bean的anotation.

@Stateless
@LocalBean
public class WeatherDataBean implements WeatherDataBeanRemote, WeatherDataBeanLocal {
    @Inject
    private EntityManager entityManager;

    public WeatherDataBean () {

    }
    // ....attributes, getter & setter methods ....
}
Run Code Online (Sandbox Code Playgroud)

我使用@Inject这个原因取自JBoss AS7快速启动的这个例子:

我们使用来自CDI的"资源生成器"模式,将实体管理器的旧式@PersistenceContext注入"别名"为CDI样式注入.这允许我们在整个应用程序中使用一致的注入样式(@Inject).

以前我用过:

@PersistenceContext(unitName="WeatherStationJPA")
private EntityManager entityManager;
Run Code Online (Sandbox Code Playgroud)

在EJB中,它没有任何问题.但是使用@Inject注释我得到这个错误:

WELD-001408在注入点[[field] @Inject private ejb.WeatherDataBean.entityManager]中带有限定符[@Default]的[EntityManager]类型的不满意依赖项

这是我如何定义类资源:

public class Resources {
     @SuppressWarnings("unused")
     @PersistenceContext(unitName="WeatherStationJPA")
     @Produces
     private EntityManager entityManager;

     @Produces
     FacesContext getFacesContext() {
         return FacesContext.getCurrentInstance();
     }
}
Run Code Online (Sandbox Code Playgroud)

如果我尝试注入实体管理器,为什么会出现此错误?

编辑: 根据@LightGuard的请求,我正在添加我用来引用注释的包:

  1. WeatherDataBean有:

    import javax.ejb.LocalBean;
    import javax.ejb.Stateless;
    import javax.inject.Inject; …
    Run Code Online (Sandbox Code Playgroud)

dependency-injection stateless-session-bean entitymanager cdi java-ee-6

7
推荐指数
2
解决办法
2万
查看次数

使用CDI将记录器注入Ejb

我正在努力将我认为是一项简单的任务放在一起.我有一个无状态单例Bean,我将用作我的应用程序的"加载器".bean包含在Jar(loader.jar)文件中,并驻留在我的EAR的lib文件夹中.

在EAR的根目录中有另一个jar,它包含我的应用程序将使用的无状态会话Bean的实现.

然后我创建了一个小的logger类,它实际上包含了log4j:



    import javax.annotation.PostConstruct;
    import javax.annotation.PreDestroy;
    import javax.enterprise.context.RequestScoped;
    import javax.enterprise.inject.Produces;
    import javax.enterprise.inject.spi.InjectionPoint;
    import javax.inject.Named;

    import org.apache.log4j.Logger;

    public class LoggerFactory {
        private Logger logger;

        public LoggerFactory(){
            logger = Logger.getLogger(this.getClass().getName());
        }

        @Produces Logger getLogger(InjectionPoint caller){
            return Logger.getLogger(caller.getMember().getDeclaringClass().getName());
        }
    }

Run Code Online (Sandbox Code Playgroud)

然后我把它放在一个罐子里,我把它命名为utils.jar.在这个jar中,按照CDI规范,我在META-INF文件夹中创建了一个空的beans.xml文件.utils.jar驻留在我的EAR的lib文件夹中.

现在,我之前提到的无状态Singleton Bean(加载器)

我写的就是这个



    import javax.annotation.PostConstruct;
    import javax.ejb.Singleton;
    import javax.ejb.Startup;
    import javax.inject.Inject;

    import org.apache.log4j.Logger;

    @Startup
    @Singleton
    public class Core {
        @Inject 
        private Logger logger;

        @PostConstruct
        void init(){
            logger.info("Core started");
        }
    }

Run Code Online (Sandbox Code Playgroud)

当我在glassfish 3.1.2上部署我的应用程序时,我在我的Loader bean中第一次调用logger时获得了一个简单的NPE.这让我觉得CDI调用根本没有发生,但我真诚地了解我做错了什么.

到目前为止,我的EAR结构如下:



       EAR
         |
         +---lib
         |     +--loader.jar
         |     +--utils.jar …
Run Code Online (Sandbox Code Playgroud)

ejb java-ee cdi

7
推荐指数
1
解决办法
5072
查看次数

依赖注入请求参数与CDI和JSF2

使用CDI和JSF2时如何将HTTP请求参数注入bean中?

cdi jsf-2 http-request-parameters

7
推荐指数
1
解决办法
6417
查看次数

当打包为EAR时,是否可以在WAR内观察CDI事件

我有一个包含多个后端模块(EJB)的企业应用程序归档(EAR)以及一些Web模块(WAR).

事件在其中一个后端模块中被触发:

@Inject private Event<MyEvent> myEvent;
...
public void fireEvent() {
  myEvent.fire(new MyEvent());
}
...
Run Code Online (Sandbox Code Playgroud)

可以在任何其他后端模块中观察到这样的代码:

public void listener(@Observes MyEvent myEvent) {
..
}
Run Code Online (Sandbox Code Playgroud)

但是我无法在WAR中检索事件.这是因为类加载器可见性(来自WAR的类对EJB不可见)还是CDI应该处理这个问题?

如果CDI不能用于应用程序范围的事件,有哪些替代方案?

  • JMS
  • 番石榴EventBus
  • ...

有什么与CDI有效吗?也许某些CDI扩展将事件连接到WAR?

-----------编辑:

如果它在同一个WAR中被触发,我能够观察到该事件.此外,我尝试使用@Stateless bean作为事件侦听器,但没有成功.

包装是这样的:

    • WAR(应在此处观察事件)
    • 战争
    • EJB(事件在这里被触发)

java ear war java-ee cdi

7
推荐指数
1
解决办法
1761
查看次数

会话过期后未调用@PreDestroy

这是在WAS8.0上运行的JSF 2应用程序.这是一个页面的"支持"bean的代码.

    @Named("mySessionBean")
    @SessionScoped
    @Stateful
    @LocalBean
    @StatefulTimeout(unit = TimeUnit.MINUTES, value = 10)
    public class MySessionBean implements Serializable {
        @PostConstruct
        public void init()
        {
             System.out.println("start MySessionBean: " + this.hashCode());
         }

        @PreDestroy
        public void cleanup()
        {
             System.out.println("destroy MySessionBean: " + this.hashCode());
         }
        ....
    }
Run Code Online (Sandbox Code Playgroud)

web.xml中设置的会话超时值小于bean的超时.当我运行应用程序时,我看到来自@PostConstruct的打印输出,但从未看到来自@PreDestroy的打印输出.我尝试了以下两种方案:1.logout - invalidateSession; 2.只需等到会话到期.

我不是应用程序的设计者.设计者坚持将所有支持bean作为有状态会话bean.我认为更主流的方法就是让它们成为CDI bean.但无论如何,当我确实将注释更改为CDI时,我也开始从@PreDestroy获取打印输出

    @Named("mySessionBean")
    @SessionScoped
    public class MySessionBean implements Serializable {
    .....
Run Code Online (Sandbox Code Playgroud)

我的问题是,在第一种情况下我没有得到@PreDestroy方法调用的原因是什么?如果我不能看到@PreDestroy被调用,在那里我可以跟踪"后盾" bean的生命周期(在这种情况下,有状态会话Bean)的任何其他方式.谢谢!

cdi java-ee-6 jsf-2 websphere-8

7
推荐指数
1
解决办法
6753
查看次数

Java EE7的拦截器问题

我正在测试/切换到Java EE7(Glassfish 4),我遇到的一个问题是拦截器,每当我尝试运行项目时,我都会收到以下错误.

严重:加载应用程序时出现异常:CDI部署失败:WELD-001417文件中启用拦截器类com.xxxxxx.security.SecuredInterceptor:/home/xxxxxx/xxxxxx/target/xxxxxx/WEB-INF/beans.xml@7既不是注释@Interceptor也没有通过便携式扩展注册

我正在看CDI 1.1规范的1.3.6节,它看起来没什么变化,所以我做错了什么?

这是我正在使用的代码;

@InterceptorBinding
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Secured {}
Run Code Online (Sandbox Code Playgroud)

 

@Secured
@Interceptor
public class SecuredInterceptor implements Serializable
{
    @AroundInvoke
    public Object interceptSecured(InvocationContext ic) throws Exception
    {
        // Do Stuff
    }
}
Run Code Online (Sandbox Code Playgroud)

 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
       bean-discovery-mode="annotated">
    <interceptors>
        <class>com.xxxxxx.security.SecuredInterceptor</class>
    </interceptors>
</beans>
Run Code Online (Sandbox Code Playgroud)

glassfish interceptor cdi java-ee-7

7
推荐指数
2
解决办法
2697
查看次数

Viewscoped JSF和CDI bean

我在JBoss EAP 6上使用Java EE 6,我的JSF bean注释如下:( @ManagedBean @ViewScoped两者都来自javax.faces.bean包)

然而,他们也CDI豆(默认构造函数,使用@Inject,@PreDestroy等等).我一直在阅读你不能混合这些注释(JSF和CDI),但它显然工作正常:注入正在工作,preDestroy在视图更改时被调用等).

我错过了什么吗?问题是什么?为什么不用?

jsf cdi view-scope

7
推荐指数
1
解决办法
4173
查看次数

如果要注入的实例具有最终类,如何使用InjectMocks

我想用mockito测试一些服务.这些服务基于CDI,不幸的是,使用现场注入,我无法改变.

public class Service {
   @Inject Logger logger;

   public void method() {
      logger.info("some log text");
  }
}
Run Code Online (Sandbox Code Playgroud)

现在使用mockito的@InjectMocks注释创建可测试的实例非常容易.它将注入嘲笑和间谍.

@RunWith(MockitoJUnitRunner.class)
public class ServiceTest {
  @Spy Logger logger = LoggerFactory.getLogger(Service.class);

  @InjectMocks Service service;

  @Test public void test() {
     // Given
     // When
     service.method();
     // Then
  }
Run Code Online (Sandbox Code Playgroud)

我需要将一些工作记录器注入我正在测试的服务类中.记录器框架是slf4j,首选记录器是logback.但不幸的Logger是,logback的实现是最终的,所以我不能窥探它,它会导致运行时异常.

我想到的解决方法:

  • 使用反射来初始化服务上的记录器属性(穷人的注射)
  • 实现一个spyable(非最终)记录器包装器,它委托给最终的logback记录器

但对于那些(那些)问题,是否有一个干净或至少更好的解决方案?

java logback mockito cdi

7
推荐指数
1
解决办法
1454
查看次数

为什么无状态bean被视为伪范围并且不能具有循环依赖性?

使用Wildfly 8.1我有几个bean,我尝试将几个EJB互相注入.可以说我有3个豆子:

@Stateless 
public class A{
  @Inject
  private B b;
}

@Stateless 
public class B{
  @Inject
  private C c;
}

@Stateless 
public class C{
  @Inject
  private A a;
}
Run Code Online (Sandbox Code Playgroud)

显然,我有循环依赖.根据规格:

容器需要支持bean依赖关系图中的循环,其中参与每个循环依赖关系的至少一个bean具有正常范围

在容器中的代码上运行会导致表单错误:

org.jboss.weld.exceptions.DeploymentException:WELD-001443:伪范围bean具有循环依赖关系.依赖路径:

-Session bean [带有限定符的A类[@Default @Any]; 本地接口是[A] BackedAnnotatedField] @Inject private B,

[..]

我的问题是:@Stateless bean的范围是什么?它默认是@Dependent吗?最重要的是我如何在无状态会话bean之间启用循环依赖?

对不起,如果这个问题太琐碎了.我将非常感谢任何可以解释所呈现行为的进一步阅读资源.提前致谢.

更新 好了.我找到了解决方法.我使用@EJB注释而不是@Inject,但这并没有解释@Inject的奇怪行为.这个问题仍未解决,但正如Mika所说,CDI规范和Weld RI都可能是未解决的问题.

ejb java-ee cdi ejb-3.0 wildfly

7
推荐指数
1
解决办法
5281
查看次数