1、第一種調用方法:
Properties p = new Properties();
p.setProperty("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
p.setProperty("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces");
p.setProperty("java.naming.provider.url", "10.10.77.87:1199");
InitialContext ctx = new InitialContext(p);
CreditDirectPayRemote remote = (CreditDirectPayRemote) ctx.lookup("creditDirectPay/pay/remote");
在使用ejb用戶端時,如果将jndi對象緩存起來,不用每次都lookup,這樣可以節省一點效率,但是當ejb服務重新開機時,緩存的jndi對象将不能使用。
Properties p = new Properties();
p.setProperty("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
p.setProperty("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces");
p.setProperty("java.naming.provider.url", "10.10.77.87:1199");
InitialContext ctx = new InitialContext(p);
CreditDirectPayRemote remote = (CreditDirectPayRemote) ctx.lookup("creditDirectPay/pay/remote");
for(;;){
try {
System.out.println("第"+(++i)+"次:");
rs= remote.directPay();
Thread.sleep(1500);
} catch (Exception e) {
System.out.println("異常:"+e.getMessage());
Thread.sleep(1000);
}
}
将ejb服務重新開機後,報如下錯誤:
異常:Unreachable?: Service unavailable.
java.lang.RuntimeException: Unreachable?: Service unavailable.
at org.jboss.aspects.remoting.ClusterChooserInterceptor.invoke(ClusterChooserInterceptor.java:176)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
at org.jboss.aspects.tx.ClientTxPropagationInterceptor.invoke(ClientTxPropagationInterceptor.java:67)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
at org.jboss.aspects.security.SecurityClientInterceptor.invoke(SecurityClientInterceptor.java:53)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
at org.jboss.ejb3.remoting.ClusteredIsLocalInterceptor.invoke(ClusteredIsLocalInterceptor.java:55)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
at org.jboss.ejb3.stateless.StatelessClusteredProxy.invoke(StatelessClusteredProxy.java:112)
at com.sun.proxy.$Proxy0.directPay(Unknown Source)
at EjbTest.main(EjbTest.java:95)
是以,如果要支援ejb伺服器的重新開機而不重新開機用戶端應用,不能将用戶端應用的jndi對象緩存。
2、第二種方法:在spring裡,通過配置,可以支援緩存,也可以不支援緩存,配置如下:
<bean id="jndiTemplate"
class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.provider.url">
${java.naming.provider.url}
</prop>
<prop key="java.naming.factory.initial">
${java.naming.factory.initial}
</prop>
<prop key="java.naming.factory.url.pkgs">
${java.naming.factory.url.pkgs}
</prop>
</props>
</property>
</bean>
<bean id="creditDirectPayRemote" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate" ref="jndiTemplate"/>
<property name="cache" value="false"/>
<property name="jndiName" value="creditDirectPay/pay/remote"/>
</bean>
<bean id="testBean" class="com.Test">
<property name="creditDirectPayRemote" ref="creditDirectPayRemote" />
</bean>
cache設為false就不緩存,每次用的時候重新lookup,否則,就會緩存。
分析spring源碼如下:
JndiObjectFactoryBean
if (this.proxyInterfaces != null || !this.lookupOnStartup || !this.cache || this.exposeAccessContext) {
// We need to create a proxy for this...
if (this.defaultObject != null) {
throw new IllegalArgumentException(
"'defaultObject' is not supported in combination with 'proxyInterface'");
}
// We need a proxy and a JndiObjectTargetSource.
this.jndiObject = JndiObjectProxyFactory.createJndiObjectProxy(this);
}
else {
if (this.defaultObject != null && getExpectedType() != null &&
!getExpectedType().isInstance(this.defaultObject)) {
throw new IllegalArgumentException("Default object [" + this.defaultObject +
"] of type [" + this.defaultObject.getClass().getName() +
"] is not of expected type [" + getExpectedType().getName() + "]");
}
// Locate specified JNDI object.
this.jndiObject = lookupWithFallback();
}
}
private static Object createJndiObjectProxy(JndiObjectFactoryBean jof) throws NamingException {
// Create a JndiObjectTargetSource that mirrors the JndiObjectFactoryBean's configuration.
JndiObjectTargetSource targetSource = new JndiObjectTargetSource();
targetSource.setJndiTemplate(jof.getJndiTemplate());
targetSource.setJndiName(jof.getJndiName());
targetSource.setExpectedType(jof.getExpectedType());
targetSource.setResourceRef(jof.isResourceRef());
targetSource.setLookupOnStartup(jof.lookupOnStartup);
targetSource.setCache(jof.cache);
targetSource.afterPropertiesSet();
// Create a proxy with JndiObjectFactoryBean's proxy interface and the JndiObjectTargetSource.
ProxyFactory proxyFactory = new ProxyFactory();
if (jof.proxyInterfaces != null) {
proxyFactory.setInterfaces(jof.proxyInterfaces);
}
else {
Class targetClass = targetSource.getTargetClass();
if (targetClass == null) {
throw new IllegalStateException(
"Cannot deactivate 'lookupOnStartup' without specifying a 'proxyInterface' or 'expectedType'");
}
proxyFactory.setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, jof.beanClassLoader));
}
if (jof.exposeAccessContext) {
proxyFactory.addAdvice(new JndiContextExposingInterceptor(jof.getJndiTemplate()));
}
proxyFactory.setTargetSource(targetSource);
return proxyFactory.getProxy(jof.beanClassLoader);
}
JndiObjectTargetSource類部分代碼:如果cache為false cachedObject 就會一直是null,每次調用都會重新lookup
public Object getTarget() {
try {
if (this.lookupOnStartup || !this.cache) {
return (this.cachedObject != null ? this.cachedObject : lookup());
}
else {
synchronized (this) {
if (this.cachedObject == null) {
this.cachedObject = lookup();
}
return this.cachedObject;
}
}
}
catch (NamingException ex) {
throw new JndiLookupFailureException("JndiObjectTargetSource failed to obtain new target object", ex);
}
}
lookup的調用
protected <T> T lookup(String jndiName, Class<T> requiredType) throws NamingException {
Assert.notNull(jndiName, "'jndiName' must not be null");
String convertedName = convertJndiName(jndiName);
T jndiObject = null;
try {
jndiObject = getJndiTemplate().lookup(convertedName, requiredType);
}
catch (NamingException ex) {
if (!convertedName.equals(jndiName)) {
// Try fallback to originally specified name...
if (logger.isDebugEnabled()) {
logger.debug("Converted JNDI name [" + convertedName +
"] not found - trying original name [" + jndiName + "]. " + ex);
}
jndiObject = getJndiTemplate().lookup(jndiName, requiredType);
}
else {
throw ex;
}
}
public Object lookup(final String name) throws NamingException {
if (logger.isDebugEnabled()) {
logger.debug("Looking up JNDI object with name [" + name + "]");
}
return execute(new JndiCallback<Object>() {
public Object doInContext(Context ctx) throws NamingException {
Object located = ctx.lookup(name);
if (located == null) {
throw new NameNotFoundException(
"JNDI object with [" + name + "] not found: JNDI implementation returned null");
}
return located;
}
});
}
public <T> T execute(JndiCallback<T> contextCallback) throws NamingException {//每次都會建立一個新的InitialContext對象,然後lookup,最終關閉。
Context ctx = getContext();
try {
return contextCallback.doInContext(ctx);
}
finally {
releaseContext(ctx);
}
}
3、第三種方法
如果不使用spring注入的方式編寫ejb的調用,可以直接引用spring的org.springframework.jndi.JndiTemplate類,如下:
Properties p = new Properties();
p.setProperty("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
p.setProperty("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces");
p.setProperty("java.naming.provider.url", "10.10.77.87:1199");
JndiTemplate jndiTemplate = new JndiTemplate(p);
Object remot = null;
try {
remot = jndiTemplate.lookup(jndi);
} catch (NamingException e) {
}
這也是每次都重新lookup jndi對象,不會緩存。