Maven… 它是什么?





1.1. Maven… 它是什么?


如何回答这个问题要看你怎么看这个问题。 绝大部分Maven用户都称Maven是一个”构建工具”:一个用来把源代码构建成可发布的构件的工具。 构建工程师和项目经理会说Maven是一个更复杂的东西:一个项目管理工具。那么区别是什么? 像Ant这样的构建工具仅仅是关注预处理,编译,打包,测试和分发。像 Maven 这样的一个项目管理工具提供了构建工具所提供功能的超集。 除了提供构建的功能,Maven还可以生成报告,生成Web站点,并且帮助推动工作团 队成员间的交流。


一个更正式的 Apache Maven 的定义: Maven是一个项目管理工具,它包含了一个项目对象模型 (Project Object Model),一组标准集合,一个项目生命周期(Project Lifecycle),一个依赖管理系统(Dependency Management System),和用来运行定义在生命周期阶段(phase)中插件(plugin)目标(goal)的逻辑。 当你使用Maven的时候,你用一个明确定义的项目对象模型来描述你的项目,然后 Maven 可以应用横切的逻辑,这些逻辑来自一组共享的(或者自定义的)插件。


别让Maven是一个”项目管理”工具的事实吓跑你。如果你只是在找一个构建工具,Maven能做这个工作。 事实上,本书的一些章节将会涉及使用Maven来构建和分发你的项目。






1.2. 约定优于配置(Convention Over Configuration)


约定优于配置是一个简单的概念。 系统,类库,框架应该假定合理的默认值,而非要求提供不必要的配置。 流行的框架如 Ruby on RailsEJB3 已经开始坚持这些原则,以对像原始的 EJB 2.1 规范那样的框架的配置复杂度做出反应。 一个约定优于配置的例子就像 EJB3 持久化,将一个 特殊的Bean持久化,你所需要做的只是将这个类标注为 @Entity 。 框架将会假定表名和列名是基于类名是属性名。 系统也提供了一些钩子,当有需要的时候你可以重写这些名字,但是,在大部分情况下,你会发现使用框架提供的默认值会让你的项目运行的更快。


Maven通过给项目提供明智的默认行为来融合这个概念。 在没有自定义的情况下,源代码假定是在 ${basedir}/src/main/java,资源文件假定是在 ${basedir}/src/main/resources 。测试代码假定是在 ${basedir}/src/test 。项目假定会产生一个 JAR 文件。Maven 假定你想要把编译好的字节码放到 ${basedir}/target/classes 并且在 ${basedir}/target 创建一个可分发的 JAR 文件。 虽然这看起来无关紧要,但是想想大部分基于 Ant 的构建必须为每个子项目定义这些目录。 Maven 对约定优于配置的应用不仅仅是简单的目录位置,Maven 的核心插件使用了一组通用的约定,以用来编译源代码,打包可分发的构件,生成 web 站点,还有许多其他的过程。 Maven 的力量来自它的”武断”,它有一个定义好的生命周期和一组知道如何构建和装配软件的通用插件。如果你遵循这些约定,Maven 只需要几乎为零的工作——仅仅是将你的源代码放到正确的目录,Maven 将会帮你处理剩下的事情。


使用“遵循约定优于配置”系统的一个副作用是用户可能会觉得他们被强迫使用一种特殊的方法。 当然 Maven 有一些核心观点不应该被怀疑,但是其实很多默认行为还是可配置的。 例如项目源码的资源文件的位置可以被自定义,JAR 文件的名字可以被自定义,在开发自定义插件的时候,几乎任何行为可以被裁剪以满足你特定的环境需求。 如果你不想遵循约定,Maven 也会允许你自定义默认值来适应你的需求。






1.3. 一个一般的接口


在 Maven 为构建软件提供一个一般的接口之前,每个单独的项目都专门有人来管理一个完全自定义的构建系统。开发人员必须在开发软件之外去学习每个他们要参与的新项目的构建系统的特点。 在2001年,构建一个项目如 Turbine 和构建另外一个项目如 Tomcat ,两者方法是完全不同的。如果一个新的进行静态源码分析的源码分析工具面世了,或者如果有人开发了一个新的单元测试框架,每个人都必须放下手头的工作去想办法使这个新东西适应每个项目的自定义构建环境。 如何运行单元测试?世界上有一千种不同的答案。构建环境由无数无休止的关于工具和构建程序的争论所描述刻画。Maven 之前的时代是低效率的时代,是“构建工程师”的时代。


现在,大部分开源开发者已经或者正在使用 Maven 来管理他们新的软件项目。这种转变不仅仅是开发人员从一种构建工具转移到另外一种构建工具,更是开发人员开始为他们的项目采用一种一般的接口。随着软件系统变得越来越模块化,构建系统变得更复杂,而项目的数量更是如火箭般飞速上升。在 Maven 之前,当你想要从 Subversion 签出一个项目如 Apache ActiveMQApache ServiceMix ,然后从源码进行构建,你需要为每个项目留出一个小时来理解给它的构建系统。这个项目需要构建什么?需要现在什么类库?把类库放哪里?构建中我该运行什么目标?最好的情况下,理解一个新项目的构建需要几分钟,最坏的情况下(例如 Jakarta 项目的旧的 Servlet API 实现),一个项目的构建特别的困难,以至于花了几个小时以后,新的贡献者也只能编辑源码和编译项目。现在,你只要签出源码,然后运行: mvn install 。虽然 Maven 有很多优点,包括依赖管理和通过插件重用一般的构建逻辑,但它成功的最核心原因是它定义了构建软件的一般的接口。每当你看到一个使用 Maven 的项目如 Apache Wicket ,你就可以假设你能签出它的源码然后使用 mvn install 构建它,没什么好争论的。你知道点火开关在哪里,你知道油门在右边,刹车在左边。






1.4. 基于Maven插件的全局性重用


Maven 的核心其实不做什么实际的事情,除了解析一些 XML 文档,管理生命周期与插件之外,它什么也不懂。Maven 被设计成将主要的职责委派给一组 Maven 插件,这些插件可以影响 Maven 生命周期,提供对目标的访问。绝大多数 Maven 的动作发生于 Maven 插件的目标,如编译源码,打包二进制代码,发布站点和其它构建任务。你从 Apache 下载的 Maven 不知道如何打包 WAR 文件,也不知道如何运行单元测试,Maven 大部分的智能是由插件实现的,而插件从 Maven 仓库获得。事实上,第一次你用全新的 Maven 安装运行诸如 mvn install 命令的时候,它会从中央 Maven 仓库下载大部分核心 Maven 插件。这不仅仅是一个最小化 Maven 分发包大小的技巧,这种方式更能让你升级插件以给你项目的构建提高能力。Maven 从远程仓库获取依赖和插件的这一事实允许了构建逻辑的全局性重用。


Maven Surefire 插件是负责运行单元测试的插件。从版本 1.0 发展到目前广泛使用的在 JUnit 基础上增加了 TestNG 测试框架支持的版本。这种发展并没有破坏向后兼容性,如果你使用之前 Surefire 插件编译运行你的 JUnit 3 单元测试,然后你升级到了最新版本的 Surefire 插件,你的测试仍然能成功运行。但是,我们又获得了新的功能,如果你想使用 TestNG 运行单元测试,那么感谢 Surefire 插件的维护者,你已经可以使用 TestNG 了。你也能运行支持注解的 JUnit 4 单元测试。不用升级 Maven 安装或者新装任何软件,你就能获得这些功能。更重要的是,除了 POM 中一个插件的版本号,你不需要更改你项目的任何东西。


这种机制不仅仅适用于 Surefire 插件,项目使用 Compiler 插件进行编译,通过 Jar 插件变成 JAR 文件,还有一些插件生成报告,运行 JRuby 和 Groovy 的代码,以及一些用来向远程服务器发布站点的插件。Maven 将一般的构建任务抽象成插件,同时这些插件得到了很好的维护以及全局的共享,你不需要从头开始自定义你项目的构建系统然后提供支持。你完全可以从 Maven 插件获益,这些插件有人维护,可以从远程仓库下载到。这就是基于 Maven 插件的全局性重用。






1.5. 一个“项目”的概念模型


Maven 维护了一个项目的模型,你不仅仅需要把源码编译成字节码,你还需要开发软件项目的描述信息,为项目指定一组唯一的坐标。你要描述项目的的属性。项目的许可证是什么?谁开发这个项目,为这个项目做贡献?这个项目依赖于其它什么项目没有?Maven不仅仅是一个“构建工具”,它不仅仅是在类似于 make 和 Ant 的工具的基础上的改进,它是包含了一组关于软件项目和软件开发的语义规则的平台。这个基于每一个项目定义的模型实现了如下特征:




依赖管理


由于项目是根据一个包含组标识符,构件标识符和版本的唯一的坐标定义的。项目间可以使用这些坐标来声明依赖。


远程仓库


和项目依赖相关的,我们可以使用定义在项目对象模型(POM)中的坐标来创建 Maven 构件的仓库。


全局性构建逻辑重用


插件被编写成和项目模型对象(POM)一起工作,它们没有被设计成操作某一个已知位置的特定文件。一切都被抽象到模型中,插件配置和自定义行为都在模型中进行。


工具可移植性/集成


像 Eclipse,NetBeans,和 InteliJ 这样的工具现在有共同的地方来找到项目的信息。在 Maven 出现之前,每个 IDE 都有不同的方法来存储实际上是自定义项目对象模型(POM)的信息。Maven 标准化了这种描述,而虽然每个 IDE 仍然继续维护它的自定义项目文件,但这些文件现在可以很容易的由模型生成。


便于搜索和过滤构件


像 Nexus 这样的工具允许你使用存储在 POM 中的信息对仓库中的内容进行索引和搜索。


Maven 为软件项目的语义一致性描述的开端提供了一个基础。






1.6. Maven是Ant的另一种选择么?


当然,Maven 是 Ant 的另一种选择,但是 Apache Ant 继续是一个伟大的,被广泛使用的工具。它已经是多年以来 Java 构建的统治者,而你很容易的在你项目的 Maven 构建中集成 Ant 构建脚本。这是 Maven 项目一种很常见的使用模式。而另一方面,随着越来越多的开源项目转移到 Maven 用它作为项目管理平台,开发人员开始意识到 Maven 不仅仅简化了构建管理任务,它也帮助鼓励开发人员的软件项目使用通用的接口。Maven 不仅仅是一个工具,它更是一个平台,当你只是将 Maven 考虑成 Ant 的另一种选择的时候,你是在比较苹果和橘子。“Maven”包含了很多构建工具以外的东西。


有一个核心观点使得所有的关于 Maven 和. Ant, Maven 和 Buildr, Maven 和 Grandle 的争论变得无关紧要。Maven并不是完全根据你构建系统的机制来定义的,它不是为你构建的不同任务编写脚本,它提倡一组标注,一个一般的接口,一个生命周期,一个标准的仓库格式,一个标准的目录布局,等等。它当然也不太在意 POM 的格式正好是 XML 还是 YAML 还是 Ruby。它比这些大得多,Maven 涉及的比构建工具本身多得多。当本书讨论 Maven 的时候,它也设计到支持 Maven 的软件,系统和标准。Buildr,Ivy,Gradle,所有这些工具都和 Maven 帮助创建的仓库格式交互,而你可以很容易的使用如 Nexus 这样的工具来支持一个完全由 Buildr 编写的构建。Nexus 将在本书后面介绍。


