没有合适的资源?快使用搜索试试~ 我知道了~
Java面试题.pdf
1.该资源内容由用户上传,如若侵权请联系客服进行举报
2.虚拟产品一经售出概不退款(资源遇到问题,请及时私信上传者)
2.虚拟产品一经售出概不退款(资源遇到问题,请及时私信上传者)
版权申诉
0 下载量 40 浏览量
2021-11-13
00:38:52
上传
评论
收藏 79KB PDF 举报
温馨提示
试读
28页
Java面试题.pdf
资源推荐
资源详情
资源评论
1.Struts 中 Action 是线程安全的吗?如果不是, 请说出理由. 在 Struts 可以定义静态变量吗?
参考答案 :
Servlet 是在多线程环境下的。即可能有多个请求发给一个 servelt 实例,每个请求是一个线
程。
struts 下 的 action 也 类 似 , 同 样 在 多 线 程 环 境 下 。 可 以 参 考 struts user guide:
http://struts.apache.org/struts-action/userGuide/building_controller.html 中 的 Action Class
Design Guidelines 一节 : Write code for a multi-threaded environment - Our controller servlet
creates only one instance of your Action class, and uses this one instance to service all requests.
Thus, you need to write thread-safe Action classes. Follow the same guidelines you would use to
write thread-safe Servlets.
译:为多线程环境编写代码。 我们的 controller servlet 指挥创建你的 Action 类的一个实例, 用
此实例来服务所有的请求。因此,你必须编写线程安全的 Action 类。遵循与写线程安全的
servlet 同样的方针。
1.什么是线程安全的代码
在多线程环境下能正确执行的代码就是线程安全的。
安全的意思是能正确执行,否则后果是程序执行错误,可能出现各种异常情况。
2.如何编写线程安全的代码
很多书籍里都详细讲解了如何这方面的问题, 他们主要讲解的是如何同步线程对共享资源的
使用的问题。主要是对 synchronized 关键字的各种用法,以及锁的概念。
Java1.5 中也提供了如读写锁这类的工具类。这些都需要较高的技巧,而且相对难于调试。
但是,线程同步是不得以的方法 ,是比较复杂的 ,而且会带来性能的损失。等效的代码中,不
需要同步在编写容易度和性能上会更好些。
我这里强调的是什么代码是始终为线程安全的、是不需要同步的。如下 :
1)常量始终是线程安全的,因为只存在读操作。
2)对构造器的访问 (new 操作 )是线程安全的,因为每次都新建一个实例,不会访问共享的资
源。
3)最重要的是 :局部变量是线程安全的。因为每执行一个方法,都会在独立的空间创建局部
变量,它不是共享的资源。局部变量包括方法的参数变量。
struts user guide 里有:
Only Use Local Variables - The most important principle that aids in thread-safe coding is to use
only local variables, not instance variables , in your Action class.
译:只使用用局部变量。 --编写线程安全的代码最重要的原则就是,在 Action 类中只使用局
部变量,不使用实例变量。
总结:
在 Java的 Web 服务器环境下开发, 要注意线程安全的问题。 最简单的实现方式就是在 Servlet
和 Struts Action 里不要使用类变量、实例变量,但可以使用类常量和实例常量。
如果有这些变量,可以将它们转换为方法的参数传入,以消除它们。
注意一个容易混淆的地方:被 Servlet 或 Action 调用的类中 (如值对象、领域模型类 )中是否
可以安全的使用实例变量?如果你在每次方法调用时
新建一个对象, 再调用它们的方法, 则不存在同步问题 ---因为它们不是多个线程共享的资源,
只有共享的资源才需要同步 ---而 Servlet 和 Action 的实例对于多个线程是共享的。
换句话说, Servlet 和 Action 的实例会被多个线程同时调用,而过了这一层 ,如果在你自己的
代码中没有另外启动线程, 且每次调用后续业务对象时都是先新建一个实例再调用, 则都是
线程安全的。
2.你对 Spring 中的 IoC 有什么理解 ?Spring 实现 DI(Dependency Injection) 有几种方式 ?各有什
么优缺点 ? 参考答案 :
1、好莱坞原则 —— 不要打电话找我,我会打给你的。 IoC 将创建的职责从应用程序代码搬
到 了 框 架 中 。 Spring 对 Setter 注 入 和 构 造 方 法 注 入 提 供 支 持 。( 详 见
http://martinfowler.com/articles/injection.html , 以 及 http://www.redsaga.com/ spring_re ...
ctory-collaborators )
2、在一个面向对象的系统中,系统的各种功能是由许许多多的不同对象协作完成的。在这
种情况下, 各个对象内部是如何实现自己的对系统设计人员来讲就不那么重要了; 而各个对
象之间的协作关系则成为系统设计的关键。 小到不同类之间的通信, 大到各模块之间的交互,
在 系 统 设 计 之 初 都 是 要 着 重 考 虑 的 , 这 也 是 系 统 设 计 的 主 要 工 作 内 容 。( 详 见
http://deve.blogdriver.com/deve/415943.html )
Type1 接口注入
我们常常借助接口来将调用者与实现者分离。如 :
public class ClassA {
private InterfaceB clzB;
public doSomething() {
Ojbect obj =
Class.forName(Config.BImplementation).newInstance();
clzB = (InterfaceB)obj;
clzB.doIt();
}
……
} 上面的代码中, ClassA 依赖于 InterfaceB 的实现,如何获得 InterfaceB 实现类的实例?
传统的方法是在代码中创建 InterfaceB 实现类的实例, 并将起赋予 clzB 。而这样一来, ClassA
在编译期即依赖于 InterfaceB 的实现。为了将调用者与实现者在编译期分离,于是有了上面
的代码,我们根据预先在配置文件中设定的实现类的类名 (Config.BImplementation) ,动态加
载实现类,并通过 InterfaceB 强制转型后为 ClassA 所用。这就是接口注入的一个最原始的
雏形。而对于一个 Type1 型 IOC 容器而言,加载接口实现并创建其实例的工作由容器完成。
如下面这个类 :
public class ClassA {
private InterfaceB clzB;
public Object doSomething(InterfaceB b) {
clzB = b;
return clzB.doIt();
}
……
} 在运行期, InterfaceB 实例将由容器提供。
Type1 型 IOC 发展较早(有意或无意) ,在实际中得到了普遍应用,即使在 IOC 的概念尚未
确立时,这样的
方法也已经频繁出现在我们的代码中。
下面的代码大家应该非常熟悉:
public class MyServlet extends HttpServlet {
public void doGet(
HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
……
}
} 这也是一个 Type1 型注入, HttpServletRequest 和 HttpServletResponse 实例由 Servlet
Container 在运行期动态注入。另, Apache Avalon 是一个较为典型的 Type1 型 IOC 容器。
Type2 设值注入
在各种类型的依赖注入模式中, 设值注入模式在实际开发中得到了最广泛的应用 (其中很大
一部分得
力于 Spring 框架的影响) 。
在笔者看来,基于设置模式的依赖注入机制更加直观、也更加自然。 Quick Start 中的示例,
就是典
型的设置注入,即通过类的 setter 方法完成依赖关系的设置。
Type3 构造子注入
public class DIByConstructor {
private final DataSource dataSource;
private final String message;
public DIByConstructor(DataSource ds, String msg) {
this.dataSource = ds;
this.message = msg;
}
……
} 构造子注入,即通过构造函数完成依赖关系的设定,如:
可以看到, 在 Type3 类型的依赖注入机制中, 依赖关系是通过类构造函数建立, 容器通过调
用类的构
造方法,将其所需的依赖关系注入其中。
PicoContainer(另一种实现了依赖注入模式的轻量级容器)首先实现了 Type3 类型的依赖注
入模式。
color=red] 几种依赖注入模式的对比总结 [/color]
接口注入模式因为历史较为悠久, 在很多容器中都已经得到应用。 但由于其在灵活性、 易用
性上不如
其他两种注入模式,因而在 IOC 的专题世界内并不被看好。
Type2 和 Type3 型的依赖注入实现则是目前主流的 IOC 实现模式。这两种实现方式各有特点,
也各具
优势(一句经典废话 J)。
Type2 设值注入的优势
1. 对于习惯了传统 JavaBean开发的程序员而言, 通过 setter 方法设定依赖关系显得更加直
观,更加自然。
2. 如果依赖关系(或继承关系)较为复杂,那么 Type3 模式的构造函数也会相当庞大(我
们需
要在构造函数中设定所有依赖关系) ,此时 Type2 模式往往更为简洁。
3. 对于某些第三方类库而言, 可能要求我们的组件必须提供一个默认的构造函数 (如 Struts
中的 Action ),此时 Type3 类型的依赖注入机制就体现出其局限性,难以完成我们期望的功
能。
Type3 构造子注入的优势:
1. “在构造期即创建一个完整、合法的对象 ”,对于这条 Java 设计原则, Type3 无疑是最好
的
响应者。
2. 避免了繁琐的 setter 方法的编写,所有依赖关系均在构造函数中设定,依赖关系集中呈
现,
更加易读。
3. 由于没有 setter 方法,依赖关系在构造时由容器一次性设定,因此组件在被创建之后即
处于
相对 “不变 ”的稳定状态,无需担心上层代码在调用过程中执行 setter 方法对组件依赖关系
产生破坏,特别是对于 Singleton 模式的组件而言,这可能对整个系统产生重大的影响。
4. 同样, 由于关联关系仅在构造函数中表达, 只有组件创建者需要关心组件内部的依赖关
系。
对调用者而言,组件中的依赖关系处于黑盒之中。对上层屏蔽不必要的信息,也为系统的
层次清晰性提供了保证。
5. 通过构造子注入, 意味着我们可以在构造函数中决定依赖关系的注入顺序, 对于一个大
量
依赖外部服务的组件而言,依赖关系的获得顺序可能非常重要,比如某个依赖关系注入的
先决条件是组件的 DataSource 及相关资源已经被设定。
3.在 Spring 中, Bean 有几种作用域 ? 参考答案 :
Spring 中 bean 的作用域
如何使用 spring 的作用域:
<bean id="role" class=" spring.chapter2.maryGame.Role" scope="singleton"/>
这里的 scope 就是用来配置 spring bean 的作用域,它标识 bean 的作用域。
在 spring2.0 之前 bean 只有 2 种作用域即: singleton(单例 )、non-singleton(也称 prototype ),
Spring2.0 以后,增加了 session、request、global session 三种专用于 Web 应用程序上下文的
Bean。因此,默认情况下 Spring2.0 现在有五种类型的 Bean。当然, Spring2.0 对 Bean 的
类型的设计进行了重构,并设计出灵活的 Bean 类型支持,理论上可以有无数多种类型的
Bean,用户可以根据自己的需要,增加新的 Bean 类型,满足实际应用需求。
1、singleton 作用域
当一个 bean的作用域设置为 singleton, 那么 Spring IOC 容器中只会存在一个共享的 bean 实
例,并且所有对 bean 的请求, 只要 id 与该 bean定义相匹配, 则只会返回 bean 的同一实例。
换言之,当把一个 bean 定义设置为 singleton 作用域时, Spring IOC 容器只会创建该 bean
定义的唯一实例。这个单一实例会被存储到单例缓存( singleton cache)中,并且所有针对
该 bean 的后续请求和引用都将返回被缓存的对象实例,这里要注意的是 singleton 作用域和
GOF 设计模式中的单例是完全不同的, 单例设计模式表示一个 ClassLoader 中只有一个 class
存在,而这里的 singleton 则表示一个容器对应一个 bean,也就是说当一个 bean 被标识为
singleton 时候, spring 的 IOC 容器中只会存在一个该 bean。
配置实例:
<bean id="role" class=" spring.chapter2.maryGame.Role" scope="singleton"/>
或者
<bean id="role" class=" spring.chapter2.maryGame.Role" singleton="true"/>
2、prototype
prototype 作用域部署的 bean,每一次请求(将其注入到另一个 bean 中,或者以程序的
方式调用容器的 getBean()方法)都会产生一个新的 bean 实例,相当一个 new 的操作,对于
prototype 作用域的 bean,有一点非常重要,那就是 Spring 不能对一个 prototype bean 的整
个生命周期负责,容器在初始化、配置、装饰或者是装配完一个 prototype 实例后,将它交
给客户端,随后就对该 prototype 实例不闻不问了。不管何种作用域,容器都会调用所有对
象的初始化生命周期回调方法,而对 prototype 而言,任何配置好的析构生命周期回调方法
都将不会被调用。 清除 prototype 作用域的对象并释放任何 prototype bean 所持有的昂贵资源,
都是客户端代码的职责。 (让 Spring 容器释放被 singleton 作用域 bean 占用资源的一种可行
方式是,通过使用 bean的后置处理器,该处理器持有要被清除的 bean 的引用。)
配置实例:
<bean id="role" class=" spring.chapter2.maryGame.Role" scope="prototype"/>
或者
<beanid="role" class=" spring.chapter2.maryGame.Role" singleton="false"/>
3、request
request 表示该针对每一次 HTTP 请求都会产生一个新的 bean,同时该 bean仅在当前 HTTP
request 内有效。
request、session、global session 使用的时候首先要在 web.xml 中做如下配置:
如果你使用的是 Servlet 2.4 及以上的 web 容器,那么你仅需要在 web 应用的 XML 声明
文件 web.xml 中增加下述 ContextListener 即可:
<web-app>
...
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
...
</web-app>
,如果是 Servlet2.4 以前的 web 容器 ,那么你要使用一个 javax.servlet.Filter 的实现:
<web-app>
...
<filter>
<filter-name>requestContextFilter</filter-name>
<filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>requestContextFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
...
</web-app>
接着既可以配置 bean 的作用域了:
<bean id="role" class=" spring.chapter2.maryGame.Role" scope="request"/>
4、session
session作用域表示该针对每一次 HTTP 请求都会产生一个新的 bean,同时该 bean 仅在当
剩余27页未读,继续阅读
资源评论
BlueWatergg
- 粉丝: 3
- 资源: 11万+
下载权益
C知道特权
VIP文章
课程特权
开通VIP
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功