2013-04-09 50 views
0

我使用的是Weblogic 10.3.6,Mojarra 2.0.9和EJB3。我們擁有@ViewScoped和@SessionScoped JSF託管bean,並且我們要求在發生服務器故障的情況下仍然可以繼續使用。我剛剛解決了這個問題,直到我在JSF Beans上使用EJB注入時遇到了問題。下面是simplifed豆@EJB在故障轉移後在JSF Bean上注入

EJB接口

@JNDIName("our.ejb.jndiname") 
@Remote 
public interface OurEJBInterface { 

    some methods... 

} 

EJB豆

@Stateless 
@TransactionManagement(TransactionManagementType.CONTAINER) 
public class ourBean implements OurEJBInterface { 

    the methods... 
} 

JSF輔助Bean

@ManagedBean 
@ViewScoped 
public class OurBackingBean { 


    @EJB 
    private OurBeanBeanInterface ourBeanBeanInterface ; 


    public void submit() 
    { 
     ourBeanBeanInterface.doSomethingFromBean(); 
    } 

} 

當我們模擬會話正確從新的服務器,不過參考EJB仍然指向舊服務器檢索故障轉移,我們得到這個錯誤:

javax.ejb.EJBException: Could not establish a connection with -1977369784351278190S:MCPVMWLS01:[7030,7030,-1,-1,-1,-1,-1]:Destin8ShowCase:JVM01, java.rmi.ConnectException: Destination unreachable; nested exception is: 
    java.io.IOException: Empty server reply; No available router to destination; nested exception is: 
    java.rmi.ConnectException: Destination unreachable; nested exception is: 
    java.io.IOException: Empty server reply; No available router to destination; nested exception is: java.rmi.ConnectException: Destination unreachable; nested exception is: 
    java.io.IOException: Empty server reply; No available router to destination 
java.rmi.ConnectException: Destination unreachable; nested exception is: 
    java.io.IOException: Empty server reply; No available router to destination 
    at weblogic.rjvm.ConnectionManager.bootstrap(ConnectionManager.java:470) 
    at weblogic.rjvm.ConnectionManager.bootstrap(ConnectionManager.java:402) 
    at weblogic.rjvm.RJVMImpl.ensureConnectionEstablished(RJVMImpl.java:306) 
    at weblogic.rjvm.RJVMImpl.getOutputStream(RJVMImpl.java:350) 
    at weblogic.rjvm.RJVMImpl.getRequestStreamInternal(RJVMImpl.java:612) 
    at weblogic.rjvm.RJVMImpl.getRequestStream(RJVMImpl.java:563) 
    at weblogic.rjvm.RJVMImpl.getOutboundRequest(RJVMImpl.java:789) 
    at weblogic.rmi.internal.BasicRemoteRef.getOutboundRequest(BasicRemoteRef.java:159) 
    at weblogic.rmi.internal.BasicRemoteRef.invoke(BasicRemoteRef.java:211) 
    at com.mcpplc.destin8.ejbs.manifestenquiry.ManifestEnquiryFacadeBean_qzni2o_ManifestEnquiryFacadeBeanInterfaceImpl_1036_WLStub.doMEQ02(Unknown Source) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:597) 
    at weblogic.ejb.container.internal.RemoteBusinessIntfProxy.invoke(RemoteBusinessIntfProxy.java:85) 
    at $Proxy286.doMEQ02(Unknown Source) 
    at com.mcpplc.destin8.web.jsf.backingbeans.imports.Meq02BackingBean.customProcessing(Meq02BackingBean.java:49) 
    at com.mcpplc.destin8.web.jsf.backingbeans.BackingBean.submit(BackingBean.java:179) 

有什麼辦法讓Managed Bean重新初始化指向新服務器的新EJB引用?

我知道我可以使用服務定位器,將init放在提交方法中,但如果可能的話,想使用@EJB。

在此先感謝。

+0

如果我理解正確的,你的問題是有關測試補丁。在測試過程中,您無法正確實例化您的EJB。在這種情況下,你應該使用MocKClasses和一個MockServer。你可以用http://arquillian.org/來完成,或者http://code.google.com/p/mockito/就足夠了。我希望這可以幫助你。 – 2013-04-09 15:11:40

+0

感謝您的回覆,但這不是測試相關的。這是故障切換方案中的實時代碼。 – andyfinch 2013-04-10 07:28:21

回答

0

經過一些試驗和錯誤後解決這個問題。正如Jan躲過我的注意,只注入了當地的jndi名字。爲了確保返回的EJB代理是全球性的,我需要刪除接口的@JNDIname註釋,並提供一個mappedName到@stateless@ejb註釋

@Stateless(mappedName = "MyFacadeBean") 

@EJB(mappedName = "MyFacadeBean") 
private MyFacadeBean myFacadeBean; 
0

我來自JBoss世界,所以我不完全確定它。但是你真的可以用這種方式注入一個遠程接口嗎?我認爲必須有一個查找定義。但是對於本地接口,您的呼叫應該可以工作。 如果您使用的遠程接口,你應該使用

@EJB(lookup="jnp://wholeclustername/YourBean/remote")

和你的DNS必須指向你的網絡,兩臺機器。

另一種可能的解決方法可以是@ Produce-method和@Inject,您可以在生產者方法中執行查找。

編輯:

是的,不幸的是。我也不時遇到這些黑客:(

也許還有另一種解決方法或解決方案,我在Weblogic中不夠穩固如果你想從你的源代碼中解耦,你也可以使用攔截器並注入SLSB實例每次調用,可能是因爲您的故障轉移其與@PostConstruct工作,嫌我不知道。

public class LookUpEJBInterceptor {

@AroundInvoke 
public Object around(InvocationContext ctx){ 
    try { 
     Class<?> clazzOfEJBImplementation = ctx.getTarget().getClass(); 
     //look for your field, I just check for the EJB annotation but that's not enough 
     for (Field f : clazzOfEJBImplementation.getDeclaredFields()){ 
      if(f.isAnnotationPresent(EJB.class)){ 
       f.setAccessible(true); 
       f.set(ctx.getTarget(), lookupEJB()); 
      } 
     } 

     return ctx.proceed(); 
    } catch (Exception e) { 
     e.printStackTrace(); 
     throw new EJBException(); 
    } 

} 

/** 
* get your ejb 
* 
* @return 
* @throws NamingException 
*/ 
private Object lookupEJB() throws NamingException{ 
    return new InitialContext().lookup("Your ejb lookup"); 
} 

第二個編輯:

如果你可以用AspectJ你可以構建像一個黑客這個:

pointcut checkEJB(OurEJBInterface r): call(void OurEJBInterface.yourVoid()) && target(r); 

void around (OurEJBInterface r) : yourVoid(r){ 
    r = lookupYourEJB(); 
    return proceed(r); 
} 

private Object lookupEJB() throws NamingException{ 
    return new InitialContext().lookup("Your ejb lookup"); 
} 

但兩者都只是黑客

+0

感謝您的回覆。相信我上面的代碼基本上是可用的生產代碼。我對'@ produce'和'@ inject'不太瞭解,但似乎如果我每次都必須調用一個方法來獲得我的EJB,我可能會堅持服務定位器。 – andyfinch 2013-04-09 14:45:50