虽然 Maven 是很多类似工具的另一个选择?但社区需要向前发展,就要看清楚技术是资本经济中不友好的竞争者之间持续的、零和的游戏。这可能是大企业之前相互关联的方式,但是和开源社区的工作方式没太大关系。“谁是胜利者?Ant 还是 Maven”这个大标题没什么建设性意义。如果你非要我们来回答这个问题,我们会很明确的说作为构建的基本技术,Maven 是 Ant 的更好选择;同时,Maven 的边界在持续的移动,Maven 的社区也在持续的是试图找到新的方法,使其更通用,互操作性更好,更易协同工作。Maven 的核心财产是声明性构建,依赖管理,仓库管理,基于插件的高度和重用,但是当前,和开源社区相互协作以降低”企业级构建“的低效率这个目标来比,这些想法的特定实现没那么重要。






1.7. 比较Maven和Ant


虽然上一节应该已经让你确信本书的作者没有兴趣挑起 Apache Ant 和 Apache Maven 之间的争执,但是我们认识到许多组织必须在 Apache Ant 和 Apache Maven 之间做一个选择。本节我们对比一下这两个工具。


Ant 在构建过程方面十分优秀,它是一个基于任务和依赖的构建系统。每个任务包含一组由 XML 编码的指令。有 copy 任务和 javac 任务,以及 jar 任务。在你使用 Ant 的时候,你为 Ant 提供特定的指令以编译和打包你的输出。看下面的例子,一个简单的 build.xml 文件:



Example 1.1. 一个简单的 Ant build.xml 文件


<project name=“my-project” default=“dist” basedir=“.”>
<description>
simple example build file
</description>
<!– set global properties for this build —>
<property name=“src” location=“src/main/java”/>
<property name=“build” location=“target/classes”/>
<property name=“dist” location=“target”/>

<target name=“init”>
<!– Create the time stamp —>
<tstamp/>
<!– Create the build directory structure used by compile —>
<mkdir dir=“${build}”/>
</target>

<target name=“compile” depends=“init”
description=“compile the source “ >
<!– Compile the java code from ${src} into ${build} —>
<javac srcdir=“${src}” destdir=“${build}”/>
</target>

<target name=“dist” depends=“compile”
description=“generate the distribution” >
<!– Create the distribution directory —>
<mkdir dir=“${dist}/lib”/>

<!– Put everything in ${build} into the MyProject-${DSTAMP}.jar file —>
<jar jarfile=“${dist}/lib/MyProject-${DSTAMP}.jar” basedir=“${build}”/>
</target>

<target name=“clean”
description=“clean up” >
<!– Delete the ${build} and ${dist} directory trees —>
<delete dir=“${build}”/>
<delete dir=“${dist}”/>
</target>
</project>



在这个简单的 Ant 例子中,你能看到,你需要明确的告诉 Ant 你想让它做什么。有一个包含 javac 任务的编译目标用来将 src/main/java 的源码编译至 target/classes 目录。你必须明确告诉 Ant 你的源码在哪里,结果字节码你想存储在哪里,如何将这些字节码打包成 JAR 文件。虽然最近有些进展以帮助 Ant 减少程序,但一个开发者对 Ant 的感受是用 XML 编写程序语言。


用 Maven 样例与之前的 Ant 样例做个比较。在 Maven 中,要从 Java 源码创建一个 JAR 文件,你只需要创建一个简单的 pom.xml,将你的源码放在 ${basedir}/src/main/java ,然后从命令行运行 mvn install。下面的样例 Maven pom.xml 文件能完成和之前 Ant 样例所做的同样的事情。



Example 1.2. 一个简单的 Maven pom.xml


<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.sonatype.maven</groupId>
<artifactId>my-project</artifactId>
<version>1.0</version>
</project>


这就是你 pom.xml 的全部。从命令行运行 mvn install 会处理资源文件,编译源代码,运行单元测试,创建一个 JAR ,然后把这个 JAR 安装到本地仓库以为其它项目提供重用性。不用做任何修改,你可以运行 mvn site ,然后在 target/site 目录找到一个 index.html 文件,这个文件链接了 JavaDoc 和一些关于源代码的报告。


诚然,这是一个最简单的样例项目。一个只包含源代码并且生成一个 JAR 的项目。一个遵循 Maven 的约定,不需要任何依赖和定制的项目。如果我们想要定制行为,我们的 pom.xml 的大小将会增加,在最大的项目中,你能看到一个非常复杂的 Maven POM 的集合,它们包含了大量的插件定制和依赖声明。但是,虽然你项目的 POM 文件变得增大,它们包含的信息与一个差不多大小的基于 Ant 项目的构建文件的信息是完全不同的。Maven POM 包含声明:“这是一个 JAR 项目”,“源代码在 src/main/java 目录”。Ant 构建文件包含显式的指令:“这是一个项目”,“源代码在 src/main/java ”,“针对这个目录运行 javac ”,“把结果放到 target/classes ”,“从……创建一个 JAR ”,等等。Ant 必须的过程必须是显式的,而 Maven 有一些“内置”的东西使它知道源代码在哪里,如何处理它们。


该例中 Ant 和 Maven 的区别是:




Apache Ant





  • Ant 没有正式的约定如一个一般项目的目录结构,你必须明确的告诉 Ant 哪里去找源代码,哪里放置输出。随着时间的推移,非正式的约定出现了,但是它们还没有在产品中模式化。



  • Ant 是程序化的,你必须明确的告诉 Ant 做什么,什么时候做。你必须告诉它去编译,然后复制,然后压缩。



  • Ant 没有生命周期,你必须定义目标和目标之间的依赖。你必须手工为每个目标附上一个任务序列。


Apache Maven





  • Maven 拥有约定,因为你遵循了约定,它已经知道你的源代码在哪里。它把字节码放到 target/classes ,然后在 target 生成一个 JAR 文件。



  • Maven 是声明式的。你需要做的只是创建一个 pom.xml 文件然后将源代码放到默认的目录。Maven 会帮你处理其它的事情。



  • Maven 有一个生命周期,当你运行 mvn install 的时候被调用。这条命令告诉 Maven 执行一系列的有序的步骤,直到到达你指定的生命周期。遍历生命周期旅途中的一个影响就是,Maven 运行了许多默认的插件目标,这些目标完成了像编译和创建一个 JAR 文件这样的工作。


Maven 以插件的形式为一些一般的项目任务提供了内置的智能。如果你想要编写运行单元测试,你需要做的只是编写测试然后放到 ${basedir}/src/test/java ,添加一个对于 TestNG 或者 JUnit 的测试范围依赖,然后运行 mvn test 。如果你想要部署一个 web 应用而非 JAR ,你需要做的是改变你的项目类型为 war ,然后把你文档根目录置为 ${basedir}/src/main/webapp 。当然,你可以用 Ant 做这些事情,但是你将需要从零开始写这些指令。使用 Ant ,你首先需要确定 JUnit JAR 文件应该放在哪里,然后你需要创建一个包含这个 JUnit JAR 文件的 classpath ,然后告诉 Ant 它应该从哪里去找测试源代码,编写一个目标来编译测试源代码为字节码,使用 JUnit 来执行单元测试。


没有诸如 antlibs 和 lvy 等技术的支持(即使有了这些支持技术),Ant 给人感觉是自定义的程序化构建。项目中一组高效的坚持约定的 Maven POM ,相对于 Ant 的配置文件,只有很少的 XML 。Maven 的另一个优点是它依靠广泛公用的 Maven 插件。所有人使用 Maven Surefire 插件来运行单元测试,如果有人添加了一些针对新的测试框架的支持,你可以仅仅通过在你项目的 POM 中升级某个特定插件的版本来获得新的功能。


使用 Maven 还是 Ant 的决定不是非此即彼的,Ant 在复杂的构建中还有它的位置。如果你目前的构建包含一些高度自定义的过程,或者你已经写了一些 Ant 脚本通过一种明确的方法完成一个明确的过程,而这种过程不适合 Maven 标准,你仍然可以在 Maven 中用这些脚本。作为一个 Maven 的核心插件, Ant 还是可用的。自定义的插件可以用 Ant 来实现,Maven 项目可以配置成在生命周期中运行 Ant 的脚本。






1.8. 总结


我们刻意的使这篇介绍保持得简短。 我们略述了一些Maven定义的要点,它们合起来是什么,它是基于什么改进的,同时介绍了其它构建工具。 下一章将深入一个简单的项目,看 Maven 如何能够通过最小数量的配置来执行典型的任务。


JDK5.0垃圾收集优化之–Don’t Pause



      作者:江南白衣,最新版链接:http://blog.csdn.net/calvinxiu/archive/2007/05/18/1614473.aspx,版权所有,转载请保留原文链接。


      原本想把题目更简单的定为–《不要停》的,但还是自己YY一下就算了。
      Java开发Server最大的障碍,就是JDK1.4版之前的的串行垃圾收集机制会引起长时间的服务暂停,明白原理后,想想那些用JDK1.3写Server的先辈,不得不后怕。
     好在JDK1.4已开始支持多线程并行的后台垃圾收集算法,JDK5.0则优化了默认值的设置。


一、参考资料:



  1. Tuning Garbage Collection with the 5.0 Java Virtual Machine 官方指南。
  2. Hotspot memory management whitepaper 官方白皮书。
  3. Java Tuning White Paper 官方文档。
  4. FAQ about Garbage Collection in the Hotspot  官方FAQ,JVM1.4.2。
  5. Java HotSpot 虚拟机中的垃圾收集 JavaOne2004上的中文ppt
  6. A Collection of JVM Options JVM选项的超完整收集。

二、基本概念


1、堆(Heap)


JVM管理的内存叫堆。在32Bit操作系统上有1.5G-2G的限制,而64Bit的就没有。


JVM初始分配的内存由-Xms指定,默认是物理内存的1/64但小于1G。


JVM最大分配的内存由-Xmx指定,默认是物理内存的1/4但小于1G。


默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制,可以由-XX:MinHeapFreeRatio=指定。
默认空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制,可以由-XX:MaxHeapFreeRatio=指定。


服务器一般设置-Xms、-Xmx相等以避免在每次GC 后调整堆的大小,所以上面的两个参数没啥用。 



2.基本收集算法



  1. 复制:将堆内分成两个相同空间,从根(ThreadLocal的对象,静态对象)开始访问每一个关联的活跃对象,将空间A的活跃对象全部复制到空间B,然后一次性回收整个空间A。
    因为只访问活跃对象,将所有活动对象复制走之后就清空整个空间,不用去访问死对象,所以遍历空间的成本较小,但需要巨大的复制成本和较多的内存。
  2. 标记清除(mark-sweep):收集器先从根开始访问所有活跃对象,标记为活跃对象。然后再遍历一次整个内存区域,把所有没有标记活跃的对象进行回收处理。该算法遍历整个空间的成本较大暂停时间随空间大小线性增大,而且整理后堆里的碎片很多。
  3. 标记整理(mark-sweep-compact):综合了上述两者的做法和优点,先标记活跃对象,然后将其合并成较大的内存块。

    可见,没有免费的午餐,无论采用复制还是标记清除算法,自动的东西都要付出很大的性能代价。


3.分代


    分代是Java垃圾收集的一大亮点,根据对象的生命周期长短,把堆分为3个代:Young,Old和Permanent,根据不同代的特点采用不同的收集算法,扬长避短也。


Young(Nursery),年轻代。研究表明大部分对象都是朝生暮死,随生随灭的。因此所有收集器都为年轻代选择了复制算法。
    复制算法优点是只访问活跃对象,缺点是复制成本高。因为年轻代只有少量的对象能熬到垃圾收集,因此只需少量的复制成本。而且复制收集器只访问活跃对象,对那些占了最大比率的死对象视而不见,充分发挥了它遍历空间成本低的优点。


    Young的默认值为4M,随堆内存增大,约为1/15,JVM会根据情况动态管理其大小变化。
    -XX:NewRatio= 参数可以设置Young与Old的大小比例,-server时默认为1:2,但实际上young启动时远低于这个比率?如果信不过JVM,也可以用-Xmn硬性规定其大小,有文档推荐设为Heap总大小的1/4。


    Young的大小非常非常重要,见“后面暂停时间优先收集器”的论述。


    Young里面又分为3个区域,一个Eden,所有新建对象都会存在于该区,两个Survivor区,用来实施复制算法。每次复制就是将Eden和第一块Survior的活对象复制到第2块,然后清空Eden与第一块Survior。Eden与Survivor的比例由-XX:SurvivorRatio=设置,默认为32。Survivio大了会浪费,小了的话,会使一些年轻对象潜逃到老人区,引起老人区的不安,但这个参数对性能并不重要。 


Old(Tenured),年老代。年轻代的对象如果能够挺过数次收集,就会进入老人区。老人区使用标记整理算法。因为老人区的对象都没那么容易死的,采用复制算法就要反复的复制对象,很不合算,只好采用标记清理算法,但标记清理算法其实也不轻松,每次都要遍历区域内所有对象,所以还是没有免费的午餐啊。


-XX:MaxTenuringThreshold=设置熬过年轻代多少次收集后移入老人区,CMS中默认为0,熬过第一次GC就转入,可以用-XX:+PrintTenuringDistribution查看。


Permanent,持久代。装载Class信息等基础数据,默认64M,如果是类很多很多的服务程序,需要加大其设置-XX:MaxPermSize=,否则它满了之后会引起fullgc()或Out of Memory。 注意Spring,Hibernate这类喜欢AOP动态生成类的框架需要更多的持久代内存。


4.minor/major collection


    每个代满了之后都会促发collection,(另外Concurrent Low Pause Collector默认在老人区68%的时候促发)。GC用较高的频率对young进行扫描和回收,这种叫做minor collection
而因为成本关系对Old的检查回收频率要低很多,同时对Young和Old的收集称为major collection。
    System.gc()会引发major collection,使用-XX:+DisableExplicitGC禁止它,或设为CMS并发-XX:+ExplicitGCInvokesConcurrent。


5.小结


Young — minor collection — 复制算法


Old(Tenured) — major colletion — 标记清除/标记整理算法



三、收集器


1.古老的串行收集器(Serial Collector)


    使用 -XX:+UseSerialGC,策略为年轻代串行复制,年老代串行标记整理。


2.吞吐量优先的并行收集器(Throughput Collector)


    使用 -XX:+UseParallelGC ,也是JDK5 -server的默认值。策略为:
    1.年轻代暂停应用程序,多个垃圾收集线程并行的复制收集,线程数默认为CPU个数,CPU很多时,可用–XX:ParallelGCThreads=减少线程数。
    2.年老代暂停应用程序,与串行收集器一样,单垃圾收集线程标记整理。


    所以需要2+的CPU时才会优于串行收集器,适用于后台处理,科学计算。


    可以使用-XX:MaxGCPauseMillis= 和 -XX:GCTimeRatio 来调整GC的时间。


3.暂停时间优先的并发收集器(Concurrent Low Pause Collector-CMS)


    前面说了这么多,都是为了这节做铺垫……


    使用-XX:+UseConcMarkSweepGC,策略为:
    1.年轻代同样是暂停应用程序,多个垃圾收集线程并行的复制收集。
    2.年老代则只有两次短暂停,其他时间应用程序与收集线程并发的清除。


3.1 年老代详述


    并行(Parallel)与并发(Concurrent)仅一字之差,并行指多条垃圾收集线程并行,并发指用户线程与垃圾收集线程并发,程序在继续运行,而垃圾收集程序运行于另一个个CPU上。


    并发收集一开始会很短暂的停止一次所有线程来开始初始标记根对象,然后标记线程与应用线程一起并发运行,最后又很短的暂停一次,多线程并行的重新标记之前可能因为并发而漏掉的对象,然后就开始与应用程序并发的清除过程。可见,最长的两个遍历过程都是与应用程序并发执行的,比以前的串行算法改进太多太多了!!!


    串行标记清除是等年老代满了再开始收集的,而并发收集因为要与应用程序一起运行,如果满了才收集,应用程序就无内存可用,所以系统默认68%满的时候就开始收集。内存已设得较大,吃内存又没有这么快的时候,可以用-XX:CMSInitiatingOccupancyFraction=恰当增大该比率。


3.2 年轻代详述


   可惜对年轻代的复制收集,依然必须停止所有应用程序线程,原理如此,只能靠多CPU,多收集线程并发来提高收集速度,但除非你的Server独占整台服务器,否则如果服务器上本身还有很多其他线程时,切换起来速度就….. 所以,搞到最后,暂停时间的瓶颈就落在了年轻代的复制算法上。


    因此Young的大小设置挺重要的,大点就不用频繁GC,而且增大GC的间隔后,可以让多点对象自己死掉而不用复制了。但Young增大时,GC造成的停顿时间攀升得非常恐怖,比如在我的机器上,默认8M的Young,只需要几毫秒的时间,64M就升到90毫秒,而升到256M时,就要到300毫秒了,峰值还会攀到恐怖的800ms。谁叫复制算法,要等Young满了才开始收集,开始收集就要停止所有线程呢。


3.3 持久代


可设置-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled,使CMS收集持久代的类,而不是fullgc,netbeans5.5 performance文档的推荐。


4.增量(train算法)收集器(Incremental Collector)


已停止维护,–Xincgc选项默认转为并发收集器。


四、暂停时间显示


 加入下列参数 (请将PrintGC和Details中间的空格去掉,CSDN很怪的认为是禁止字句) 


-verbose:gc -XX:+PrintGC Details  -XX:+PrintGCTimeStamps


会程序运行过程中将显示如下输出


 9.211: [GC 9.211: [ParNew: 7994K->0K(8128K), 0.0123935 secs] 427172K->419977K(524224K), 0.0125728 secs]


 显示在程序运行的9.211秒发生了Minor的垃圾收集,前一段数据针对新生区,从7994k整理为0k,新生区总大小为8128k,程序暂停了12ms,而后一段数据针对整个堆。


对于年老代的收集,暂停发生在下面两个阶段,CMS-remark的中断是17毫秒:


[GC [1 CMS-initial-mark: 80168K(196608K)] 81144K(261184K), 0.0059036 secs] 


[1 CMS-remark: 80168K(196608K)] 82493K(261184K),0.0168943 secs]


再加两个参数 -XX:+PrintGCApplicationConcurrentTime -XX:+PrintGCApplicationStoppedTime对暂停时间看得更清晰。


五、真正不停的BEA JRockit 与Sun RTS2.0


   Bea的JRockit 5.0 R27 的特色之一是动态决定的垃圾收集策略,用户可以决定自己关心的是吞吐量,暂停时间还是确定的暂停时间,再由JVM在运行时动态决定、改变改变垃圾收集策略。
   
   它的Deterministic GC的选项是-Xgcprio: deterministic,号称可以把暂停可以控制在10-30毫秒,非常的牛,一句Deterministic道尽了RealTime的真谛。 不过细看一下文档,30ms的测试环境是1 GB heap 和 平均  30% 的活跃对象(也就是300M)活动对象,2 个 Xeon 3.6 GHz  4G内存 ,或者是4 个Xeon 2.0 GHz,8G内存。


  最可惜JRockt的license很奇怪,虽然平时使用免费,但这个30ms的选项就需要购买整个Weblogic Real Time Server的license。 


  其他免费选项,有:



  • -Xgcprio:pausetime -Xpausetarget=210ms 
      因为免费,所以最低只能设置到200ms pause target。 200ms是Sun认为Real-Time的分界线。
  • -Xgc:gencon
    普通的并发做法,效率也不错。

  JavaOne2007上有Sun的 Java Real-Time System 2.0 的介绍,RTS2.0基于JDK1.5,在Real-Time  Garbage Collctor上又有改进,但还在beta版状态,只供给OEM,更怪。


六、JDK 6.0的改进


因为JDK5.0在Young较大时的表现还是不够让人满意,又继续看JDK6.0的改进,结果稍稍失望,不涉及我最头痛的年轻代复制收集改良。


1.年老代的标识-清除收集,并行执行标识
  JDK5.0只开了一条收集进程与应用线程并发标识,而6.0可以开多条收集线程来做标识,缩短标识老人区所有活动对象的时间。


2.加大了Young区的默认大小
默认大小从4M加到16M,从堆内存的1/15增加到1/7


3.System.gc()可以与应用程序并发执行
使用-XX:+ExplicitGCInvokesConcurrent 设置


七、小结


1. JDK5.0/6.0


对于服务器应用,我们使用Concurrent Low Pause Collector,对年轻代,暂停时多线程并行复制收集;对年老代,收集器与应用程序并行标记–整理收集,以达到尽量短的垃圾收集时间。


本着没有深刻测试前不要胡乱优化的宗旨,命令行属性只需简单写为:



-server -XmsM -XmxM -XX:+UseConcMarkSweepGC  -XX:+PrintGC Details  -XX:+PrintGCTimeStamps

然后要根据应用的情况,在测试软件辅助可以下看看有没有JVM的默认值和自动管理做的不够的地方可以调整,如-xmn 设Young的大小,-XX:MaxPermSize设持久代大小等。


2. JRockit 6.0 R27.2


但因为JDK5的测试结果实在不能满意,后来又尝试了JRockit,总体效果要好些。
 JRockit的特点是动态垃圾收集器是根据用户关心的特征动态决定收集算法的,参数如下



 -XmsM -XmxM -Xgcprio:pausetime -Xpausetarget=200ms -XgcReport -XgcPause -Xverbose:memory


编写对GC友好,又不泄漏的代码


   作者:江南白衣,最新版链接:http://blog.csdn.net/calvinxiu/archive/2007/05/22/1621051.aspx,版权所有,转载请保留原文链接。


    看到JavaOne2007上有篇《Garbage-Collection-Friendly Programming》的68页PPT,心想都2007了还谈这个基本问题,一定总结得很全面了才好意思站出来讲吧。    


GC的基础概念见上篇:JDK5.0垃圾收集优化之–Don’t Pause  


1.使用更多生命周期短的、小的、不改变指向(immutable)的对象,编写清晰的代码。


    出于懒惰也好,朴素的节俭意识也好,我们都习惯对一个变量重用再重用。但是….



  • Java的垃圾收集器喜欢短生命周期的对象,对象如果在新生代内,在垃圾收集发生前就死掉了,垃圾收集器就什么都不用做了。
  • 现代JVM构建一个新对象只需要10个本地CPU指令,并不弱于C/C++。 (但垃圾收集没有压缩算法时会稍慢,更频繁的New对象也导致更频繁的GC)。
  • 大对象的分配效率更低,而且对非压缩算法的垃圾收集器,更容易造成碎片。
  • 对象重用增加了代码的复杂度,降低了可读性。

   所以有标题的呼吁,比如不要害怕为中间结果分配小对象。但编程习惯的改变也不是一朝一夕的事情。



2.将用完的对象设为NULL其实没什么作用。


    貌似很酷的把对象主动设为Null 的”好习惯”其实没什么用,JIT Compiler会自动分析local变量的生命周期。
    只有一个例外情况,就是String[1024] foo 这种赤裸裸的数组,你需要主动的foo[100]=null释放第100号元素,所以最好还是直接用ArrayList这些标准库算了。


 


3.避免显式GC–System.gc()。


    大家都知道System.gc()不好,full-gc浪费巨大,gc的时机把握不一定对等等,甚至有-XX:+DisableExplicitGC的JVM参数来禁止它。


    哈哈,但我还不会用System.gc()呢,不怕不怕。真的不怕吗?



  • 先用FindBugs 查一下所用到的全部第三方类库吧…
  • 至少RMI 就会老实不客气的执行System.gc()来实现分布式GC算法。但我也不会用RMI啊。那EJB呢,EJB可是建在RMI上的….

    如果无可避免,用-Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 (单位为微妙) 增大大GC的间隔(原默认值为1分钟),-XX:+ExplicitGCInvokesConcurrent 让System.gc() 也CMS并发执行。


 


