您的位置:首页 > 其它

ejb客户端的三种调用方法,以及InitialContext lookup后的jndi对象在服务重启后缓存失效的问题

2015-10-21 20:03 603 查看
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对象,不会缓存。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: