使用@EJB时instanceof判断失效,求原因及松耦合解决方案
问题原因
- EJB代理生成规则限制:WebLogic为EJB生成的代理类仅实现被标注为EJB业务接口的接口。你的
CrudSessionLocal标注了@Local,属于合法的EJB本地业务接口;但ExceptionThrower未添加@Local或@Remote注解,不属于EJB业务接口范畴,因此容器生成的代理类CrudsTransactionSessionBean_d7q6e8_CrudSessionLocalImpl只会实现CrudSessionLocal,不会包含ExceptionThrower的接口定义。 - 注入对象为代理而非原始Bean实例:EJB容器注入的并非Bean类的直接实例,而是容器动态生成的代理对象。这个代理仅暴露业务接口声明的方法,即便Bean类实现了其他非业务接口,代理也不会继承这些接口的特性,导致
instanceof ExceptionThrower判断返回false。
保持松耦合的解决方案
以下方案均不依赖具体实现类,维持客户端与服务端的接口依赖:
方案一:合并业务接口(推荐)
让CrudSessionLocal继承ExceptionThrower,这样CrudSessionLocal作为标注了@Local的业务接口,其代理类会自动实现所有继承的接口方法,无需类型转换即可直接调用ExceptionThrower的方法:
修改interface模块的CrudSessionLocal:
@Local public interface CrudSessionLocal extends CRUDS, ExceptionThrower { // 无需新增方法,继承两个接口的方法即可 }
修改web-client模块的Servlet代码:
@EJB(beanName = "CrudsTransactionSessionBean") private CrudSessionLocal crudSessionLocal; protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 直接调用方法,无需类型转换 crudSessionLocal.setThrowException(throwException); }
该方案符合EJB设计规范,既保持松耦合,又避免类型转换问题,代码简洁易维护。
方案二:将ExceptionThrower声明为本地业务接口
给ExceptionThrower添加@Local注解,使其成为合法的EJB本地业务接口,之后可直接在Servlet中注入该接口的实例:
修改interface模块的ExceptionThrower:
@Local public interface ExceptionThrower { boolean isThrowException(); void setThrowException(boolean throwException); }
修改web-client模块的Servlet代码:
@EJB(beanName = "CrudsTransactionSessionBean") private CrudSessionLocal crudSessionLocal; @EJB(beanName = "CrudsTransactionSessionBean") private ExceptionThrower exceptionThrower; protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { exceptionThrower.setThrowException(throwException); }
注意:由于你的Bean是
@Stateless类型,两次注入的代理可能对应池中的不同实例。如果需要确保设置的属性作用在同一个Bean实例上,此方案不适用,优先选择方案一。
内容的提问来源于stack exchange,提问作者user2902165
相关产品推荐
相关产品推荐

