Como injetar um Bean de Sessão em um Bean acionado por Mensagens?
-
20-09-2019 - |
Pergunta
Estou razoavelmente novo para Java EE, então isso pode ser estúpido..tenha paciência comigo pls :D
Eu gostaria de injetar um stateless session bean em um message-driven bean.Basicamente, o MDB recebe uma mensagem de JMS, em seguida, usa um bean de sessão para executar o trabalho.O bean de sessão que contém a lógica de negócios.
Aqui está o meu Bean de Sessão:
@Stateless
public class TestBean implements TestBeanRemote {
public void doSomething() {
// business logic goes here
}
}
A interface correspondente:
@Remote
public interface TestBeanRemote {
public void doSomething();
}
Aqui está o meu MDB:
@MessageDriven(mappedName = "jms/mvs.TestController", activationConfig = {
@ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")
})
public class TestController implements MessageListener {
@EJB
private TestBean testBean;
public TestController() {
}
public void onMessage(Message message) {
testBean.doSomething();
}
}
Até agora, não é ciência do foguete, certo?
Infelizmente, ao implantar este glassfish v3, e o envio de uma mensagem para o adequado Fila JMS, eu recebo erros que o glassfish é não é possível localizar o TestBean EJB:
java.lang.IllegalStateException: Exception attempting to inject Remote ejb-ref name=mvs.test.TestController/testBean,Remote 3.x interface =mvs.test.TestBean,ejb-link=null,lookup=null,mappedName=,jndi-name=mvs.test.TestBean,refType=Session into class mvs.test.TestController
Caused by: com.sun.enterprise.container.common.spi.util.InjectionException: Exception attempting to inject Remote ejb-ref name=mvs.test.TestController/testBean,Remote 3.x interface =mvs.test.TestBean,ejb-link=null,lookup=null,mappedName=,jndi-name=mvs.test.TestBean,refType=Session into class mvs.test.TestController
Caused by: javax.naming.NamingException: Lookup failed for 'java:comp/env/mvs.test.TestController/testBean' in SerialContext [Root exception is javax.naming.NamingException: Exception resolving Ejb for 'Remote ejb-ref name=mvs.test.TestController/testBean,Remote 3.x interface =mvs.test.TestBean,ejb-link=null,lookup=null,mappedName=,jndi-name=mvs.test.TestBean,refType=Session' . Actual (possibly internal) Remote JNDI name used for lookup is 'mvs.test.TestBean#mvs.test.TestBean' [Root exception is javax.naming.NamingException: Lookup failed for 'mvs.test.TestBean#mvs.test.TestBean' in SerialContext [Root exception is javax.naming.NameNotFoundException: mvs.test.TestBean#mvs.test.TestBean not found]]]
Então minhas perguntas são:
- é esta a maneira correta de injeção de um bean de sessão para outra feijão (em particular, message driven bean)?
- qual é a nomeação de pesquisa falhando?
Solução 4
Ok, descobri que, se eu adicionar a anotação @localbean ao feijão da sessão, ele funciona. O que ...?
Outras dicas
Você poderia tentar definir coisas assim:
@Remote
public interface TestBeanRemote {
public void doSomething();
}
@Stateless(name="TestBeanRemote")
public class TestBean implements TestBeanRemote {
public void doSomething() {
// business logic goes here
}
}
E então no MDB:
@MessageDriven(mappedName = "jms/mvs.TestController", activationConfig = {
@ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")
})
public class TestController implements MessageListener {
@EJB(beanName="TestBeanRemote")
private TestBeanRemote testBean;
public TestController() {
}
public void onMessage(Message message) {
testBean.doSomething();
}
}
Se isso funcionar, tentarei fornecer uma explicação :)
Eu acho que o problema do primeiro exemplo é que você está tentando injetar a implementação do EJB e não a sua interface.O local não-interface de vista do EJB 3.1 é possível apenas se você não definir qualquer interface, nem mesmo um remoto.Para alterar o ponto de injeção para o seguinte deve funcionar out:
@EJB
private TestBeanRemote testBean;
Se você estiver usando seu aplicativo em um ambiente de cluster não, de forma única JVM, você deve pensar em mudar a interface para @Local.Assim que você estiver acessando EJBs usando sua interface remota, você está recebendo um monte de sobrecarga.Parâmetros e valores de retorno não pode ser acessado por referência, mas, por valor, como eles sempre são copiados (especificação diz isso).Isso pode levar a problemas de desempenho ao lidar com objetos mais complexos.
Espera-se que ajudaram.
Parece que meu problema estava relacionado à inversão de controle e causado pela minha falta de conhecimento e sugestões de NetBeans para nomes de classe/interface.
Descobri que - para encontrar o feijão direito e a interface certa - devo nomeá -los corretamente. Aqui está o que funciona:
@Remote
public interface Test {
public void doSomething();
}
@Stateless
public class TestBean implements Test {
public void doSomething() {
// business logic goes here
}
}
E no MDB eu acesse 'teste' não 'TestBean':
@MessageDriven(mappedName = "jms/mvs.TestController", activationConfig = {
@ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")
})
public class TestController implements MessageListener {
@EJB
private Test testBean;
public TestController() {
}
public void onMessage(Message message) {
testBean.doSomething();
}
}