4.继续千夫所指的finalize()


    大家也都知道finalize()不好,分配代价昂贵,释放代价更昂贵(要多走一个循环,而且他们死得慢,和他们相关联的对象也跟着死得慢了),又不确定能否被调用(JVM开始关闭时,就不会再进行垃圾收集),又不确定何时被调用(GC时间不定,即使system.gc()也只是提醒而不是强迫GC,又不确定以什么样的顺序调用,所以finalize不是C++的析构函数,也不像C++的析构函数。


   我们都知道啊,所以我从来都没使用。都是在显式的维护那些外部资源,比如在finally{}里释放。


 


5.WeakReference/SoftReference


   这是个平时不怎么会搭理,偶然知道了又觉得有用的Java特征。大家都知道Java里所有对象除int等基本类型外,都是Pass by Reference的指针,实例只要被一个对象连着,就不会被收集。
    而WeakReference就是真正意义上的C++指针,只是单纯的指向一个对象,而不会影响对象的引用计数。
    而SoftReference更特别,在内存足够时,对象会因为SoftReference的存在而不被收集,但内存不足时,对象就还是会被收集,怎么看都是做简单缓存的料子。代码如下:



  Foo foo = new Foo(); 
  SoftReference sr
= new SoftReference(foo); 
  Foo bar 
=  sr.get(); 

  如果foo已被垃圾收集,sr.get()会返回Null;


  另外还有一个ReferenceQueue的机制,使得对象被回收时能获得通知,比finalize()完全不知道GC何时会执行要聪明的多。



  ReferenceQueue rq = new ReferenceQueue();
  ref 
= new WeakReference(foo, rq); 
  WeakReference cleaned 
= rq.pool(); 

  cleaned就是刚刚被GC掉的WeakReference。


6.内存泄漏


   java 不是有垃圾收集器了吗?怎么还泄漏啊,唬我啊??
   嗯,此泄漏非比泄漏。C/C++的泄漏,是对象已不可到达,而内存又没有回收,真正的内存黑洞。
   而Java的泄漏,则是因为各种原因,对象对应用已经无用,但一直被持有,一直可到达。
   总结原因无外乎几方面:



  1. 被生命周期极长的集合类不当持有,号称是Java内存泄漏的首因。
    这些集合类的生命周期通常极长,而且是一个辅助管理性质的对象,在一个业务事务运行完后,如果没有将某个业务对象主动的从中清除的话,这个集合就会吃越来越多内存,可以用WeakReference,如WeakHashMap,使得它持有的对象不增加对象的引用数。
  2. Scope定义不对,这个很简单了,方法的局部变量定义成类的变量,类的静态变量等。
  3. 异常时没有加finally{}来释放某些资源,JDBC时代也是很普遍的事情。
  4. 另外一些我了解不深的原因,如:Swing里的Listener没有显式remove;内部类持有外部对象的隐式引用;Finalizers造成关联对象没有被及时清空等。

内存泄漏的检测


有不少工具辅助做这个事情的,如果手上一个工具也没有,可以用JDK自带的小工具:



  • 看看谁占满了Heap?
    用JDK6的jmap可以显示运行程序中对象的类型,个数与所占的大小
    先用jps 找到进程号,然后jmap -histo pid 显示或 jmap -dump:file=heap_file_name pid 导出heap文件
  • 为什么这些对象仍然可以到达?
    用jhat(Java Heap Analysis Tool) 分析刚才导出的heap文件。
    先jhat heap_file_name,然后打开浏览器http://localhost:7000/ 浏览。

myeclipse 6 hot key content assist

为什么MyEclipse6.0 不出现快速提示,我要把整个单词快打完了才出现,。
如:public class TestMain extends TestCase 如果是以前3.2的extends  直接按“ALT+/”就可以出现这个单词提示,
我现在完全要自己打出来了。这样会浪费很多时间的。
  这是不是那么没有设置好呀。

 

 

eclipse3.3中把内容助手(content assist)的快捷键由 alt + /  改成了ctrl + space,这又刚好跟我们操作系统的切换输入法的快捷键冲突,所以造成内容助手不能使用了,给写代码带来了极大的不便。 而已前eclipse 3.2版本中的 alt + / 快捷键被作为新的单词补全(word competion)功能的快捷键。所以现在想像以前一样使用alt + / 来实现内容助手的功能,就需要更改eclipse3.3快捷键的设置了。具体操作如下:

1. 点击Windows->Preferences->General->Keys .

2. 在列出的快捷键列表中查找到:word competion,把它的快捷键alt + / 改成其它的快捷键(怎么改,先把此快捷键删除,点右边的按钮”remove binding”, 再选中binding文本框,输入你想要的快捷键)。

3. 在列出的快捷键列表中查找到:content assist,把它的快捷键 ctrl + space 改成我们想的的 alt + / 即可了。

Resin-pro-3.1.6 full crack download



Caucho Technology is an engineering company devoted to reliable open source and high performance Java-PHP solutions. Caucho is a Sun Microsystems Java EE licensee whose products include Resin application server, Hessian web services and Quercus Java-PHP solutions.


Resin Professional is the application server of choice for over 7,500 companies. Technical support is handled by Caucho engineers and not outsourced, meaning that when you contact Caucho for a support issue, you receive a fast response directly from the engineers who write the code. Resin runs on all major operating systems including Linux, Windows and Solaris.


 

Resin-pro-3.1.6 full crack download

Windows


Linux

resin-pro-3.1.5 full cracked.

 虽然resin-pro-3.1.5早在2月26号就发布了,但一直标记为dev,今天发现已经不是dev了,赶紧下载回来破解。


resin-pro-3.1.5.zip 下载


resin-pro-3.1.5.tar.gz 下载


此次破解的跟上次的3.1.3一样,功能上完全没有任何限制了,可以使用session持久化、cache等,只需要做好相关的配置即可。


 3.1.5的Change Log请看官方文档:Resin Change Log,同时可以看到3.1.6 snapshot了。 我会及时破解Resin的最新版本!


文章来源:http://www.dingl.com/blog/archives/28


proxool.FatalSqlExceptionHelper.testException()

我终于找到了出问题的线程了。


通过thread dump 我发现如下线程一直在运行:
“resin-tcp-connection-*:80-6075” daemon prio=1 tid=0x0857aac8 nid=0x7fb0 runnable [0x82dfe000..0x82dff19c]
at org.logicalcobwebs.proxool.FatalSqlExceptionHelper.testException(FatalSqlExceptionHelper.java:116)
at org.logicalcobwebs.proxool.FatalSqlExceptionHelper.testException(FatalSqlExceptionHelper.java:103)
at org.logicalcobwebs.proxool.AbstractProxyStatement.testException(AbstractProxyStatement.java:65)
at org.logicalcobwebs.proxool.ProxyStatement.invoke(ProxyStatement.java:146)
at org.logicalcobwebs.proxool.ProxyStatement.intercept(ProxyStatement.java:57)
at $java.sql.Statement$$EnhancerByCGLIB$$1a91e2dc.close()
at com.tag.db.doEndTag(valuetag.java:438)
at _jsp._rst._eng_0aa__jsp._jspService(_products_0viewinfo__jsp.java:75)
at com.caucho.jsp.JavaPage.service(JavaPage.java:60)
at com.caucho.jsp.Page.pageservice(Page.java:570)
at com.caucho.server.dispatch.PageFilterChain.doFilter(PageFilterChain.java:159)
at com.kenfor.exutil.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:152)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:70)
at com.kenfor.exutil.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:152)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:70)
at com.caucho.server.webapp.WebAppFilterChain.doFilter(WebAppFilterChain.java:178)
at com.caucho.server.dispatch.ServletInvocation.service(ServletInvocation.java:229)
at com.caucho.server.http.HttpRequest.handleRequest(HttpRequest.java:267)
at com.caucho.server.port.TcpConnection.run(TcpConnection.java:388)
– locked <0x5c472008> (a java.lang.Object)
at com.caucho.util.ThreadPool.runTasks(ThreadPool.java:490)
at com.caucho.util.ThreadPool.run(ThreadPool.java:423)
at java.lang.Thread.run(Thread.java:595)


然后我又查看了顶级的代码调用
at org.logicalcobwebs.proxool.FatalSqlExceptionHelper.testException(FatalSqlExceptionHelper.java:116)
也就是testException这个方法一直在执行,我不清楚为什么为会出现如此死循环。


我想问问大家,什么样的代码会导致proxool的testException一直运行着。



——————————————————————————–


不知道是分数不够,还是人才稀少,怎么就没人回答呢。郁闷


——————————————————————————–


为什么会重复出现:
at com.kenfor.exutil.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:152)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:70)
at com.kenfor.exutil.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:152)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:70)
谁能告诉我啊。


——————————————————————————–


本来proxool是很有口碑的连接池 ,怎么会导致


at org.logicalcobwebs.proxool.FatalSqlExceptionHelper.testException(FatalSqlExceptionHelper.java:116)中testException运行没完没了呢。


——————————————————————————–


努力接分升级中…帮你up!


——————————————————————————–


filter 死循环调用?


——————————————————————————–


回复:iihero(阿黑哥)


应该不是filter的引起的,如果是filter的话,那所有的页面都会很容易进入死循环。


——————————————————————————–


下面就是这个永远不结束的方法,我看了一下源代码,虽然有循环部分,但也不导致死循环,
大伙帮我分析一下,具体是什么原因会导致下面的代码一直执行?
/**
* Test to see if an exception is a fatal one
* @param cpd the definition so we can find out what a fatal exception looks like
* @param t the exception to test
* @param level the recursion level (max 20)
* @return true if it is fatal
*/
protected static boolean testException(ConnectionPoolDefinitionIF cpd, Throwable t, int level) {
boolean fatalSqlExceptionDetected = false;
Iterator i = cpd.getFatalSqlExceptions().iterator();
while (i.hasNext()) {
if (t.getMessage() != null && t.getMessage().indexOf((String) i.next()) > -1) {
// This SQL exception indicates a fatal problem with this connection.
fatalSqlExceptionDetected = true;
}
}


// If it isn’t fatal, then try testing the contained exception
if (!fatalSqlExceptionDetected && level < 20) {
Throwable cause = getCause(t);
if (cause != null) {
fatalSqlExceptionDetected = testException(cpd, cause, level + 1);
}
}


return fatalSqlExceptionDetected;
}


——————————————————————————–


while (i.hasNext()) {
if (t.getMessage() != null && t.getMessage().indexOf((String) i.next()) > -1) {
// This SQL exception indicates a fatal problem with this connection.
fatalSqlExceptionDetected = true;
}
}


t.getMessage() != null这句话不成立的话,就没机会调用i.next()
就死循环了。


——————————————————————————–


在网上大家都对proxool赞赏有加,但是我们的项目出现如此严重的错误,实属不应该,
请兄弟们帮我查明此原因,不让我再去怀疑proxool的过错了,把清白留proxool。


——————————————————————————–


回复:zhmt(不爽你就用分砸我!!!)


t.getMessage() != null不成立,也应该会再次调用i.hasNext()吧


——————————————————————————–


请大伙帮我把铁顶起来,都快两天了,还是没找到答案。


——————————————————————————–


你说的错了,&& 运算是从左到右,左边的不成立,直接就返回false了,不再计算右边的。所以不调用i.next()。


楼主要加强基础。


——————————————————————————–


你可以写个小例子测试一下。


——————————————————————————–


当 t.getMessage() != null不成立时,是“t.getMessage().indexOf((String) i.next()) > -1”没机会执行。不是i.hasNext


