我在GlassFish 3.1和Jboss AS 6.1中测试了这种行为。
在我的测试中,我已按如下方式配置了一个应用程序: 1)具有Postconstruct方法的Singleton,大约需要1.5分钟才能结束(使用thread.sleep()), 2)一个无状态Bean(名为“Abean”),每30秒运行一次@Schedule方法, 3)一个无状态Bean(名为“Bbean”),在应用程序部署之后由外部客户端请求调用(用于测试EJB 3.1中描述的场景
规范)。 注意:不会在任何EJB bean中注入Singleton。
当我在应用服务器中部署此应用程序时,我可以观察到以下内容:
Jboss和GlassFish服务器都允许预定调用和外部客户端调用到达其目标无状态bean“Abean”和“Bbean”,而Singleton仍在执行其Postconstruct方法。
在我看来,这两个应用服务器都不符合EJB 3.1规范,因为它涉及外部客户端调用(参见参考文献4.8.1 ejb-3_1-fr-specs)。 我还想知道他们的行为是否与预定电话有关(我正在考虑@Startup模式...)
这是我的测试应用程序代码:
Singleton bean
package ejbBeans;
import java.util.Date;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.ejb.SessionContext;
import javax.ejb.Singleton;
import javax.ejb.Startup;
@Startup
@Singleton
public class TestSessionBeanSingleton {
@Resource
SessionContext context;
public TestSessionBeanSingleton() throws Exception {
System.out.println("TestSessionBeanSingleton Constructor called");
}
@PostConstruct
private void init() {
System.out.println("TestSessionBeanSingleton postconstruct called " + new Date());
try {
Thread.sleep(90000);
} catch (InterruptedException e) {
System.out.println("TestSessionBeanSingleton postconstruct InterruptedException");
}
System.out.println("TestSessionBeanSingleton postconstruct End after 1,5 min " + new Date());
}
public void method1() {
System.out.println("TestSessionBeanSingleton method1 called");
}
}
无国籍豆“Abean”
package ejbBeans;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.ejb.Remote;
import javax.ejb.SessionContext;
import javax.ejb.Stateless;
@Stateless
@Remote(TestInterfaceStateless.class)
public class TestSessionBeanStateless implements TestInterfaceStateless {
@Resource
SessionContext context;
public TestSessionBeanStateless() throws Exception {
System.out.println("TestSessionBeanStateless Constructor called");
}
@PostConstruct
private void init() {
System.out.println("TestSessionBeanStateless postconstruct called");
}
public void method1(String x, Long y) {
System.out.println("TestSessionBeanStateless method1 called: String = " + x + " Long = " + y);
}
}
“Abean”远程接口
package ejbBeans;
public interface TestInterfaceStateless {
public void method1(String x, Long y);
}
预定方法bean“Bbean”
package ejbBeans;
import javax.annotation.Resource;
import javax.ejb.Schedule;
import javax.ejb.SessionContext;
import javax.ejb.Stateless;
@Stateless
public class TestTimerServiceBean {
@Resource
SessionContext sessionContext;
@Schedule(second="*/30", minute="*",hour="*",persistent=false, info="myScheduled")
public void scheduledMethod() {
System.out.println("TestTimerServiceBean autoScheduledTimedMethod called");
}
}
外部客户
package ejbClient;
import ejbBeans.TestInterfaceStateless;
import ejbBeans.TestSessionBeanStateless;
public class TestStatelessClient {
public static void main(String[] args) {
try {
TestInterfaceStateless sessionBeanEjb = (TestInterfaceStateless) ServiceLocator.locateServerSessionBean(TestInterfaceStateless.class, TestSessionBeanStateless.class, ServiceLocator.ViewType.REMOTE);
sessionBeanEjb.method1("test",25L);
} catch (Exception e) {
e.printStackTrace();
}
}
}
外部客户端的服务定位器
package ejbClient;
import java.util.Hashtable;
import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;
public class ServiceLocator {
public static enum ViewType {
NO_INTERFACE("no-interface"),
LOCAL("local"),
REMOTE("remote");
private String name;
private ViewType(String name) {
this.name = name;
}
}
protected static Object locateServerSessionBean(Class<?> beanIterface, Class<?> beanClassName, ViewType viewType) {
Object bean = null;
bean = locateJboss(beanIterface, beanClassName, viewType);
if (bean == null)
bean = locateGlassfish(beanIterface, beanClassName, viewType);
return bean;
}
private static Object locateJboss(Class<?> beanIterface, Class<?> beanClassName, ViewType viewType) {
String jndiLookupString = beanClassName.getSimpleName();
switch (viewType) {
case NO_INTERFACE:
jndiLookupString += "/" + viewType.name;
break;
case LOCAL:
case REMOTE:
jndiLookupString += "/" + viewType.name + "-" + beanIterface.getCanonicalName();
break;
}
try {
Properties env = new Properties();
env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
env.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");
env.put(Context.PROVIDER_URL, "jnp://localhost:1099");
InitialContext context = new InitialContext(env);
Object bean = context.lookup(jndiLookupString);
return bean;
} catch (Exception e) {
System.out.println("Locator: bean not found with Jboss name: " +jndiLookupString +", return null");
return null;
}
}
private static Object locateGlassfish(Class<?> beanIterface, Class<?> beanClassName, ViewType viewType) {
String jndiLookupString = "java:global/TestStartup/" + beanClassName.getSimpleName() + "!" + beanIterface.getCanonicalName();
try {
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.enterprise.naming.SerialInitContextFactory");
InitialContext context = new InitialContext(env);
Object bean = context.lookup(jndiLookupString);
return bean;
} catch (Exception e) {
System.out.println("Locator: bean not found with Glassfish name: " +jndiLookupString +", return null");
return null;
}
}
}
Jboss log
20:16:08,207 WARN [org.jboss.ejb3.TimerServiceContainer] EJBTHREE-2193: using deprecated TimerServiceFactory for restoring timers
20:16:08,556 INFO [org.jboss.ejb3.session.SessionSpecContainer] Starting jboss.j2ee:jar=TestStartup.jar,name=TestSessionBeanSingleton,service=EJB3
20:16:08,557 WARN [org.jboss.ejb3.session.SessionSpecContainer] EJBTHREE-2126: container jboss.j2ee:jar=TestStartup.jar,name=TestSessionBeanSingleton,service=EJB3 does not verify the businessObjectFactory
20:16:08,557 INFO [org.jboss.ejb3.EJBContainer] STARTED EJB: ejbBeans.TestSessionBeanSingleton ejbName: TestSessionBeanSingleton
20:16:08,557 WARN [org.jboss.ejb3.TimerServiceContainer] EJBTHREE-2193: using deprecated TimerServiceFactory for restoring timers
20:16:08,559 INFORMAZIONI [STDOUT] TestSessionBeanSingleton Constructor called
20:16:08,739 INFORMAZIONI [STDOUT] TestSessionBeanSingleton postconstruct called Sat Jan 28 20:16:08 CET 2017
20:16:30,055 INFORMAZIONI [STDOUT] TestTimerServiceBean autoScheduledTimedMethod called
20:16:55,733 INFORMAZIONI [STDOUT] TestSessionBeanStateless Constructor called
20:16:55,735 INFORMAZIONI [STDOUT] TestSessionBeanStateless postconstruct called
20:16:55,761 INFORMAZIONI [STDOUT] TestSessionBeanStateless method1 called: String = test Long = 25
20:17:00,006 INFORMAZIONI [STDOUT] TestTimerServiceBean autoScheduledTimedMethod called
20:17:30,023 INFORMAZIONI [STDOUT] TestTimerServiceBean autoScheduledTimedMethod called
20:17:38,740 INFORMAZIONI [STDOUT] TestSessionBeanSingleton postconstruct End after 1,5 min Sat Jan 28 20:17:38 CET 2017
20:17:38,761 INFORMAZIONI [STDOUT] TestSessionBeanSingleton Constructor called
20:17:38,761 INFO [org.jboss.ejb3.nointerface.impl.jndi.AbstractNoInterfaceViewBinder] Binding the following entry in Global JNDI for bean:TestSessionBeanSingleton
TestSessionBeanSingleton/no-interface -> EJB3.1 no-interface view
20:17:38,764 INFO [org.jboss.ejb3.nointerface.impl.jndi.AbstractNoInterfaceViewBinder] Binding the following entry in Global JNDI for bean:TestTimerServiceBean
TestTimerServiceBean/no-interface -> EJB3.1 no-interface view
20:18:00,004 INFORMAZIONI [STDOUT] TestTimerServiceBean autoScheduledTimedMethod called
20:18:30,003 INFORMAZIONI [STDOUT] TestTimerServiceBean autoScheduledTimedMethod called
20:19:00,002 INFORMAZIONI [STDOUT] TestTimerServiceBean autoScheduledTimedMethod called
GlassFish日志
2017-01-28T22:11:03.025+0100|Informazioni: JTS5014: Recoverable JTS instance, serverId = [3700]
2017-01-28T22:11:03.900+0100|Informazioni: EJB5181:Portable JNDI names for EJB TestSessionBeanStateless: [java:global/TestStartup/TestSessionBeanStateless!ejbBeans.TestInterfaceStateless, java:global/TestStartup/TestSessionBeanStateless]
2017-01-28T22:11:03.900+0100|Informazioni: EJB5182:Glassfish-specific (Non-portable) JNDI names for EJB TestSessionBeanStateless: [ejbBeans.TestInterfaceStateless#ejbBeans.TestInterfaceStateless, ejbBeans.TestInterfaceStateless]
2017-01-28T22:11:03.985+0100|Informazioni: Loading EJBTimerService. Please wait.
2017-01-28T22:11:04.458+0100|Informazioni: WEB0169: Created HTTP listener [http-listener-1] on host/port [0.0.0.0:8080]
2017-01-28T22:11:04.469+0100|Informazioni: WEB0169: Created HTTP listener [http-listener-2] on host/port [0.0.0.0:8181]
2017-01-28T22:11:04.474+0100|Informazioni: WEB0169: Created HTTP listener [admin-listener] on host/port [0.0.0.0:4848]
2017-01-28T22:11:04.523+0100|Informazioni: WEB0171: Created virtual server [server]
2017-01-28T22:11:04.525+0100|Informazioni: WEB0171: Created virtual server [__asadmin]
2017-01-28T22:11:05.020+0100|Informazioni: WEB0172: Virtual server [server] loaded default web module []
2017-01-28T22:11:09.059+0100|Informazioni: HV000001: Hibernate Validator 4.3.0.Final
2017-01-28T22:11:11.256+0100|Informazioni: EclipseLink, version: Eclipse Persistence Services - 2.3.2.v20111125-r10461
2017-01-28T22:11:13.065+0100|Informazioni: file:/C:/Servers/glassfish3/glassfish/domains/domain1/applications/ejb-timer-service-app/WEB-INF/classes/___EJB__Timer__App login successful
2017-01-28T22:11:13.066+0100|Avvertenza: Multiple [2] JMX MBeanServer instances exist, we will use the server at index [0] : [com.sun.enterprise.v3.admin.DynamicInterceptor@11d6ecc3].
2017-01-28T22:11:13.066+0100|Avvertenza: JMX MBeanServer in use: [com.sun.enterprise.v3.admin.DynamicInterceptor@11d6ecc3] from index [0]
2017-01-28T22:11:13.066+0100|Avvertenza: JMX MBeanServer in use: [com.sun.jmx.mbeanserver.JmxMBeanServer@44c3b4dd] from index [1]
2017-01-28T22:11:13.133+0100|Informazioni: [TimerBeanContainer] Created TimerBeanContainer: TimerBean
2017-01-28T22:11:13.163+0100|Informazioni: EJB5181:Portable JNDI names for EJB TimerBean: [java:global/ejb-timer-service-app/TimerBean, java:global/ejb-timer-service-app/TimerBean!com.sun.ejb.containers.TimerLocal]
2017-01-28T22:11:13.367+0100|Informazioni: WEB0671: Loading application [ejb-timer-service-app] at [/ejb-timer-service-app]
2017-01-28T22:11:13.369+0100|Informazioni: EJB5109:EJB Timer Service started successfully for data source [jdbc/__TimerPool]
2017-01-28T22:11:13.372+0100|Informazioni: Setting DBReadBeforeTimeout to false
2017-01-28T22:11:13.372+0100|Informazioni: ==> Restoring Timers ...
2017-01-28T22:11:13.805+0100|Informazioni: There are no EJB Timers owned by this server
2017-01-28T22:11:13.805+0100|Informazioni: <== ... Timers Restored.
2017-01-28T22:11:13.809+0100|Informazioni: EJB5181:Portable JNDI names for EJB TestTimerServiceBean: [java:global/TestStartup/TestTimerServiceBean, java:global/TestStartup/TestTimerServiceBean!ejbBeans.TestTimerServiceBean]
2017-01-28T22:11:13.836+0100|Informazioni: EJB5181:Portable JNDI names for EJB TestSessionBeanSingleton: [java:global/TestStartup/TestSessionBeanSingleton!ejbBeans.TestSessionBeanSingleton, java:global/TestStartup/TestSessionBeanSingleton]
2017-01-28T22:11:13.840+0100|Informazioni: TestSessionBeanSingleton Constructor called
2017-01-28T22:11:13.869+0100|Informazioni: TestSessionBeanSingleton Constructor called
2017-01-28T22:11:13.873+0100|Informazioni: TestSessionBeanSingleton postconstruct called Sat Jan 28 22:11:13 CET 2017
2017-01-28T22:11:30.015+0100|Informazioni: TestTimerServiceBean autoScheduledTimedMethod called
2017-01-28T22:11:44.763+0100|Informazioni: TestSessionBeanStateless Constructor called
2017-01-28T22:11:44.765+0100|Informazioni: TestSessionBeanStateless postconstruct called
2017-01-28T22:11:44.766+0100|Informazioni: TestSessionBeanStateless method1 called: String = test Long = 25
2017-01-28T22:12:00.002+0100|Informazioni: TestTimerServiceBean autoScheduledTimedMethod called
2017-01-28T22:12:30.002+0100|Informazioni: TestTimerServiceBean autoScheduledTimedMethod called
2017-01-28T22:12:43.873+0100|Informazioni: TestSessionBeanSingleton postconstruct End after 1,5 min Sat Jan 28 22:12:43 CET 2017
2017-01-28T22:12:43.878+0100|Informazioni: CORE10010: Loading application TestStartup done in 109.016 ms
2017-01-28T22:12:43.882+0100|Informazioni: Oracle GlassFish Server 3.1.2.2 (5) startup time : Felix (3.797ms), startup services(110.692ms), total(114.489ms)
2017-01-28T22:12:47.603+0100|Informazioni: JMX005: JMXStartupService had Started JMXConnector on JMXService URL service:jmx:rmi://192.168.1.7:8686/jndi/rmi://192.168.1.7:8686/jmxrmi
2017-01-28T22:13:00.002+0100|Informazioni: TestTimerServiceBean autoScheduledTimedMethod called