Java程序员面试题集合(10)

90、说说在 weblogic 中开发消息 Bean 时的 persistent 与 non-persisten 的差别
persistent 方式的 MDB 可以保证消息传递的可靠性,也就是如果 EJB 容器出现问题而 JMS 服务器依然会将消息在此 MDB 可用的时候发送过来,而 non-persistent 方式的消息将被丢弃。既然没有标准答案,就根据自己的所了解的,补充修正一下好了
91、Servlet 执行时一般实现哪几个方法?
public void init(ServletConfig config)
public ServletConfig getServletConfig()
public String getServletInfo()
public void service(ServletRequest request,ServletResponse response)
public void destroy()
init ()方法在 servlet 的生命周期中仅执行一次,在服务器装载 servlet 时执行。缺省的 init()方法通常是符合要求的,不过也可以根据需要进行 override,比如管理服务器端资源,一次性装入 GIF 图像,初始化数据库连接等,缺省的 inti()方法设置了 servlet 的初始化参数,并用它的 ServeltConfig 对象参数来启动配置,所以覆盖 init()方法时,应调用 super.init()以确保仍然执行这些任务。
service ()方法是 servlet 的核心,在调用 service()方法之前,应确保已完成 init()方法。对于HttpServlet,每当客户请求一个 HttpServlet 对象,该对象的 service()方法就要被调用,HttpServlet 缺省的 service()方法的服务功能就是调用与 HTTP 请求的方法相应的 do 功能,doPost()和 doGet(),所以对于 HttpServlet,一般都是重写 doPost()和 doGet() 方法。
destroy()方法在 servlet 的生命周期中也仅执行一次,即在服务器停止卸载 servlet 时执行,把servlet 作为服务器进程的一部分关闭。缺省的 destroy()方法通常是符合要求的,但也可以override,比如在卸载 servlet 时将统计数字保存在文件中,或是关闭数据库连接。
getServletConfig() 方法返回一个servletConfig对象,该对象用来返回初始化参数和servletContext。servletContext 接口提供有关 servlet 的环境信息。
getServletInfo()方法提供有关 servlet 的信息,如作者,版本,版权。
92、j2ee 常用的设计模式?说明工厂模式。
Java 中的 23 种设计模式:
Factory(工厂模式), Builder(建造模式), Factory Method(工厂方法模式),Prototype(原始模型模式),Singleton(单例模式), Facade(门面模式),Adapter(适配器模式), Bridge(桥梁模式), Composite(合成模式),Decorator(装饰模式), Flyweight(享元模式), Proxy(代理模式),Command(命令模式), Interpreter(解释器模式), Visitor(访问者模式),Iterator(迭代子模式), Mediator(调停者模式), Memento(备忘录模式),Observer(观察者模式), State(状态模式), Strategy(策略模式),Template Method(模板方法模式), Chain Of Responsibleity(责任链模式)
工厂模式:工厂模式是一种经常被使用到的模式,根据工厂模式实现的类可以根据提供的数据生成一组类中某一个类的实例,通常这一组类有一个公共的抽象父类并且实现了相同的方法,但是这些方法针对不同的数据进行了不同的操作。首先需要定义一个基类,该类的子类通过不同的方法实现了基类中的方法。然后需要定义一个工厂类,工厂类可以根据条件生成不同的子类实例。当得到子类的实例后,开发人员可以调用基类中的方法而不必考虑到底返回的是哪一个子类的实例。
93、EJB 需直接实现它的业务接口或 Home 接口吗,请简述理由。
远程接口和 Home 接口不需要直接实现,他们的实现代码是由服务器产生的,程序运行中对 应实现类会作为对应接口类型的实例被使用。
其实一直都不是很明白 EJB 的 remote 接口,home 接口,Bean 类究竟是如何使用的,或许应该进一步了解 EJB 的原理吧,查到了一个原创文章,那就说说 EJB 调用的原理吧。其实在这个问题上,最需要理解的是 RMI 机制原理。
一个远程对象至少要包括 4 个 class 文件:远程对象、远程对象接口、实现远程接口的对象的 stub、对象的 skeleton。
而在 EJB 中则至少要包括 10 个 class:
Bean 类,特定 App Server 的 Bean 实现类Bean 的 remote 接口,特定 App Server 的 remote 接口实现类,特定 App Server 的 remote 接口的实现类的 stub 类和 skeleton 类。
Bean 的 home 接口,特定 App Server 的 home 接口实现类,特定 App Server 的 home 接口的实现类的 stub 类和 skeleton 类。
和 RMI 不同的是,EJB 中这 10 个 class 真正需要用户写的只有 3 个,Bean 类,remote 接口,home 接口,其它的 7 个究竟怎么生成,被打包在哪里,是否需要更多的类文件,否根据不同的 App Server 表现出较大的差异。
Weblogic:
home 接口和 remote 接口的 weblogic 的实现类的 stub 类和 skeleton 类是在 EJB 被部署到weblogic 的时候,由 weblogic 动态生成 stub 类和 skeleton 类的字节码,所以看不到这 4 个类文件。
对于一次客户端远程调用 EJB,要经过两个远程对象的多次 RMI 循环。首先是通过 JNDI查找 Home 接口,获得 Home 接口的实现类,这个过程其实相当复杂,首先是找到 Home 接口的 Weblogic 实现类,然后创建一个 Home 接口的 Weblogic 实现类的 stub 类的对象实例,将它序列化传送给客户端(注意 stub 类的实例是在第 1 次 RMI 循环中,由服务器动态发送给客户端的,因此不需要客户端保存 Home 接口的 Weblogic 实现类的 stub 类),最后客户端获得该 stub 类的对象实例(普通的 RMI 需要在客户端保存 stub 类,而 EJB 不需要,因为服务器会把 stub 类的对象实例发送给客户端)。
客户端拿到服务器给它的 Home 接口的 Weblogic 实现类的 stub 类对象实例以后,调用 stub类的 create 方法, (在代码上就是 home.create(),但是后台要做很多事情),于是经过第 2 次RMI 循环,在服务器端,Home 接口的 Weblogic 实现类的 skeleton 类收到 stub 类的调用信息后,由它再去调用 Home 接口的 Weblogic 实现类的 create 方法。
在服务端, Home 接口的 Weblogic 实现类的 create 方法再去调用 Bean 类的 Weblogic 实现类的 ejbCreate 方法,在服务端创建或者分配一个 EJB 实例,然后将这个 EJB 实例的远程接口的 Weblogic 实现类的 stub 类对象实例序列化发送给客户端。
客户端收到 remote 接口的 Weblogic 实现类的 stub 类的对象实例,对该对象实例的方法调用(在客户端代码中实际上就是对 remote 接口的调用),将传送给服务器端 remote 接口的Weblogic 实现类的 skeleton 类对象,而 skeleton 类对象再调用相应的 remote 接口的 Weblogic实现类,然后 remote 接口的 Weblogic 实现类再去调用 Bean 类的 Weblogic 实现类,如此就完成一次 EJB 对象的远程调用。
先拿普通 RMI 来说,有 4 个 class,分别是远程对象,对象的接口,对象的 stub 类和 skeleton类。而对象本身和对象的 stub 类同时都实现了接口类。而我们在客户端代码调用远程对象的时候,虽然在代码中操纵接口,实质上是在操纵 stub 类,例如:
接口类:Hello
远程对象:Hello_S
erver
stub 类:Hello_Stub
skeleton 类:Hello_Skeleton
客户端代码要这样写:
Hello h = new Hello_Stub();
h.getString();
我们不会这些写:
Hello_Stub h = new Hello_Stub();
h.getString();
因为使用接口适用性更广,就算更换了接口实现类,也不需要更改代码。因此客户端需要Hello.class 和 Hello_Stub.class 这两个文件。但是对于 EJB 来说,就不需要 Hello_Stub.class,因为服务器会发送给它,但是 Hello.class 文件客户端是省不了的,必须有。表面上我们的客户端代码在操纵 Hello,但别忘记了 Hello只是一个接口,抽象的,实质上是在操纵 Hello_Stub。
拿 Weblogic 上的 EJB 举例子,10 个 class 分别是:
Bean 类:HelloBean (用户编写)
Bean 类的 Weblogic 实现类:HelloBean_Impl (EJBC 生成)
Home 接口:HelloHome (用户编写)
Home 接口的 Weblogic 实现类 HelloBean_HomeImpl(EJBC 生成)
Home 接口的 Weblogic 实现类的 stub 类 HelloBean_HomeImpl_WLStub(部署的时候动态生成字节码)
Home 接口的 Weblogic 实现类的 skeleton 类 HelloBean_HomeImpl_WLSkeleton(部署的时候动态生成字节码)
Remote 接口: Hello (用户编写)
Remote 接口的 Weblogic 实现类 HelloBean_EOImpl(EJBC 生成)
Remote 接口的 Weblogic 实现类的 stub 类 HelloBean_EOImpl_WLStub(部署的时候动态生成字节码)
Remote 接口的 Weblogic 实现类的 skeleton 类 HelloBean_EOImpl_WLSkeleton(部署的时候动态生成字节码)
客户端只需要 Hello.class 和 HelloHome.class 这两个文件。
HelloHome home=(Home)PortableRemoteObject.narrow(ctx.lookup("Hello"),HelloHome.class);
这一行代码是从 JNDI 获得 Home 接口,但是请记住!接口是抽象的,那么 home 这个对象到底是什么类的对象实例呢?很简单,用 toString()输出看一下就明白了,下面一行是输出结果:
HelloBean_HomeImpl_WLStub@18c458
这表明home这个通过从服务器的JNDI树上查找获得的对象实际上是HelloBean_HomeImpl_WLStub 类的一个实例。
接下来客户端代码:
Hello h = home.create()
同样 Hello 只是一个抽象的接口,那么 h 对象是什么东西呢?打印一下:
HelloBean_EOImpl_WLStub@8fa0d1
原来是 HelloBean_EOImpl_WLStub 的一个对象实例。
用这个例子来简述一遍 EJB 调用过程:
首先客户端JNDI查询,服务端JNDI树上Hello这个名字实际上绑定的对象是HelloBean_HomeImpl_WLStub,所以服务端将创建 HelloBean_HomeImpl_WLStub 的一个对象实例,序列化返回给客户端。于是客户端得到 home 对象,表面上是得到 HelloHome 接口的实例,实际上是进行了一次远程调用得到了HelloBean_HomeImpl_WLStub 类的对象实例,别忘记了HelloBean_HomeImpl_WLStub 也实现了 HelloHome 接口。
然后 home.create()实质上就是 HelloBean_HomeImpl_WLStub.create(),该方法将发送信息给HelloBean_HomeImpl_WLSkeleton,而 HelloBean_HomeImpl_WLSkeleton 接受到信息后,再去调用 HelloBean_HomeImpl 的 create 方法,至此完成第 1 次完整的 RMI 循环。
注意在这次 RMI 循环过程中,远程对象是 HelloBean_HomeImpl,远程对象的接口是HelloHome , 对 象 的 stub 是 HelloBean_HomeImpl_WLStub , 对 象 的 skeleton 是HelloBean_HomeImpl_WLSkeleton。然后 HelloBean_HomeImpl 再去调用 HelloBean_Impl 的 ejbCreate 方法,而 HelloBean_Impl的ejbCreate方法将负责创建或者分配一个Bean实例,并且创建一个HelloBean_EOImpl_WLStub 的对象实例。
这一步比较有趣的是,在前一步 RMI 循环中,远程对象 HelloBean_HomeImpl 在客户端有一个代理类 HelloBean_HomeImpl_WLStub,但在这一步, HelloBean_HomeImpl 自己却充当了 HelloBean_Impl 的代理类,只不过 HelloBean_HomeImpl 不在客户端,而是在服务端,因此不进行 RMI。
然后 HelloBean_EOImpl_WLStub 的对象实例序列化返回给客户端,这一步也很有趣,上次RMI 过程,主角是 HelloBean_HomeImpl 和它的代理类 HelloBean_HomeImpl_WLStub,但这这一次换成了 HelloBean_EOImpl 和它的代理类 HelloBean_EOImpl_WLStub 来玩了。
Hello h = home.create();h.helloWorld();假设 Hello 接口有一个 helloWorld 远程方法,那么表面上是在调用 Hello 接口的 helloWorld方法,实际上是在调用 HelloBean_EOImpl_WLStub 的 helloWorld 方法。
然后HelloBean_EOImpl_WLStub的helloWorld方法将发送信息给服务器上的HelloBean_EOImpl_WLSkeleton,而 HelloBean_EOImpl_WLSkeleton 收到信息以后,再去调用 HelloBean_EOImpl 的 helloWorld 方法。至此,完成第 2 次完整的 RMI 循环过程。
在刚才HelloBean_EOImpl是作为远程对象被调用的,它的代理类是HelloBean_EOImpl_WLStub,但现在 HelloBean_EOImpl 要作为 HelloBean_Impl 的代理类了。
现在 HelloBean_EOImpl 去调用 HelloBean_Impl 的 helloWorld 方法。注意!HelloBean_Impl继承了 HelloBean,而 HelloBean 中的 helloWorld 方法是我们亲自编写的代码,现在终于调用到了我们编写的代码了!
至此,一次EJB调用过程终于完成。在整个过程中,服务端主要要调用的类是HelloBean_Impl ,HelloBean_EOImpl ,HelloBean_HomeImpl , HelloBean_HomeImpl_WLSkeleton ,HelloBean_EOImpl_WLSkeleton 。 客户端主要调用的类是HelloBean_HomeImpl_WLStub, HelloBean_EOImpl_WLStub,这两个类在客户端代码中并不会直接出现,出现在代码中的类是他们的接口 HelloHome 和 Hello,因此客户端需要这两个接口文件,而 Stub 是服务器传送给他们的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值