——————————————————————————–


回复: zhmt(不爽你就用分砸我!!!)


我还是不明白,t.getMessage() != null这句话不成立的话,就会导致死循环。


——————————————————————————–


就算“t.getMessage().indexOf((String) i.next()) > -1不知道,也不会导致死循环啊。


——————————————————————————–


我上面的那段代码是从proxool中取出来的,如果这么容易就死循环了,那我就要怀疑这个东西的安全性啦。


——————————————————————————–


你的问题的背景是什么啊?
不能光看这一点。


——————————————————————————–


resin-tcp-connection-*:80-6075″ daemon prio=1 tid=0x0857aac8 nid=0x7fb0 runnable


这是个守护线程,(daemon),一直运行的话,是很正常的。可能问题不在这里,你的是什么性能问题啊?


——————————————————————————–


好,那我就说说背景 :


我维护的是个网站项目,网站经常服务器cpu 99%,并且上去了就不下来了,开始我就确定是
死循环的问题,但是找不到根据,前两天我用kill -3 pid,每隔5分钟Thread Dump一下,发现
上面的线程一直在虚拟机(JVM)里面运行者。那只有死循环才不会退出的。
我不知道我讲清楚没?


——————————————————————————–


daemon是守护进程,但是不应该不结束。


——————————————————————————–


你确信是这个线程启动后cpu才到100%的吗?


——————————————————————————–


是的。在平时,我找不到这样的线程。


——————————————————————————–


我查了一下它的源码,这个类是用来检查一个异常是否是严重异常,它能一直运行说明你的应用导致了很多sql异常。如果这个pool是经过大家的检验的话,可能你的应用中,哪一部分的sql调用很有问题。


——————————————————————————–


是的,但是很多异常也会有个数量限制啊,可能处理校验的速度慢啊,而不会出现,死循环啊。
在页面上传入的sql语句难免有些问题,我测试过,一般情况下,系统会自动处理的,但是我想在就不明白,什么情况下,什么样的SQL语句会导致死循环。


——————————————————————————–


你看了有多少个这样线程了吗?
可能不是死循环,而是线程结束后又被启动起来。或者是启动了多个这样的线程。
如果不是我感才说的那个死循环的,就不可能出现死循环了(next和hasNext要成对使用才不会死在那,如果只使用hasNext而不使用next,那么iterator是不往下走的,就会死了。)。
另外它的递归调用也不会超过20层,所以也不会死。


——————————————————————————–


我觉得从自己的应用上来改进应该更好。


——————————————————————————–


回复:zhmt(不爽你就用分砸我!!!)


你说的有道理,如果 t.getMessage() ==null的话,就会陷入死循环。


但是我看我们的代码都是按照JDBC规范来写的啊。


下面我贴些原码,帮我看看有什么问题。


 


——————————————————————————–


public HashMap getdbValue(PoolBean pool) throws Exception
{
if(pool.getLog().isDebugEnabled())
pool.getLog().debug(“star getdbValue”);


String system_name = pool.getDatabaseInfo().getSystemName();
HashMap result = null;
String temp_sql = createSql();
if(temp_sql == null)
throw new SQLException(“not sql statement”);


Statement stmt = null;
ResultSet rs = null;
Connection con = null;
try
{
con = pool.getNoInfoConnection();// .getConnection();
con.setReadOnly(true);
stmt = con.createStatement();
rs = stmt.executeQuery(temp_sql);
// rs = stmt.executeQuery(sql);
if (rs != null) {
ResultSetMetaData rsmd = rs.getMetaData();
int colCount = rsmd.getColumnCount();
if (rs.next()) {
result = new HashMap();
for (int i = 1; i <= colCount; i++) {
String name = rsmd.getColumnName(i);
name = name.toLowerCase();
String type_name = rsmd.getColumnTypeName(i).toLowerCase();
// System.out.println(“field name : ” + name + ” , type_anme : ” + type_name);
if (“text”.equals(type_name)) {
//当字段类型为text时,如果直接用rs.getObject(i)取数据,在jtds1.0版本中不能直接取出,改为以下方式即可 2005-07-22 张贵平
String tt_str = rs.getString(i);
// System.out.println(“text — “+tt_str);
if (tt_str == null)
tt_str = “”;
else
tt_str = tt_str.trim();
result.put(name.trim(), tt_str);
}
else {
Object obj_value = rs.getObject(i);
if (obj_value instanceof java.lang.String) {
String t_str = null;
if (obj_value == null)
t_str = “”;
else
t_str = String.valueOf(obj_value).trim();
result.put(name.trim(), t_str);
}
else {
result.put(name.trim(), obj_value);
}
}
}
}
rsmd = null;
}
rs.close();
stmt.close();
con.setReadOnly(false);
con.close();
}
catch(SQLException e)
{
//CloseCon.Close(con);
pool.getLog().error(system_name+”,”+e.getMessage()+”,sql:”+temp_sql);
throw new SQLException(“database perform error : ” + e.getMessage());
}
finally
{
CloseCon.Close(con);
}


return result;


}


从线程堆栈上看$java.sql.Statement$$EnhancerByCGLIB$$1a91e2dc.close()
,是从stmt.close()进去的。



——————————————————————————–


觉得不规范
rs.close();
stmt.close();
con.setReadOnly(false);
con.close();


以上这些东西都要放在finnally块中的。


我没用过PoolBean,不知道怎么用,觉得数据库的操作好像没多大问题。你倒网上搜索资料看看吧。


——————————————————————————–


你看下Filter里面的跳转是不是错了。


——————————————————————————–


回复:zhmt(不爽你就用分砸我!!!)


PoolBean 是我们自己写的一个类,主要是做跟连接池的衔接工作。


是的,不是很规范,但是这样也应该不会导致proxool死循环。


——————————————————————————–


我们自己的Filter类,看看有什么问题。


public class SetCharacterEncodingFilter implements Filter {


Log log = LogFactory.getLog(this.getClass().getName());


// —————————————————– Instance Variables


/**
* The default character encoding to set for requests that pass through
* this filter.
*/
protected String encoding = null;



/**
* The filter configuration object we are associated with. If this value
* is null, this filter instance is not currently configured.
*/
protected FilterConfig filterConfig = null;


/**
* 上传文件的最大大小
*/
protected int fileMaxLength = 200*1024; //200K


/**
* Should a character encoding specified by the client be ignored?
*/
protected boolean ignore = true;



/**
* Take this filter out of service.
*/
public void destroy() {


this.encoding = null;
this.filterConfig = null;


}



/**
* Select and set (if specified) the character encoding to be used to
* interpret request parameters for this request.
*
* @param request The servlet request we are processing
* @param result The servlet response we are creating
* @param chain The filter chain we are processing
*
* @exception IOException if an input/output error occurs
* @exception ServletException if a servlet error occurs
*/
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException {


// Conditionally select and set the character encoding to be used


HttpServletRequest t_re = (HttpServletRequest) request;


String re_uri = trimString(t_re.getRequestURI());
String re_host = trimString(t_re.getServerName());
String qu_str = trimString(t_re.getQueryString());



if (re_uri.indexOf(“.do”) > 0)
{
if (log.isInfoEnabled())
log.info(re_host + re_uri + “?” + qu_str);


try
{


if (ignore || (request.getCharacterEncoding() == null)) {
String encoding = selectEncoding(request);
if (encoding != null)
request.setCharacterEncoding(encoding);
}
// Pass control on to the next filter
chain.doFilter(request, response);
}
catch(Exception e)
{
// e.printStackTrace();
String error_mes = e.getMessage();
String strServerName = null;
String strQueryString = null;
String requestUrl = null;
String remoteAddr = null;
String referer = “”;
if(error_mes.indexOf(“reset”)<0 )
{
try {
strServerName = t_re.getServerName();
strQueryString = t_re.getQueryString();
requestUrl = t_re.getRequestURI();
// strQueryString = CodeTransfer.ISOToUnicode(strQueryString);
referer = t_re.getHeader(“referer”);
remoteAddr = t_re.getRemoteAddr();
}
catch (Exception e1) {}
if (error_mes != null && !”null”.equals(error_mes)&& error_mes.length() > 0) {
log.error(“,exception:” +
error_mes + strServerName + ” , ” + strQueryString + ” , ” +
requestUrl + ” , ” + referer);
// System.out.println(“exception at filter:” +
// error_mes);
}


}
if(log.isInfoEnabled())
log.info(strServerName + ” , ” + strQueryString+ ” , ” + requestUrl + ” , ” + referer);
}


}



/**
* Place this filter into service.
*
* @param filterConfig The filter configuration object
*/
public void init(FilterConfig filterConfig) throws ServletException {


this.filterConfig = filterConfig;
this.encoding = filterConfig.getInitParameter(“encoding”);
String value = filterConfig.getInitParameter(“ignore”);
String file_max_length = filterConfig.getInitParameter(“file_max_length”);
if(file_max_length!=null && file_max_length.length() >0)
{
fileMaxLength = com.kenfor.util.MyUtil.getStringToInt(file_max_length,200)*1024;
}


if (value == null)
this.ignore = true;
else if (value.equalsIgnoreCase(“true”))
this.ignore = true;
else if (value.equalsIgnoreCase(“yes”))
this.ignore = true;
else
this.ignore = false;


}


/**
* Select an appropriate character encoding to be used, based on the
* characteristics of the current request and/or filter initialization
* parameters. If no character encoding should be set, return
* null.
*


* The default implementation unconditionally returns the value configured
* by the encoding initialization parameter for this
* filter.
*
* @param request The servlet request we are processing
*/
protected String selectEncoding(ServletRequest request) {


return (this.encoding);


}
private String trimString(String value)
{
String result = “”;
if(value !=null)
result = value.trim();


return result;
}



}


 


 


——————————————————————————–


如果真的是proxool,那我应该感到欣慰,如果是我们写的代码不当引起的,但我就真的无地之容了。


——————————————————————————–


呵呵,这个我也搞不清楚,楼主最好把你们的那个poolBean自己测试一下。
能找到那种情况下出那个错误是最好的。


看看循环使用的时候是否也抛出这个异常,如果这样的话就查查哪的问题吧。如果不出错,可能就是sql写的有问题了。


Googlipse-不错的GWT Eclipse插件


最近发现一个很不错的用于在Eclipse IDE下应用GWT开发AJAX的插件,叫Googlipse,名字还很好记,呵呵.
它的最近发布版本是0.5.4版,可以支持GWT1.4.60,不过在sourceforge.net里的邮件列表里发现原来这个插件已经停止开发与BUG修复了,真是可惜.现在把安装与使用方法简单翻译一下,以防自己以后忘记,也方便大家学习.不过,本人E文也一般,大致上给翻译一下, 翻译的很生硬,不过主要的信息还是体现出来了,大家将就一下


准备:


1) 下载:http://sourceforge.net/projects/googlipse


2) 安装前提:
 a) Eclipse 3.2 with WebTools Platform 1.5(一定要装,)
 b) 已经安装了JDK 1.5以上
 c) 还需要下载 Google Web Toolkit , 网址是: http://code.google.com/webtoolkit/


 


安装插件到制作实例的全过程(英文是从官方网站上COPY的)


 (*) Drop the com.googlipse.gwt_<version>.jar file in your eclipse\plugins folder
 将com.googlipse.gwt_<version>.jar文件放到你的Eclipse安装文件夹中的plugins文件夹下 (译者注: 我这里用的的com.googlipse.gwt_0.5.4.jar)


 (*) Open Eclipse. Select Window->Preferences->Googlipse and set GWT home to the directory where you have installed the Google Web Toolkit.
 打开Eclipse, 选择Window->Preferences->Googlipse , 设置GWT安装目录


 (*) You are all set to code.
 (此句不知该怎么翻译..-_-!)


