2010-03-17 17 views
5

Soy bastante nuevo en Java EE, así que esto podría ser estúpido ... tengan paciencia conmigo por favor: D¿Cómo inyectar un Bean Session en un Bean Driveled Message?

Me gustaría inyectar un bean de sesión sin estado en un bean controlado por mensajes. Básicamente, el MDB recibe un mensaje JMS y luego usa un bean de sesión para realizar el trabajo. El bean de sesión contiene la lógica comercial.

Aquí es mi bean de sesión:

@Stateless 
public class TestBean implements TestBeanRemote { 

    public void doSomething() { 
    // business logic goes here 
    } 
} 

La interfaz de juego:

@Remote 
public interface TestBeanRemote { 

    public void doSomething(); 
} 

Aquí está mi 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(); 
    } 
} 

Hasta el momento, no es ciencia de cohetes, ¿verdad?

Por desgracia, al implementar esta a GlassFish v3, y el envío de un mensaje a la adecuada cola JMS, tengo errores que GlassFish es incapaz de localizar el 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]]] 

Así que mis preguntas son:

  • ¿es esta la forma correcta de inyectar un bean de sesión en otro bean (particularmente un bean controlado por mensajes)?
  • ¿por qué falla la búsqueda de nombres?

Respuesta

3

Bien, descubrí que si agrego la anotación @LocalBean al bean de sesión, funciona. Que ...?

+0

Estoy un poco más lejos ahora. @LocalBean identifica un bean sin una interfaz. Así que esto no es lo que quiero, aunque funciona: D – Hank

+0

Deberías haber usado "@EJB private TestBeanRemote testBean;" – Dagvadorj

6

Podría tratar de definir cosas como esta:

@Remote 
public interface TestBeanRemote { 

    public void doSomething(); 
} 

@Stateless(name="TestBeanRemote") 
public class TestBean implements TestBeanRemote { 

    public void doSomething() { 
    // business logic goes here 
    } 
} 

Y luego, en el 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(); 
    } 
} 

Si este trabajo, voy a tratar de dar una explicación :)

+0

Lo sentimos, desafortunadamente eso tampoco funciona. Creo que iré con lo que descubrí sobre IoC. ¡Gracias de cualquier manera! – Hank

+0

@Hank Weird, según entiendo que debería. Estoy confundido ... –

4

Parece que mi problema estaba relacionado con la Inversión de control y causado por mi falta de conocimiento y las sugerencias de Netbeans para nombres de clase/interfaz.

Descubrí que, para encontrar el frijol correcto y la interfaz correcta, debería nombrarlos correctamente. Esto es lo que funciona:

@Remote 
public interface Test { 

    public void doSomething(); 
} 

@Stateless 
public class TestBean implements Test { 

    public void doSomething() { 
    // business logic goes here 
    } 
} 

Y en el MDB accedo 'Test' no '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(); 
    } 
} 
+0

¿Puedes agregar alguna referencia sobre tus hallazgos sobre las convenciones de nombres? –

+1

Pruebe aquí: http://java.sun.com/blueprints/code/namingconventions.html – Hank

+0

Ok, estoy empezando a entender esto cada vez más ahora. Mi ejemplo anterior sería correcto, si la interfaz fuera @Local. Cuando inyecto un bean de sesión en algo, estoy inyectando . El contenedor luego trata de encontrar la clase de implementación ( Bean), así como la interfaz apropiada (para @Local use: o Local, para @Remote use: Remoto). ¡Así que el problema no era JNDI, no estaba cumpliendo con las convenciones de nomenclatura! – Hank

6

Creo que el problema del primer ejemplo es que usted está tratando de inyectar la implementación del EJB y no su interfaz. La vista local sin interfaz de EJB 3.1 solo es posible si no define ninguna interfaz, ni siquiera una remota.Por lo que cambiar el punto de inyección a la siguiente debería funcionar:

@EJB 
private TestBeanRemote testBean; 

Si está utilizando su aplicación dentro de un entorno no agrupado, por lo única JVM, debe pensar en cambiar la interfaz a @Local. Tan pronto como accedas a los EJB usando su interfaz remota, obtienes muchos gastos generales. Ya no se puede acceder a los parámetros y valores de retorno por referencia, sino por valor, ya que siempre se copian (la especificación lo dice). Esto podría conducir a problemas de rendimiento cuando se trata de objetos más complejos.

Esperado que ayudó.

Cuestiones relacionadas