ejb客户端的三种调用方法,以及InitialContext lookup后的jndi对象在服务重启后缓存失效的问题
2015-10-21 20:03
603 查看
1、第一种调用方法:
在使用ejb客户端时,如果将jndi对象缓存起来,不用每次都lookup,这样可以节省一点效率,但是当ejb服务重启时,缓存的jndi对象将不能使用。
将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里,通过配置,可以支持缓存,也可以不支持缓存,配置如下:
cache设为false就不缓存,每次用的时候重新lookup,否则,就会缓存。
分析spring源码如下:
JndiObjectFactoryBean
JndiObjectTargetSource类部分代码:如果cache为false cachedObject 就会一直是null,每次调用都会重新lookup
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"); 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对象,不会缓存。
相关文章推荐
- DEVICE_ATTR 和 sysfs 的东西 -- sysfs_create_group
- 开博!
- UVA 10201
- live555移植到Android过程.
- finalize()与System.gc()
- 【WIN10】Toast 通知
- JAVA数据类型学习总结
- 命令行安装卸载驱动服务
- [android]AlertDialog和AlertDialog.Builder
- AJAX responseXML 实例着重点的说明
- 洛谷1043 数字游戏
- 活动的启动模式
- 内存缓存 原理 实现
- 查看电脑中打开端口的命令
- 串口ISP方式下载单片机程序设计
- fatal error LNK1181: 无法打开输入文件“libcd.lib”
- Web Cryptography API
- swift-正则验证手机号码
- 项目开发,我的名字不可能这么可爱——开篇
- Python之继承