Adding Googlipse to your project:
 Googlipse is implemented as a WTP Facet. When creating a new Dynamic Web Project, select Googlipse in the Project Facets page. If you already have a Dynamic Web Project, you can add Googlipse facet by selecting Project->Properties->Project Facets(Please make sure you don’t have gwt-user.jar in your classpath). In case you didn’t like Googlipse, you can remove the facet.


添加Googlipse到你的工程:
 Googlipse是一个实现了WTP的插件(Facet这个单词不知道具体要怎么翻译,暂且翻译成”插件”). 当新建一个的动态WEB工程时,可在工程模块页面中选择Googlipse.如果已经有一个动态WEB工程时,可以通过 Project->Properties->Project Facets 添加Googlipse插件(请确认gwt-user.jar在不在你的classpath中). 假使你不喜欢Googlipse,你也可以移除它.


Creating a Module:
 Once you have a Dynamic Web Project with Googlipse facet, you can add a new module by File->New->Other->Googlipse->Gwt Module. Modules can be created only in valid java packages (default package is not allowed). Either you can type in the package (with project & source folder) in the location field or you can select it by clicking Browse button. You can also click the Create button to create a new package. Next type in the name of the module. Click Finish, you will have all the artifacts for the module generated.


新建一个模块:
 当有了一个包含Googlipse插件的动态WEB工程后,你可以通过 File->New->Other->Googlipse->Gwt Module 添加一个新的模块. 这些模块只能被创建到一个有效的包中(默认包名不允许使用),
你可以指定包名(包含工程名和源文件夹名)或通过点击Browse按钮选择包. 你也可以自己新建一个包. 然后输入模块名称,点击Finish, 就可以得到这个模块生成的组件.
 
Adding a Remote Service;


 Note :A Remote Service will be created only in a module. So if you don’t have a module, you need to create one using the New Module wizard, before this step.
 You can select File->New->Other->Googlipse->Gwt Remote Service. Click the Browse button and select the module (the gwt.xml file). Type the name and uri for the service and click Finish. Now the artifacts for the remote service will be generated. (You have to add an entry in the gwt.xml file manually. Googlipse doesn’t add it. This feature will be implemented in future versions)


添加远程服务:
 提示: 一个模块中只能创建一个远程服务. 在这一步之前, 如果你没有模块, 你需要使用New Module向导创建一个新模块
 选择: File->New->Other->Googlipse->Gwt Remote Service , 点击Browse按钮,选择当前模块(即gwt.xml文件),输入该服务的名程和uri地址,然后点击Finish. 现在这个远程服务的组件就已经生成了.(你必须手动地在gwt.xml文件中添加配置. Googlipse并不自动添加, 在以后的版本中将支持该功能)
 
Adding a Remote Service method:


 You can open the RemoteService interface and add/change methods in it. You need to provide the implementation of those methods in RemoteServiceImpl class, but thanks to Googlipse, you don’t have to do anything in RemoteServiceAsync. Googlipse will automatically update the corresponding Async file whenever a RemoteService interface is changed.


添加一个远程服务的方法:
 你可以打开RemoteService接口并添加/修改其中的方法. 你需要在RemoteServiceImpl类中提供这些方法的实现, 不过有了Googlipse, 你不需要做任何事情,当RemoteService接口改变时Googlipse会自动更新相应的文件
 
Calling a method using Remote Service:
 The utility class in the Remote service should help you in making the remote call.
 
 MyRemoteServiceAsync async = MyRemoteService.Util.getInstance();
 async.makeRemoteCall(param1, param2, callback);
 
在远程服务中调用一个方法:
 在远程服务的实体类会帮你产生相应的远程调用.
 MyRemoteServiceAsync async = MyRemoteService.Util.getInstance();
 async.makeRemoteCall(param1, param2, callback);


Running/Debugging a Gwt Application:
 Select Run->Run/Debug to activate the Lauch configuration dialog box. Double Click “Gwt Application”. In the main page, you can select the Project & Module you want to run. In the parameters page you can select the parameters such as port and log level. Click Run to execute the GwtShell & bring up your application. The laucher will add the jar files & all the source folders in the project to your application.


运行/调试:
 选择 Run->Run/Debug 显示Lauch configuration对话框, 双击”Gwt Application”. 在main页面中,选择要运行的工程和模块.在parameters页面中选择参数,如端口和日志级别. 点击Run,即可执行GwtShell并加载你的应用程序, GwtShell将添加工程中的jar包和所有的源文件夹到你的应用程序中

2008年最值得学习的5个Java技术


Carlos Perez发表了2008年最值得学习的5个Java技术:

1.OSGi(特别是Java动态模型方面)

OSGi service platform是一个基于Java的platform,OSGi service platform是一个开放并且提供统一接口标准的体系框架,基于这个体系框架,服务提供商,程序开发人员,软件提供商,服务网管运营商,设备提供商能够协调地联合起来开发,部署以及管理向用户提供的各种服务。

2.JCP JAVA内容仓库(Java Content Repository) 2002年一月发布

3.GWT (Google Web Toolkit ) 2006年5月发布,Google 推出的一个开发 Ajax 应用的框架,它支持用 Java 开发和调试 Ajax 应用。

4.Groovy 2004年5月发布,Groovy是一种基于JVM的敏捷开发语言,它结合了Python、Ruby和Smalltalk的许多强大的特性。Java开发者可以使用类似Java的语法来获得这些特性的支持。

5.Cloud computing 云计算(虚拟服务器设计,不使用EJB的分布式运算)


 


 


这是一个很有意思的名单,因为以上技术都算比较“老”的技术了,你认为2008最应该值得学习的java技术是什么?


 


附:什么是JCP JAVA内容仓库(Java Content Repository)?


 


JSR -170把自己定义为一个能与内容仓库互相访问的,独立的,标准的方式。同时它也对内容仓库做出了自己的定义,它认为内容仓库是一个高级的信息管理系统,该系统是是传统的数据仓库的扩展,它提供了诸如版本控制、全文检索,访问控制,内容分类、访问控制、内容事件监视等内容服务。

Java Content Repository  API(JSR-170)试图建立一套标准的API去访问内容仓库。如果你对内容管理系统(CMS)不熟悉的话,你一定会对内容仓库是什么感到疑惑。你可以这样去理解,把内容仓库理解为一个用来存储文本和二进制数据(图片,word文档,PDF等等)的数据存储应用程序。一个显著的特点是你不用关心你真正的数据到底存储在什么地方,是关系数据库?是文件系统?还是XML?不仅仅是数据的存储和读取,大多数的内容仓库还提供了更加高级的功能,例如访问控制,查找,版本控制,锁定内容等等。


 


一段时间以来市场上出现了各个厂家开发的不同的CMS系统,这些系统都建立在他们各自的内容仓库之上。
问题出现了,每个CMS开发商都提供了他们自己的API来访问内容仓库。这对应用程序的开发者带来了困扰,因为他们要学习不同的开发商提供的API,同时,他们的代码也与这些特定的API产生了绑定。

JSR-170正是为解决这一问题而出现的,它提供了一套标准的API来访问任何数据仓库。通过JSR-170,你开发代码只需要引用 javax.jcr.* 这些类和接口。它适用于任何兼容JSR-170规范的内容仓库。

我们将通过一个例子来逐步了解JSR-170。

为什么需要 Java Content Repository API

随着各个厂家各自的内容仓库实现数量的增长,人们越来越需要一组通用的编程接口来使用这些内容仓库,这就是JSR-170所要做的东西。它提供一组通用的编程接口来连接内容仓库。你可以把JSR-170理解为和JDBC类似的API,这样你可以不依赖任何具体的内容仓库实现来开发你的程序。你可以直接使用支持JSR-170的内容仓库;或者如果一些厂家的内容仓库不支持JSR-170则可以通过这些厂家提供的JSR-170驱动来完成从JSR-170与厂家特定的内容仓库的转换。

下面这张图描述了使用JSR-170开发的应用系统的结构。在该系统运行的时候,它可以操作内容仓库1,2,3中的任意一个。在这些内容仓库当中,只有2 是直接支持JSR-170的,剩下的两个都需要JSR-170驱动来和应用系统交互。注意:你的应用系统完全不用关心你的数据是如何存储的。1可能使用了关系数据库来存储,而2使用了文件系统,至于上,它甚至更前卫的使用了XML。

repositorymodel1.gif

JSR-170 API对不同的人员提供了不同的好处。

●对于开发者无需了解厂家的仓库特定的API,只要兼容JSR-170就可以通过JSR-170访问其仓库。
●对于使用CMS的公司则无需花费资金用于在不同种类CMS的内容仓库之间进行转换。
●对于CMS厂家,无需自己开发内容仓库,而专注于开发CMS应用。


 


来自:http://www.iocblog.net/static/2007/475.html

Java on Guice

Java on Guice
Guice 1.0 User’s Guide






Guice (pronounced “juice”) is an ultra-lightweight, next-generation dependency injection container for Java 5 and later.


Introduction


The enterprise Java community exerts a lot of effort toward wiring objects together. How does your web application get access to a middle tier service, or your service to the logged in user or transaction manager? You’ll find many general and specific solutions to this problem. Some rely on patterns. Others use frameworks. All result in varying degrees of testability and some amount of boilerplate code. You’ll soon see that Guice enables the best of all worlds: easy unit testing, maximal flexibility and maintainability, and minimal repetition.



We’ll use an unrealistically simple example to illustrate the benefits of Guice over some classic approaches which you’re probably already familiar with. The following example is so simple in fact that, even though it will show immediate benefits, we won’t actually do Guice justice. We hope you’ll see that as your application grows, Guice’s benefits accelerate.



In this example, a client depends on a service interface. This could be any arbitrary service. We’ll just call it Service.




public interface Service {


  void go();
}



We have a default implementation of this service which the client should not depend directly on. If we decide to use a different service implementation in the future, we don’t want to go around and change all of our clients.




public class ServiceImpl implements Service {


  public void go() {


    …


  }


}



We also have a mock service which we can use in unit tests.



public class MockService implements Service {




  private boolean gone = false;

  public void go() {
    gone = true;
  }

  public boolean isGone() {
    return gone;
  }
}


Plain Old Factories


Before we discovered dependency injection, we mostly used the factory pattern. In addition to the service interface, you have a service factory which provides the service to clients as well as a way for tests to pass in a mock service. We’ll make the service a singleton so we can keep this example as simple as possible.


public class ServiceFactory {

  private ServiceFactory() {}
   
  private static Service instance = new ServiceImpl();

  public static Service getInstance() {
    return instance;
  }
 
  public static void setInstance(Service service) {
    instance = service;
  }
}


Our client goes directly to the factory every time it needs a service.



public class Client {

  public void go() {
    Service service = ServiceFactory.getInstance();
    service.go();
  }
}



The client is simple enough, but the unit test for the client has to pass in a mock service and then remember to clean up afterwards. This isn’t such a big deal in our simple example, but as you add more clients and services, all this mocking and cleaning up creates friction for unit test writing. Also, if you forget to clean up after your test, other tests may succeed or fail when they shouldn’t. Even worse, tests may fail depending on which order you run them in.



public void testClient() {
  Service previous = ServiceFactory.getInstance();
  try {
    final MockService mock = new MockService();
    ServiceFactory.setInstance(mock);
    Client client = new Client();
    client.go();
    assertTrue(mock.isGone());
  }
  finally {
    ServiceFactory.setInstance(previous);
  }
}




Finally, note that the service factory’s API ties us to a singleton approach. Even if getInstance() could return multiple instances, setInstance() ties our hands. Moving to a non-singleton implementation would mean switching to a more complex API.


Dependency Injection By Hand


The dependency injection pattern aims in part to make unit testing easier. We don’t necessarily need a specialized framework to practice dependency injection. You can get roughly 80% of the benefit writing code by hand.

While the client asked the factory for a service in our previous example, with dependency injection, the client expects to have its dependency passed in. Don’t call me, I’ll call you, so to speak.


public class Client {
   
  private final Service service;

  public Client(Service service) {
    this.service = service;
  }

  public void go() {
    service.go();
  }
}


This simplifies our unit test considerably. We can just pass in a mock service and throw everything away when we’re done.



public void testClient() {
  MockService mock = new MockService();
  Client client = new Client(mock);
  client.go();
  assertTrue(mock.isGone());
}


We can also tell from the API exactly what the client depends on.

Now, how do we connect the client with a service? When implementing dependency injection by hand, we can move all dependency logic into factory classes. This means we need a factory for our client, too.



public static class ClientFactory {

  private ClientFactory() {}

  public static Client getInstance() {
    Service service = ServiceFactory.getInstance();
    return new Client(service);
  }
}


Implementing dependency injection by hand requires roughly the same number of lines of code as plain old factories.

Dependency Injection with Guice


Writing factories and dependency injection logic by hand for every service and client can become tedious. Some other dependency injection frameworks even require you to explicitly map services to the places where you want them injected.

Guice aims to eliminate all of this boilerplate without sacrificing maintainability.

With Guice, you implement modules. Guice passes a binder to your module, and your module uses the binder to map interfaces to implementations. The following module tells Guice to map Service to ServiceImpl in singleton scope:


public class MyModule implements Module {
  public void configure(Binder binder) {
    binder.bind(Service.class)
      .to(ServiceImpl.class)
      .in(Scopes.SINGLETON);
  }
}


A module tells Guice what we want to inject. Now, how do we tell Guice where we want it injected? With Guice, you annotate constructors, methods and fields with @Inject.



public class Client {

  private final Service service;

  @Inject
  public Client(Service service) {
    this.service = service;
  }

  public void go() {
    service.go();
  }
}


The @Inject annotation makes it clear to a programmer editing your class which members are injected.

For Guice to inject Client, we must either directly ask Guice to create a Client instance for us, or some other class must have Client injected into it.

Guice vs. Dependency Injection By Hand


As you can see, Guice saves you from having to write factory classes. You don’t have to write explicit code wiring clients to their dependencies. If you forget to provide a dependency, Guice fails at startup. Guice handles circular dependencies automatically.

Guice enables you to specify scopes declaratively. For example, you don’t have to write the same code to store an object in the HttpSession over and over.

In the real world, you often don’t know an implementation class until runtime. You need meta factories or service locators for your factories. Guice addresses these problems with minimal effort.

When injecting dependencies by hand, you can easily slip back into old habits and introduce direct dependencies, especially if you’re new to the concept of dependency injection. Using Guice turns the tables and makes doing the right thing easier. Guice helps keep you on track.

More Annotations


When possible, Guice enables you to use annotations in lieu of explicit bindings and eliminate even more boilerplate code. Back to our example, if you need an interface to simplify unit testing but you don’t care about compile time dependencies, you can point to a default implementation directly from your interface.


@ImplementedBy(ServiceImpl.class)
public interface Service {
  void go();
}


If a client needs a Service and Guice can’t find an explicit binding, Guice will inject an instance of ServiceImpl.

By default, Guice injects a new instance every time. If you want to specify a different scope, you can annotate the implementation class, too.



@Singleton
public class ServiceImpl implements Service {
  public void go() {
    …
  }
}

Architectural Overview


We can break Guice’s architecture down into two distinct stages: startup and runtime. You build an Injector during startup and use it to inject objects at runtime.

Startup


You configure Guice by implementing Module. You pass Guice a module, Guice passes your module a Binder, and your module uses the binder to configure bindings. A binding most commonly consists of a mapping between an interface and a concrete implementation. For example:


public class MyModule implements Module {
  public void configure(Binder binder) {
    // Bind Foo to FooImpl. Guice will create a new
    // instance of FooImpl for every injection.
    binder.bind(Foo.class)
.to(FooImpl.class);

    // Bind Bar to an instance of Bar.
    Bar bar = new Bar();
    binder.bind(Bar.class).toInstance(bar);
  }
}


Guice can look at the classes you tell it about during this stage and any classes those classes know about, and tell you whether or not you’re missing any dependencies. For example, in a Struts 2 application, Guice knows about all of your actions. Guice can validate your actions and anything they transitively depend on, and fail early if necessary.

Creating an Injector entails the following steps:






  1. First, create an instance of your module and pass it to Guice.createInjector().
  2. Guice creates a Binder and passes it to your module.
  3. Your module uses the binder to define bindings.
  4. Based on the bindings you specified, Guice creates an Injector and returns it to you.
  5. You use the injector to inject an object.

Runtime


We can now use the injector we created during the first stage to inject objects and introspect on our bindings. Guice’s runtime model consists of an injector which contains some number of bindings.





A Key uniquely identifies each binding. The key consists of a type which the client depends on and an optional annotation. You can use an annotation to differentiate multiple bindings to the same type. The key’s type and annotation correspond to the type and annotation at a point of injection.

Each binding has a provider which provides instances of the necessary type. You can provide a class, and Guice will create instances of it for you. You can give Guice an instance of the type you’re binding to. You can implement your own provider, and Guice can inject dependencies into it.

Each binding also has an optional scope. Bindings have no scope by default, and Guice creates a new instance for every injection. A custom scope enables you to control whether or not Guice creates a new instance. For example, you can create one instance per HttpSession.

Bootstrapping Your Application


The idea of bootstrapping is fundamental to dependency injection. Always explicitly asking the Injector for dependencies would be using Guice as a service locator, not a dependency injection framework.

Your code should deal directly with the Injector as little as possible. Instead, you want to bootstrap your application by injecting one root object. The container can further inject dependencies into the root object’s dependencies, and so on recursively. In the end, your application should ideally have one class (if that many) which knows about the Injector, and every other class should expect to have dependencies injected.

For example, a web application framework such as Struts 2 bootstraps your application by injecting all of your actions. You might bootstrap a web service framework by injecting your service implementation classes.

Dependency injection is viral. If you’re refactoring an existing code base with a lot of static methods, you may start to feel like you’re pulling a never-ending thread. This is a Good Thing. It means dependency injection is making your code more flexible and testable.

If you get in over your head, rather than try to refactor an entire code base all in one shot, you might temporarily store a reference to the Injector in a static field somewhere or use static injection. Name the field’s class clearly though: InjectorHack and GodKillsAKittenEveryTimeYouUseMe come to mind. Keep in mind that you you’ll have to mock this class, and your unit tests will have to install an Injector here by hand, and remember to clean up afterwards.

Binding Dependencies


How does Guice know what to inject? For starters, a Key composed of a type and an optional annotation uniquely identifies a dependency. Guice refers to the mapping between a key and an implementation as a Binding. An implementation can consist of a single object, a class which Guice should also inject, or a custom provider.


When injecting a dependency, Guice first looks for an explicit binding, a binding which you specified using the Binder. The Binder API uses the builder pattern to create a domain-specific expression language. Different methods return different objects depending on the context limiting you to appropriate methods.




For example, to bind an interface Service to a concrete implementation ServiceImpl, call:



binder.bind(Service.class).to(ServiceImpl.class);


This binding matches the following the method:



@Inject
void injectService(Service service) {
  …
}



Note: In contrast to some other frameworks, Guice gives no special treatment to “setter” methods. Guice will inject any method with any number of parameters so long as the method has an @Inject annotation, even if the method is in a superclass.

DRY (Don’t Repeat Yourself)


Repeating “binder” over and over for each binding can get a little tedious. Guice provides a Module support class named AbstractModule which implicitly gives you access to Binder‘s methods. For example, we could extend AbstractModule and rewrite the above binding as:


bind(Service.class).to(ServiceImpl.class);


We’ll use this syntax throughout the rest of the guide.


Annotating Bindings


If you need multiple bindings to the same type, you can differentiate the bindings with annotations.  For example, to bind an interface Service and annotation @Blue to the concrete implementation BlueService, call:


bind(Service.class)
  .annotatedWith(Blue.class)

  .to(BlueService.class);



This binding matches the following the method:



@Inject
void injectService(@Blue Service service) {
  …
}


Notice that while @Inject goes on the method, binding annotations such as @Blue go directly on the parameter. The same goes for constructors. When using field injection, both annotations can apply directly to the field, as in this example:


@Inject @Blue Service service;

Creating Binding Annotations



Where did this @Blue annotation just mentioned come from?  You can create such an annotation easily, although the standard incantation you have to use is unfortunately a little complex:


/**
 * Indicates we want the blue version of a binding.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER})
@BindingAnnotation
public @interface Blue {}

Luckily, we don’t really have to understand it all just to use it.  But for the curious, here’s what all this boilerplate means:



  • @Retention(RUNTIME) allows your annotation to be visible at runtime.
  • @Target({FIELD, PARAMETER}) is a courtesy to your users; it prevents @Blue from being applied to methods, types, local variables, and other annotations, where it would serve no purpose.
  • @BindingAnnotation is a Guice-specific signal that you wish your annotation to be used in this way.  Guice will produce an error whenever user applies more than one binding annotation to the same injectable element.

Annotations With Attributes


If you can get by with marker annotations alone, feel free to skip to the next section.

You can also bind to annotation instances, i.e. you can have multiple bindings with the same type and annotation type, but with different annotation attribute values. If Guice can’t find a binding to an annotation instance with the necessary attribute values, it will look for a binding to the annotation type instead.

Say for example we have a binding annotation @Named with a single string attribute value.
@Retention(RUNTIME)
@Target({ FIELD, PARAMETER })
@BindingAnnotation
public @interface Named {
String value();
}

If we want to bind to @Named(“Bob”), we first need an implementation of Named. Our implementation must abide by the Annotation contract, specifically the implementations of hashCode() and equals().
class NamedAnnotation implements Named {

final String value;

public NamedAnnotation(String value) {
this.value = value;
}

public String value() {
return this.value;
}

public int hashCode() {
// This is specified in java.lang.Annotation.
return 127 * “value”.hashCode() ^ value.hashCode();
}

public boolean equals(Object o) {
if (!(o instanceof Named))
return false;
Named other = (Named) o;
return value.equals(other.value());
}

public String toString() {
return “@” + Named.class.getName() + “(value=” + value + “)”;
}

public Class<? extends Annotation> annotationType() {
return Named.class;
}
}
Now we can use this annotation implementation to create bindings to @Named.


bind(Person.class)
  .annotatedWith(new NamedAnnotation(“Bob”))
  .to(Bob.class);


This may seem like a lot of work compared to string based identifiers used by other frameworks, but keep in mind that you can’t do this at all with string-based identifiers. Also, you’ll find that you get a lot of reuse out of binding annotations.

Since identifying a binding by name is such a common use case, Guice provides a production-worthy implementation of @Named in com.google.inject.name.


Implicit Bindings


As we saw in the introduction, you don’t always have to declare bindings explicitly. In the absence of an explicit binding, Guice will try to inject and create a new instance of the class you depend on. If you depend on an interface, Guice will look for an @ImplementedBy annotation which points to the concrete implementation. Take the following explicit binding to a concrete, injectable class named Concrete for example. It basically says, bind Concrete to Concrete. That’s explicit, but also a little redundant.


bind(Concrete.class);


Removing the binding above would not affect the behavior of this class:



class Mixer {

  @Inject
  Mixer(Concrete concrete) {
    …
  }
}


So, take your pick: explicit or brief. In the event of an error, Guice will produce helpful messages either way.

Injecting Providers


Sometimes a client needs multiple instances of a dependency per injection. Other times a client may not want to actually retrieve an object until some time after the actual injection (if at all). For any binding of type T, rather than inject an instance of T directly, you can inject a Provider<T>. Then call Provider<T>.get() as necessary. For example:


@Inject
void injectAtm(Provider<Money> atm) {
  Money one = atm.get();
  Money two = atm.get();
  …
}


As you can see, the Provider interface couldn’t get much simpler so it doesn’t get in the way of easy unit testing.


Injecting Constant Values


When it comes to constant values, Guice gives special treatment to several types:



  • Primitive types (int, char, …)
  • Primitive wrapper types (Integer, Character, …)
  • Strings
  • Enums
  • Classes

First, when binding to constant values of these types, you needn’t specify the type you’re binding to. Guice can figure it out from the value. For example, given a binding annotation named TheAnswer:


bindConstant().annotatedWith(TheAnswer.class).to(42);


Has the same effect as:



bind(int.class).annotatedWith(TheAnswer.class).toInstance(42);


When it comes time to inject a value of one of these types, if Guice can’t find an explicit binding for a primitive type, it will look for a binding to the corresponding wrapper type and vice versa.

Converting Strings



If Guice still can’t find an explicit binding for one of the above types, it will look for a constant String binding with the same binding annotation and try to convert its value. For example:


bindConstant().annotatedWith(TheAnswer.class).to(“42”); // String!


Will match:



@Inject @TheAnswer int answer;


When converting, Guice will try to look up enums and classes by name. Guice converts a value once at startup which also means you get up front type checking. This feature comes in especially handy if the binding value comes from a properties file for example.

Custom Providers


Sometimes you need to create your objects manually rather than let Guice create them. For example, you might not be able to add @Inject annotations to the implementation class as it came from a 3rd party. In these cases, you can implement a custom Provider. Guice can even inject your provider class. For example:


class WidgetProvider implements Provider<Widget> {

  final Service service;

  @Inject
  WidgetProvider(Service service) {
    this.service = service;
  }

  public Widget get() {
    return new Widget(service);
  }
}


You bind Widget to WidgetProvider like so:



bind(Widget.class).toProvider(WidgetProvider.class);


Injecting the custom providers enables Guice to check the types and dependencies up front. Custom providers can reside in any scope independent of the scope of the objects they provide. By default, Guice creates a new provider instance for every injection. In the above example, if each Widget needs its own instance of Service, our code will work fine. You can specify a different scope for a custom factory using a scope annotation on the factory class or by creating a separate binding for the factory.

Example: Integrating With JNDI


Say for example we want to bind to objects from JNDI. We could implement a reusable custom provider similar to the one below. Notice we inject the JNDI Context:


package mypackage;

import com.google.inject.*;
import javax.naming.*;

class JndiProvider<T> implements Provider<T> {

  @Inject Context context;
  final String name;
  final Class<T> type;

  JndiProvider(Class<T> type, String name) {
    this.name = name;
    this.type = type;
  }

  public T get() {
    try {
      return type.cast(context.lookup(name));
    }
    catch (NamingException e) {
      throw new RuntimeException(e);
    }
  }

  /**
   * Creates a JNDI provider for the given
   * type and name.
   */
  static <T> Provider<T> fromJndi(
      Class<T> type, String name) {
    return new JndiProvider<T>(type, name);
  }
}


Thanks to generic type erasure, we must pass in the class at runtime. You could skip this step, but tracking down type casting errors later might be a little tricky (i.e. if JNDI returns an object of the wrong type).

We can use our custom JndiProvider to bind DataSource to an object from JNDI:



import com.google.inject.*;
import static mypackage.JndiProvider.fromJndi;
import javax.naming.*;
import javax.sql.DataSource;



// Bind Context to the default InitialContext.

bind(Context.class).to(InitialContext.class);

// Bind to DataSource from JNDI.
bind(DataSource.class)
    .toProvider(fromJndi(DataSource.class, “…”));

Scoping Bindings


By default, Guice creates a new object for every injection. We refer to this as having “no scope.” You can specify a scope when you configure a binding. For example, to inject the same instance every time:


bind(MySingleton.class).in(Scopes.SINGLETON);


As an alternative, you can use an annotation on your implementation class to specify the scope. Guice supports @Singleton by default:



@Singleton
class MySingleton {
  …
}


The annotation approach works with implicit bindings as well but requires that Guice create your objects. On the other hand, calling in() works with almost any binding type (binding to a single instance being an obvious exception) and overrides annotations when present. in() also accepts annotations if you don’t want a compile time dependency on your scope implementation.




Specify annotations for custom scopes using Binder.bindScope(). For example, given an annotation @SessionScoped and a Scope implementation ServletScopes.SESSION:




binder.bindScope(SessionScoped.class, ServletScopes.SESSION);

Creating Scope Annotations



Annotations used for scoping should:



  • Have a @Retention(RUNTIME) annotation so we can see the annotation at runtime.

  • Have a @Target({TYPE}) annotation. Scope annotations only apply to implementation classes..

  • Have a @ScopeAnnotation meta-annotation. Only one such annotation can apply to a given class.


For example:


/**
 * Scopes bindings to the current transaction.
 */
@Retention(RUNTIME)
@Target({TYPE})
@ScopeAnnotation
public @interface TransactionScoped {}

Eagerly Loading Bindings


Guice can wait to load singleton objects until you actually need them. This helps speed up development because your application starts faster and you only initialize what you need. However, sometimes you always want to load an object at startup. You can tell Guice to always eagerly load a singleton like so:


bind(StartupTask.class).asEagerSingleton();


We frequently use this to implement initialization logic for our application. You can control the ordering of your initialization by creating dependencies on singletons which Guice must instantiate first.

Injecting Between Scopes


You can safely inject objects from a larger scope into an object from a smaller scope, or the same scope. For example, you can inject an Http session-scoped object into an HTTP request-scoped object. However, injecting into objects with larger scopes is a different story. For example, if you injected a request-scoped object into a singleton, at best, you would get an error due to not running within an HTTP request, and at worst your singleton object would always reference an object from the first request. In these cases, you should inject a Provider<T> instead and use it to retrieve the object from the smaller scope as necessary.  Then, you should be certain to never invoke this provider when you are outside of T‘s scope (for example, when you are not servicing an HTTP request, and T is request-scoped).

Development Stages


Guice is aware that your application goes through different stages of development. You can tell it which stage the application is running in when you create a container. Guice currently supports “development” and “production.” We’ve found that tests usually fall under one stage or the other.

During development, Guice will load singleton objects on demand. This way, your application starts up fast and only loads the parts you’re testing.

In production, Guice will load all your singleton objects at startup. This helps catch errors early and takes any performance hits up front.

Your modules can also apply method interceptors and other bindings based on the current stage. For example, an interceptor might verify that you don’t use your objects out of scope during development.

Intercepting Methods


Guice supports simple method interception using the AOP Alliance API. You can bind interceptors from your modules using Binder. For example, to apply a transaction interceptor to methods annotated with @Transactional:


import static com.google.inject.matcher.Matchers.*;



binder.bindInterceptor(
  any(),                              // Match classes.
  annotatedWith(Transactional.class), // Match methods.
  new TransactionInterceptor()        // The interceptor.
);



Try to shoulder as much of the filtering as is possible on the matchers rather than in the interceptor’s body as the matching code runs only once at startup.


Static Injection


Static fields and methods make testing and reusing more difficult, but there are times where your only choice is to keep a static reference to the Injector.

For these situations, Guice supports injecting less accessible static members. For example, HTTP session objects often need to be serializable to support replication, but what if your session object depends on a container-scoped object? We can keep a transient reference to the object, but how do we look it up again upon deserialization?

We’ve found the most pragmatic solution to be static injection:


@SessionScoped
class User {

  @Inject
  static AuthorizationService authorizationService;
  …
}


Guice never performs static injection automatically.  You must use Binder to explicitly request that the Injector inject your static members after startup:




binder.requestStaticInjection(User.class);


Static injection is a necessary evil, which makes testing more difficult.  If you can find a way to avoid using it, you’ll probably be glad you did.

Optional Injection


Sometimes your code should work whether a binding exists or not. In these cases, you can use @Inject(optional=true) and Guice can override your default implementation with a bound implementation when available. For example:


@Inject(optional=true) Formatter formatter = new DefaultFormatter();


If someone creates a binding for Formatter, Guice will inject an instance from that binding. Otherwise, assuming Formatter isn’t injectable itself (see Implicit Bindings), Guice will skip the optional member.

Optional injection applies only to fields and methods, not constructors. In the case of methods, if a binding for one parameter is missing, Guice won’t inject the method at all, even if bindings to other parameters are available.

Binding to Strings


We try to avoid using strings whenever possible as they’re prone to misspellings, not tool friendly, and so on, but using strings instead of creating custom annotations can prove useful for quick and dirty code. For these situations, Guice provides @Named and Names. For example, a binding to a string name like:


import static com.google.inject.name.Names.*;



bind(named(“bob”)).to(10);


Will match injection points like:



@Inject @Named(“bob”) int score;

Struts 2 Support


To install the Guice Struts 2 plugin with Struts 2.0.6 or later, simply include guice-struts2-plugin-1.0.jar in your web application’s classpath and select Guice as your ObjectFactory implementation in your struts.xml file:


<constant name=”struts.objectFactory” value=”guice” />


Guice will inject all of your Struts 2 objects including actions and interceptors. You can even scope your actions. You can optionally specify a Module for Guice to install in your struts.xml file:



<constant name=”guice.module” value=”mypackage.MyModule”/>


If all of your bindings are implicit, you can get away without defining a module at all.

A Counting Example


Say for example that we want to count the number of requests in a session. Define a Counter object which will live on the session:


@SessionScoped
public class Counter {

  int count = 0;

  /** Increments the count and returns the new value. */
  public synchronized int increment() {
    return count++;
  }
}


Next, we can inject our counter into an action:



public class Count {

  final Counter counter;

  @Inject
  public Count(Counter counter) {
    this.counter = counter;
  }

  public String execute() {
    return SUCCESS;
  }

  public int getCount() {
    return counter.increment();
  }
}


Then create a mapping for our action in our struts.xml file:



<action name=”Count”
    class=”mypackage.Count”>
  <result>/WEB-INF/Counter.jsp</result>
</action>     


And a JSP to render the result:



<%@ taglib prefix=”s” uri=”/struts-tags” %>

<html>  
  <body>
    <h1>Counter Example</h1>
    <h3><b>Hits in this session:</b>
      <s:property value=”count”/></h3>
  </body>
</html>


We actually made this example more complicated than necessary in an attempt to illustrate more concepts. In reality, we could have done away with the separate Counter object and applied @SessionScoped to our action directly.

JMX Integration


See com.google.inject.tools.jmx.


Appendix: How the Injector resolves injection requests


The injector’s process of resolving an injection request depends on the bindings that have been made and the annotations found on the types involved.  Here is a summary of how an injection request is resolved:





  1. Observe the Java type and the optional “binding annotation” of the element to be injected. If the type is com.google.inject.Provider<T>, perform resolution for the type indicated by T instead.  Find a binding for this (type, annotation) pair. If none, skip to #4.
  2. Follow transitive bindings. If this binding links to another binding, follow this edge and check again, repeating until we reach a binding which does not link to any other binding. We are now at the most specific explicit binding for this injection request.
  3. If this binding specifies an instance or a Provider instance, we’re done; use this to fulfill the request.
  4. If, at this point, the injection request used an annotation type or value, we have failed and we produce an error.

  5. Otherwise examine the Java type for this binding; if an @ImplementedBy annotation is found, instantiate the referenced type.  If a @ProvidedBy annotation is found, instantiate the referenced provider and use it to obtain the desired object. Otherwise attempt to instantiate the type itself.