<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Ryan&#039;s note</title>
	<atom:link href="http://www.ryanote.com/feed" rel="self" type="application/rss+xml" />
	<link>http://www.ryanote.com</link>
	<description>IT生活笔记:沉淀经验,分享感悟</description>
	<lastBuildDate>Wed, 23 Mar 2011 08:37:04 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
		
<!-- Start Of Script Generated By WP-PostViews Plus -->
<script type='text/javascript' src='http://www.ryanote.com/wordpress/wp-includes/js/jquery/jquery.js?ver=1.3.2'></script>
<script type="text/javascript">
/* <![CDATA[ */
/* ]]> */
</script>
<!-- End Of Script Generated By WP-PostViews Plus -->
	<item>
		<title>HTTP缓存解析</title>
		<link>http://www.ryanote.com/archives/181</link>
		<comments>http://www.ryanote.com/archives/181#comments</comments>
		<pubDate>Wed, 23 Mar 2011 08:37:03 +0000</pubDate>
		<dc:creator>Ryan</dc:creator>
				<category><![CDATA[客户端优化]]></category>
		<category><![CDATA[性能优化]]></category>
		<category><![CDATA[cache]]></category>
		<category><![CDATA[header]]></category>
		<category><![CDATA[http]]></category>

		<guid isPermaLink="false">http://www.ryanote.com/?p=181</guid>
		<description><![CDATA[刷新和输入网址后回车的区别

强制刷新(ctrl+F5):不理会缓存协商,全部重新获取.此时请求中的Cache-Control值为no-cache
刷新(F5)时:当点击浏览器上的刷新，客户端发送的请求中的Cache-Control均是max-age=0，表示validate操作，发送请求到服务器要求检查cache，再更新cache，一般得到的是304 Not Modified，表示没变动
输入网址直接回车时:如果Expired或Cache-Control还未过期,则不会返回304状态，因为浏览器已经不用向web服务器发出请求

Expires与Cache-Control的区别

给静态资源(HTML文件，图片文件等）加上Expires/Cache-Control Header。如果HTTP Response中有Expires这样的Header的话，浏览器会Cache这个资源，理想状况下（注意，只是理想状况），在Expire Date之前，不会再发HTTP请求给Server要这个资源，不过Expires的值只能是一个固定日期，比如“Thu 27 Nov 2008 07:00:00 GMT”，不能是一个类似“从现在开始之后10年”这样一个随机浮动的值，如果要这样的效果，可以用Cache-Control这样的Header，如果HTTP Resposne中有这样的Header:“Cache-Control: max-age = 100”，表示这个资源在cache中的最大寿命是100秒。
同一个HTTP Response中可以同时有Expires和Cache-Control，但是Cache-Control权限比Expires大，会override它的。
HTTP/1.0有一个功能比较弱的缓存控制机制：Pragma，使用HTTP/1.0的缓存将忽略Expires和Cache-Control头。

Last-modified/If-Modified-Since与Etag/If-None-Match区别

HTTP的Response中还会有另外一个Header叫Last-Modified，比如“Last-Modified:  Thu, 06 Apr 2006 21:17:12 GMT”，浏览器访问一个URI得到这样的Resposne之后，就知道这个资源最后一次的修改时间，下次需要再次获得这个资源的时候，会发一个Request给Server，不过这个Request中有一条“If-Unmodified-Since: Thu, 06 Apr 2006 21:17:12 GMT”，如果在Server端在这个日期之后对这个资源进行了修改，就会照常返回这个资源给Client端，但是如果没有修改，就会返回一个304 (Not Modified) Response而不返回资源，告诉Client端：“这个资源从上次给你之来从来没改过，你放心用你Cache中的好了。” 一个304 Response比一个静态资源通常小多了，这样就节省了网络带宽。
除了Last-Modified，HTTP Response中还可能有另外一个Header: ETag。在多台负载均衡的服务器环境下，同一个文件可能会有不同的etag或者文件修改日期，浏览器每次都会重新下载，这点要根据实际情况考虑设置。
比较一下Expires和Last-Modified这两个东西，似乎Last-Modified比不上Expires，因为虽然它能够节省一点带宽，但是还是逃不掉发一个HTTP请求出去，而Expires却使得浏览器干脆连HTTP请求都不用发。不过当用户在IE或者Firefox里面按F5或者点击Refresh按钮的时候（不是在URL栏里重新输入一遍URL然后回车），就算对于有Expires的URI，一样也会发一个HTTP请求出去，所以，Last-Modified还是要用的（返回304），而且要和Expires一起用。

Apache配置

 在expires.conf设置expires，加了expires后，Cache-Control也会有相应换算后的值

&#60;IfModule mod_expires.c&#62;
ExpiresActive On
ExpiresByType image/gif &#34;access plus 1 hour&#34;
ExpiresByType image/jpeg &#34;access plus 2 hour&#34;
&#60;/IfModule&#62;


对于一般的纯静态页面，如html、gif、jpg、css、js，默认安装的Apache服务器，不会在响应头添加这个字段。
 Firefox浏览器接受到相应请求后，如果发现没有Expires字段，浏览器根据文件的类型和“Last-Modified”字段来推断出一个合适的失效时间，并存储在客户端（Firefox的缓存），推测出的时间一般是接受到响应时间后的三天左右，以后的请求就可以根据Firefox的缓存过期时间（而非http指定）来决定是否使用客户端缓存。
 Apache服务器默认情况下，会对所有的静态、动态文件的响应头添加ETag字段。如果要关闭ETag，对于Apache，在httpd.conf或者.htaccess中加一行就搞定了:FileETag none
 无论是纯静态页面还是动态页面，Firefox浏览器巧妙地按照接受到服务器响应的时间设置缓存页面的Last-Modified（Firefox的缓存），而不是按照http响应头部中的Last-Modified字段。
 一般纯静态页面本身都会有Last-Modified信息，Apache服务器会读取页面文件中的Last-Modified信息，并添加到http响应头部。

对于动态页面，如果在页面内部没有通过函数强制加上Expires，例如header(”Expires:”。 gmdate(”D， [...]]]></description>
			<content:encoded><![CDATA[<h3>刷新和输入网址后回车的区别</h3>
<ol>
<li>强制刷新(ctrl+F5):不理会缓存协商,全部重新获取.此时请求中的Cache-Control值为no-cache</li>
<li>刷新(F5)时:当点击浏览器上的刷新，客户端发送的请求中的Cache-Control均是max-age=0，表示validate操作，发送请求到服务器要求检查cache，再更新cache，一般得到的是304 Not Modified，表示没变动</li>
<li>输入网址直接回车时:如果Expired或Cache-Control还未过期,则不会返回304状态，因为浏览器已经不用向web服务器发出请求</li>
</ol>
<h3>Expires与Cache-Control的区别</h3>
<ol>
<li>给静态资源(HTML文件，图片文件等）加上Expires/Cache-Control Header。如果HTTP Response中有Expires这样的Header的话，浏览器会Cache这个资源，理想状况下（注意，只是理想状况），在Expire Date之前，不会再发HTTP请求给Server要这个资源，不过Expires的值只能是一个固定日期，比如“Thu 27 Nov 2008 07:00:00 GMT”，不能是一个类似“从现在开始之后10年”这样一个随机浮动的值，如果要这样的效果，可以用Cache-Control这样的Header，如果HTTP Resposne中有这样的Header:“Cache-Control: max-age = 100”，表示这个资源在cache中的最大寿命是100秒。</li>
<li>同一个HTTP Response中可以同时有Expires和Cache-Control，但是Cache-Control权限比Expires大，会override它的。</li>
<li>HTTP/1.0有一个功能比较弱的缓存控制机制：Pragma，使用HTTP/1.0的缓存将忽略Expires和Cache-Control头。</li>
</ol>
<h3>Last-modified/If-Modified-Since与Etag/If-None-Match区别</h3>
<ol>
<li>HTTP的Response中还会有另外一个Header叫Last-Modified，比如“Last-Modified:  Thu, 06 Apr 2006 21:17:12 GMT”，浏览器访问一个URI得到这样的Resposne之后，就知道这个资源最后一次的修改时间，下次需要再次获得这个资源的时候，会发一个Request给Server，不过这个Request中有一条“If-Unmodified-Since: Thu, 06 Apr 2006 21:17:12 GMT”，如果在Server端在这个日期之后对这个资源进行了修改，就会照常返回这个资源给Client端，但是如果没有修改，就会返回一个304 (Not Modified) Response而不返回资源，告诉Client端：“这个资源从上次给你之来从来没改过，你放心用你Cache中的好了。” 一个304 Response比一个静态资源通常小多了，这样就节省了网络带宽。</li>
<li>除了Last-Modified，HTTP Response中还可能有另外一个Header: ETag。在多台负载均衡的服务器环境下，同一个文件可能会有不同的etag或者文件修改日期，浏览器每次都会重新下载，这点要根据实际情况考虑设置。</li>
<li>比较一下Expires和Last-Modified这两个东西，似乎Last-Modified比不上Expires，因为虽然它能够节省一点带宽，但是还是逃不掉发一个HTTP请求出去，而Expires却使得浏览器干脆连HTTP请求都不用发。不过当用户在IE或者Firefox里面按F5或者点击Refresh按钮的时候（不是在URL栏里重新输入一遍URL然后回车），就算对于有Expires的URI，一样也会发一个HTTP请求出去，所以，Last-Modified还是要用的（返回304），而且要和Expires一起用。</li>
</ol>
<h3>Apache配置</h3>
<ol>
<li> 在expires.conf设置expires，加了expires后，Cache-Control也会有相应换算后的值
<pre class="brush: xml;">
&lt;IfModule mod_expires.c&gt;
ExpiresActive On
ExpiresByType image/gif &quot;access plus 1 hour&quot;
ExpiresByType image/jpeg &quot;access plus 2 hour&quot;
&lt;/IfModule&gt;
</pre>
</li>
<p>对于一般的纯静态页面，如html、gif、jpg、css、js，默认安装的Apache服务器，不会在响应头添加这个字段。</p>
<li> Firefox浏览器接受到相应请求后，如果发现没有Expires字段，浏览器根据文件的类型和“Last-Modified”字段来推断出一个合适的失效时间，并存储在客户端（Firefox的缓存），推测出的时间一般是接受到响应时间后的三天左右，以后的请求就可以根据Firefox的缓存过期时间（而非http指定）来决定是否使用客户端缓存。</li>
<li> Apache服务器默认情况下，会对所有的静态、动态文件的响应头添加ETag字段。如果要关闭ETag，对于Apache，在httpd.conf或者.htaccess中加一行就搞定了:FileETag none</li>
<li> 无论是纯静态页面还是动态页面，Firefox浏览器巧妙地按照接受到服务器响应的时间设置缓存页面的Last-Modified（Firefox的缓存），而不是按照http响应头部中的Last-Modified字段。</li>
<li> 一般纯静态页面本身都会有Last-Modified信息，Apache服务器会读取页面文件中的Last-Modified信息，并添加到http响应头部。</li>
<li>
对于动态页面，如果在页面内部没有通过函数强制加上Expires，例如header(”Expires:”。 gmdate(”D， d M Y H:i:s”) 。 ”GMT”)，Apache服务器会把Wed， 11 Jan 1984 05:00:00 GMT作为Expires字段内容，返回给浏览器。</li>
<li> 对于动态页面，如果在页面内部没有通过函数强制加上Last-Modified，例如header(”Last-Modified: ” 。 gmdate(”D， d M Y H:i:s”) 。 ”GMT”)，Apache服务器会把当前时间作为Last-Modified，返回给浏览器。</li>
<li> 关闭Last-modified
<pre class="brush: xml;">
LoadModule headers_module modules/mod_headers.so

&lt;FilesMatch &quot;\.(gif|jpg|png)&quot;&gt;
Header unset Last-Modified
&lt;/FilesMatch&gt;
</pre>
</li>
<li> 开启gzip
<pre class="brush: xml;">
&lt;ifmodule mod_deflate.c&gt;
DeflateCompressionLevel 9
AddOutputFilterByType DEFLATE text/html text/plain text/xml application/x-httpd-php
AddOutputFilter DEFLATE js css
&lt;/ifmodule&gt;
</pre>
</li>
</ol>
<div style="margin-top: 25px;color:#666; ">
<p><strong>原创文章，转载请注明：</strong> 转载自<a href="http://www.ryanote.com/wordpress/">Ryan&#039;s note</a></p>
<p><strong>本文链接地址:</strong> <a href="http://www.ryanote.com/archives/181">HTTP缓存解析</a></p>
</div>
<h2  class="related_post_title">热门日志</h2><ul class="related_post"><li><a href="http://www.ryanote.com/archives/68" title="我的技术旅程(一)">我的技术旅程(一)</a></li><li><a href="http://www.ryanote.com/archives/145" title="终于成为本本一族！">终于成为本本一族！</a></li><li><a href="http://www.ryanote.com/%e5%85%b3%e4%ba%8e" title="关于">关于</a></li><li><a href="http://www.ryanote.com/archives/158" title="揭秘Java中的String">揭秘Java中的String</a></li><li><a href="http://www.ryanote.com/archives/11" title="5个你必须掌握的maven命令">5个你必须掌握的maven命令</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.ryanote.com/archives/181/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>打造自己专用的.vimrc</title>
		<link>http://www.ryanote.com/archives/173</link>
		<comments>http://www.ryanote.com/archives/173#comments</comments>
		<pubDate>Thu, 02 Sep 2010 11:29:26 +0000</pubDate>
		<dc:creator>Ryan</dc:creator>
				<category><![CDATA[Vim]]></category>
		<category><![CDATA[vimrc]]></category>

		<guid isPermaLink="false">http://www.ryanote.com/?p=173</guid>
		<description><![CDATA[使用了一段时间的vim后，感觉越用越好用，它的操作完全颠覆了以往编辑文本的习惯，编辑文本不再枯燥，完全成了一种享受。尤其是它的可定制性真让人欲罢不能，下面我把自己目前用的.vimrc配置文件与大家分享，因为用Vim没多久，这份配置还有很多不足之处，但我还是希望大家能从中获益，做一个快乐的vimmer! 如有其它好的配置，还请不吝赐教 ：)

&#34;关闭与vi的兼容模式
set nocp &#34;nocompatible
&#34;搜索结果高亮
set hls &#34;hlsearch
&#34;增量搜索
set is &#34;incsearch
&#34;显示行号
set nu  &#34;number
&#34;退格删除indent,eol,start
set backspace=indent,eol,start
&#34;按h,l时，如果到头，则跳到上一行或下一行
set whichwrap=h,l
&#34;关闭备份
set nobackup
&#34;高亮显示光标所在行
set cursorline
&#34;禁用鼠标点击时的虚拟选中模式
set mouse-=a
&#34;tab键对应的字符宽度
set tabstop=4 &#34;ts
&#34;自动缩进时的字符宽度
set shiftwidth=4 &#34;sw
&#34;自动将Tab转化为对应宽度的空格
set et &#34;noexpandtab
&#34;当使用et将Tab替换为空格之后,不用按Backspace多次， 按一下即可
set smarttab
&#34;自动缩进
set autoindent
&#34;防止特殊符号无法正常显示。 在 Unicode 中， 许多来自不同语言的字符， 如果字型足够近似的话， 会把它们放在同一个编码中。 但在不同编码中， 字符的宽度是不一样的。
set ambiwidth=double
&#34;自动切换当前目录
set autochdir
&#34;设置当前字符编码为 UTF-8
set encoding=utf-8
&#34;设置菜单语言和编码
set langmenu=zh_CN.UTF-8
&#34;设置提示信息的语言和编码
language messages zh_CN.utf-8
&#34;设置编码的自动识别
set fileencodings=utf-8,gbk,chinese,latin-1
&#34;语法高亮
syntax on
&#34;开启文件类型自动识别， 启用文件类型插件， 启用针对文件类型的自动缩进
filetype plugin indent on

&#34;设置tag list插件
let Tlist_Ctags_Cmd=&#34;E:/Vim/vim72/ctags.exe&#34;
let Tlist_Use_Right_Window=1
let Tlist_Auto_Open=0

&#34;关闭菜单和工具栏，以最大化可视范围
set guioptions-=m
set guioptions-=T

&#34;使用主题
colorscheme	lucius 

&#34;键绑定
map [...]]]></description>
			<content:encoded><![CDATA[<p>使用了一段时间的vim后，感觉越用越好用，它的操作完全颠覆了以往编辑文本的习惯，编辑文本不再枯燥，完全成了一种享受。尤其是它的可定制性真让人欲罢不能，下面我把自己目前用的.vimrc配置文件与大家分享，因为用Vim没多久，这份配置还有很多不足之处，但我还是希望大家能从中获益，做一个快乐的vimmer! 如有其它好的配置，还请不吝赐教 ：)</p>
<pre class="brush: vb;">
&quot;关闭与vi的兼容模式
set nocp &quot;nocompatible
&quot;搜索结果高亮
set hls &quot;hlsearch
&quot;增量搜索
set is &quot;incsearch
&quot;显示行号
set nu  &quot;number
&quot;退格删除indent,eol,start
set backspace=indent,eol,start
&quot;按h,l时，如果到头，则跳到上一行或下一行
set whichwrap=h,l
&quot;关闭备份
set nobackup
&quot;高亮显示光标所在行
set cursorline
&quot;禁用鼠标点击时的虚拟选中模式
set mouse-=a
&quot;tab键对应的字符宽度
set tabstop=4 &quot;ts
&quot;自动缩进时的字符宽度
set shiftwidth=4 &quot;sw
&quot;自动将Tab转化为对应宽度的空格
set et &quot;noexpandtab
&quot;当使用et将Tab替换为空格之后,不用按Backspace多次， 按一下即可
set smarttab
&quot;自动缩进
set autoindent
&quot;防止特殊符号无法正常显示。 在 Unicode 中， 许多来自不同语言的字符， 如果字型足够近似的话， 会把它们放在同一个编码中。 但在不同编码中， 字符的宽度是不一样的。
set ambiwidth=double
&quot;自动切换当前目录
set autochdir
&quot;设置当前字符编码为 UTF-8
set encoding=utf-8
&quot;设置菜单语言和编码
set langmenu=zh_CN.UTF-8
&quot;设置提示信息的语言和编码
language messages zh_CN.utf-8
&quot;设置编码的自动识别
set fileencodings=utf-8,gbk,chinese,latin-1
&quot;语法高亮
syntax on
&quot;开启文件类型自动识别， 启用文件类型插件， 启用针对文件类型的自动缩进
filetype plugin indent on

&quot;设置tag list插件
let Tlist_Ctags_Cmd=&quot;E:/Vim/vim72/ctags.exe&quot;
let Tlist_Use_Right_Window=1
let Tlist_Auto_Open=0

&quot;关闭菜单和工具栏，以最大化可视范围
set guioptions-=m
set guioptions-=T

&quot;使用主题
colorscheme	lucius 

&quot;键绑定
map &lt;F3&gt; gg=G``
map &lt;F4&gt; ggvGy``
map &lt;C-F5&gt; &quot;+y
map &lt;C-F6&gt; &quot;+p
</pre>
<div style="margin-top: 25px;color:#666; ">
<p><strong>原创文章，转载请注明：</strong> 转载自<a href="http://www.ryanote.com/wordpress/">Ryan&#039;s note</a></p>
<p><strong>本文链接地址:</strong> <a href="http://www.ryanote.com/archives/173">打造自己专用的.vimrc</a></p>
</div>
<h2  class="related_post_title">相关日志</h2><ul class="related_post"><li><a href="http://www.ryanote.com/archives/73" title="Linux下的vi(vim)命令大全">Linux下的vi(vim)命令大全</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.ryanote.com/archives/173/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>揭秘Java中的String</title>
		<link>http://www.ryanote.com/archives/158</link>
		<comments>http://www.ryanote.com/archives/158#comments</comments>
		<pubDate>Tue, 24 Aug 2010 12:16:55 +0000</pubDate>
		<dc:creator>Ryan</dc:creator>
				<category><![CDATA[Java语言]]></category>
		<category><![CDATA[Java技术]]></category>
		<category><![CDATA[String]]></category>

		<guid isPermaLink="false">http://www.ryanote.com/?p=158</guid>
		<description><![CDATA[最近有人问我一个问题：String是什么？

是什么？脑子一片混乱。不可变？不是基本数据类型但又像基本数据类型？顿时很多模糊的理解涌入脑海，怎么都理不清，究其原因，还是对String在JVM里的实现原理不甚理解。为了彻底搞清究竟什么是String,今天特意看了很多相关的资料，终于有所感悟，感悟之余，记录于此，与大家共享。]]></description>
			<content:encoded><![CDATA[<div>
<p>最近有人问我一个问题：String是什么？</p>
<p>是什么？脑子一片混乱。不可变？不是基本数据类型但又像基本数据类型？顿时很多模糊的理解涌入脑海，怎么都理不清，究其原因，还是对String在JVM里的实现原理不甚理解。为了彻底搞清究竟什么是String,今天特意看了很多相关的资料，终于有所感悟，感悟之余，记录于此，与大家共享。（部分内容抄摘自网上）</p>
<h2>一、创建String</h2>
<p>创建一个String对象，主要有两种方式：</p>
<ol>
<li>String s=&#8221;Hello world!&#8221;;</li>
<li>String s=new String(&#8220;Hello world&#8221;);</li>
</ol>
<p>两种方式虽然都实现了创建一个String对象的功能，但实现的原理却大不相同。在讨论这两种方法的不同之前，我们先来了解一下JVM里的常量池概念，对接下来的理解很有帮助。</p>
<p>相信大家都知道，Java程序在运行之前，编译器首先要把源代码编译成字节码文件（.class文件），然后JVM再解释执行.class文件。其中，在.class文件中有一个非常重要的项—常量池，我们上面代码中的&#8221;Hello world&#8221;字符串被编译之后，就被存放在class常量池中的字符串常量表中。改用网上一段话：</p>
<blockquote><p>在Java源代码中的每一个字面值字符串，都会在编译成class文件阶段，形成标志号 为8(CONSTANT_String_info)的常量表 。 当JVM加载 class文件的时候，会为对应的常量池建立一个内存数据结构，并存放在方法区中。同时JVM会自动为CONSTANT_String_info常量表中 的字符串常量字面值 在堆中创建 新的String对象(intern字符串对象）。然后把CONSTANT_String_info常量表的入口地址转变成这个堆中String对象的直接地址(常量池解析)。</p></blockquote>
<p>源代码中所有相同字面值的字符串常量只可能建立唯一一个intern字符串对象。另外，我们也可以调用String的intern()方法来使得一个常规字符串对象成为intern字符串对象。</p>
<p>好了，下面我们来讨论一下第一种方法，也是大家非常常用的方法：</p>
<p>String s=&#8221;Hello world!&#8221;</p>
<p>首先在编译期，也就是在运行这段指令之前，<span style="color: #ff0000;">JVM就已经为&#8221;Hello world&#8221;在堆中创建了一个intern字符串，局部变量s存储的是早已创建好的intern字符串的堆地址</span>。也就是说，不管有几条String s1=&#8221;Hello world&#8221;,堆中都只有1个值为&#8221;Hello world&#8221;的字符串。</p>
<p>那么第二种方法呢？</p>
<p>String s=new String(&#8220;Hello world&#8221;)</p>
<p>同样在编译期，JVM也为&#8221;Hello world&#8221;在堆中创建了一个intern字符串，然后<span style="color: #ff0000;">用这个intern字符串的值来初始化new出来的新String对象，局部变量s实际上存储的是new出来的堆对象地址。 此时在JVM管理的堆中，有两个相同字符串值的String对象：一个是intern字符串对象，一个是new新建的字符串对象。</span></p>
<p>最后，来段代码做个更形象的比较：</p>
<pre class="brush: java;">
//代码1
String sa = &quot;ab&quot;;
String sb = &quot;cd&quot;;
String sab=sa+sb;
String s=&quot;abcd&quot;;
System.out.println(sab==s); // false
//代码2
String sc=&quot;ab&quot;+&quot;cd&quot;;
String sd=&quot;abcd&quot;;
System.out.println(sc==sd); //true
</pre>
<p>代码1中局部变量sa,sb存储的是堆中两个intern字符串对象的地址。<span style="color: #0000ff;">而当执行sa+sb时，JVM首先会在堆中创建一个StringBuilder类，同时用sa指向的intern字符串对象完成初始化，然后调用append方法完成对sb所指向的intern字符串的合并操作，接着调用StringBuilder的toString()方法在堆中创建一个String对象，最后将刚生成的String对象的堆地址存放在局部变量sab中</span>。而局部变量s存储的是常量池中&#8221;abcd&#8221;所对应的intern字符串对象的地址。 sab与s地址当然不一样了。这里要注意了，代码1的堆中实际上有五个字符串对象：三个intern字符串对象、一个String对象和一个StringBuilder对象。<br />
代码2中&#8221;ab&#8221;+&#8221;cd&#8221;会直接在编译期就合并成常量&#8221;abcd&#8221;， 因此相同字面值常量&#8221;abcd&#8221;所对应的是同一个拘留字符串对象，自然地址也就相同。</p>
<h2>二、String,StringBuffer和StringBuilder</h2>
<ol>
<li>通过查看源码可以发现，String中的value[]是常量(final)数组，只能被赋值一次；而StringBuffer中的value[]就是一个很普通的数组，而且可以通过append()方法将新字符串加入value[]末尾。</li>
<li><span style="color: #0000ff;">StringBuffer和StringBuilder的区别是StringBuffer是线程安全的，而后者不是</span>。这是因为在源代码中StringBuffer的很多方法都被关键字synchronized 修饰了，而StringBuilder没有。另外，由于String是不可变的，也就是只读，自然也是安全的了。</li>
<li>因为String对象中的value[]是不能改变的，每一次合并后字符串值都需要创建一个新的String对象来存放。循环1000次自然需要创建1000个String对象和1000个StringBuilder对象，效率低就可想而知了；而StringBuffer/StringBuilder，只需要将自己的value[]数组不停的扩大来存放即可，循环过程中无需在堆中创建任何新的对象，效率自然就高了。</li>
</ol>
<h2>三、总结：</h2>
<ol>
<li>不停的创建对象是程序低效的一个重要原因。那么相同的字符串值能否在堆中只创建一个String对象？可以！除了程序中的字符串常量会被JVM自动创建拘留字符串之外，调用String的intern()方法也能做到这一点。当调用intern()时，如果常量池中已经有了当前String的值，那么返回这个常量指向intern对象的地址。如果没有，则将String值加入常量池中，并创建一个新的intern字符串对象。</li>
<li>String的种种行为都来源于它的immutable性. 因为它是不变的,没有线程安全问题,可以无限共享,池化当然最节省时间空间; 也因为它是不变的,用&#8221;+&#8221;导致N多的新对象生成，才生的效率问题.</li>
</ol>
<h2>四、知识补充:</h2>
<h3>equals 和 == 的区别</h3>
<ol>
<li>equals 方法（是String类从它的超类Object中继承的）被用来检测两个对象是否相等，即两个对象的内容是否相等。</li>
<li>==用于比较引用和比较基本数据类型时具有不同的功能：比较基本数据类型，如果两个值相同，则结果为true ; 在比较引用时，如果引用指向内存中的同一对象，结果为true</li>
</ol>
<h3>堆、栈与常量池：</h3>
<ol>
<li>栈：存放基本类型的变量数据和对象的引用，但对象本身不存放在栈中，而是存放在堆（new 出来的对象）或者常量池中（字符串常量对象存放在常量池中。）</li>
<li>堆：存放所有new出来的对象。</li>
<li>静态域：存放静态成员（static定义的）</li>
<li>常量池：存放字符串常量和基本类型常量（public static final）。</li>
</ol>
<p><span style="color: #0000ff;">栈和常量池中的对象可以共享，堆中的对象不可以共享。栈中的数据大小和生命周期是可以确定的，当没有引用指向数据时，这个数据就会消失。堆中的对象的由垃圾回收器负责回收，因此大小和生命周期不需要确定，具有很大的灵活性。<br />
字符串：其对象的引用都是存储在栈中的，如果是编译期已经创建好(直接用双引号定义的)的就存储在常量池中，如果是运行期（new出来的）才能确定的就存储在堆中。对于equals相等的字符串，在常量池中永远只有一份，在堆中有多份。</span></p>
</div>
<div style="margin-top: 25px;color:#666; ">
<p><strong>原创文章，转载请注明：</strong> 转载自<a href="http://www.ryanote.com/wordpress/">Ryan&#039;s note</a></p>
<p><strong>本文链接地址:</strong> <a href="http://www.ryanote.com/archives/158">揭秘Java中的String</a></p>
</div>
<h2  class="related_post_title">热门日志</h2><ul class="related_post"><li><a href="http://www.ryanote.com/archives/68" title="我的技术旅程(一)">我的技术旅程(一)</a></li><li><a href="http://www.ryanote.com/archives/145" title="终于成为本本一族！">终于成为本本一族！</a></li><li><a href="http://www.ryanote.com/%e5%85%b3%e4%ba%8e" title="关于">关于</a></li><li><a href="http://www.ryanote.com/archives/158" title="揭秘Java中的String">揭秘Java中的String</a></li><li><a href="http://www.ryanote.com/archives/11" title="5个你必须掌握的maven命令">5个你必须掌握的maven命令</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.ryanote.com/archives/158/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>你不能错过的Eclipse插件</title>
		<link>http://www.ryanote.com/archives/151</link>
		<comments>http://www.ryanote.com/archives/151#comments</comments>
		<pubDate>Tue, 17 Aug 2010 13:37:39 +0000</pubDate>
		<dc:creator>Ryan</dc:creator>
				<category><![CDATA[Eclipse]]></category>
		<category><![CDATA[插件]]></category>
		<category><![CDATA[plugin]]></category>

		<guid isPermaLink="false">http://www.ryanote.com/?p=151</guid>
		<description><![CDATA[
今天晚上估计要在公司待的很晚了，趁着一些任务在自动运行的间隙，抽空整理一下自己喜欢的一些eclipse插件：


spket:   http://www.spket.com/update
一款很好用的JS、XML编辑器， 有着很体贴的intellisense
vrapper(imitate vim): http://vrapper.sourceforge.net/update-site/stable
模拟VIM的一款插件，虽然和真正的VIM相比还少一些功能，但基本上一些常用的功能都有了，而且相比与eclim这个直接内嵌VIM的插件，它显得更为轻量，而且保留eclipse自身一些好用的快捷键。提示一下，在老版本的eclipse(ganymede)里，好像装不上。
subclipse: http://subclipse.tigris.org/update_1.6.x
相信用过SVN的人都会用过这款插件，有了这个，在eclipse操作SVN不但更方便，而且更直观。
eclemma: http://update.eclemma.org/
用于统计测试代码的覆盖率，可以帮助你找出遗漏的测试部分 。
veloeclipse：http://veloeclipse.googlecode.com/svn/trunk/update/
用velocity进行页面开发的话，那么eclipse自带的编辑器肯定满足不了你的需要，不但没着色，也没提示。而这款插件正好弥补了上述的不足，用过你就会喜欢上的。相比另一款velocity编辑插件， http://veloedit.sourceforge.net/updates/，它更为好用，并且不会像后者那样经常出现无法正常打开的现象。
findbugs：http://findbugs.cs.umd.edu/eclipse
顾名思义，是帮助你更快地找出代码里的Bugs的。用一下，你就能感受到它的神奇。
spring IDE: http://springide.org/updatesite/
大名鼎鼎的spring IDE,就不用多说了。


这次就先介绍这几个了，以后有发现更好的，我会及时与大家分享的。


原创文章，转载请注明： 转载自Ryan&#039;s note
本文链接地址: 你不能错过的Eclipse插件

热门日志我的技术旅程(一)终于成为本本一族！关于揭秘Java中的String5个你必须掌握的maven命令]]></description>
			<content:encoded><![CDATA[<div>
<p>今天晚上估计要在公司待的很晚了，趁着一些任务在自动运行的间隙，抽空整理一下自己喜欢的一些eclipse插件：</p>
<div id="_mcePaste">
<ol>
<li>spket:  <a href="http://www.spket.com/update" target="_blank"> http://www.spket.com/update</a><br />
一款很好用的JS、XML编辑器， 有着很体贴的intellisense</li>
<li>vrapper(imitate vim): <a href="http://vrapper.sourceforge.net/update-site/stable" target="_blank">http://vrapper.sourceforge.net/update-site/stable</a><br />
模拟VIM的一款插件，虽然和真正的VIM相比还少一些功能，但基本上一些常用的功能都有了，而且相比与eclim这个直接内嵌VIM的插件，它显得更为轻量，而且保留eclipse自身一些好用的快捷键。提示一下，在老版本的eclipse(ganymede)里，好像装不上。</li>
<li>subclipse: <a href="http://subclipse.tigris.org/update_1.6.x" target="_blank">http://subclipse.tigris.org/update_1.6.x</a><br />
相信用过SVN的人都会用过这款插件，有了这个，在eclipse操作SVN不但更方便，而且更直观。</li>
<li>eclemma:<a href=" http://update.eclemma.org/" target="_blank"> http://update.eclemma.org/</a><br />
用于统计测试代码的覆盖率，可以帮助你找出遗漏的测试部分 。</li>
<li>veloeclipse：<a href="http://veloeclipse.googlecode.com/svn/trunk/update/" target="_blank">http://veloeclipse.googlecode.com/svn/trunk/update/</a><br />
用velocity进行页面开发的话，那么eclipse自带的编辑器肯定满足不了你的需要，不但没着色，也没提示。而这款插件正好弥补了上述的不足，用过你就会喜欢上的。相比另一款velocity编辑插件， http://veloedit.sourceforge.net/updates/，它更为好用，并且不会像后者那样经常出现无法正常打开的现象。</li>
<li>findbugs：<a href="http://findbugs.cs.umd.edu/eclipse" target="_blank">http://findbugs.cs.umd.edu/eclipse</a><br />
顾名思义，是帮助你更快地找出代码里的Bugs的。用一下，你就能感受到它的神奇。</li>
<li>spring IDE: <a href="http://springide.org/updatesite/" target="_blank">http://springide.org/updatesite/</a><br />
大名鼎鼎的spring IDE,就不用多说了。</li>
</ol>
</div>
<p>这次就先介绍这几个了，以后有发现更好的，我会及时与大家分享的。</p>
</div>
<div style="margin-top: 25px;color:#666; ">
<p><strong>原创文章，转载请注明：</strong> 转载自<a href="http://www.ryanote.com/wordpress/">Ryan&#039;s note</a></p>
<p><strong>本文链接地址:</strong> <a href="http://www.ryanote.com/archives/151">你不能错过的Eclipse插件</a></p>
</div>
<h2  class="related_post_title">热门日志</h2><ul class="related_post"><li><a href="http://www.ryanote.com/archives/68" title="我的技术旅程(一)">我的技术旅程(一)</a></li><li><a href="http://www.ryanote.com/archives/145" title="终于成为本本一族！">终于成为本本一族！</a></li><li><a href="http://www.ryanote.com/%e5%85%b3%e4%ba%8e" title="关于">关于</a></li><li><a href="http://www.ryanote.com/archives/158" title="揭秘Java中的String">揭秘Java中的String</a></li><li><a href="http://www.ryanote.com/archives/11" title="5个你必须掌握的maven命令">5个你必须掌握的maven命令</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.ryanote.com/archives/151/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>终于成为本本一族！</title>
		<link>http://www.ryanote.com/archives/145</link>
		<comments>http://www.ryanote.com/archives/145#comments</comments>
		<pubDate>Sun, 09 May 2010 13:45:02 +0000</pubDate>
		<dc:creator>Ryan</dc:creator>
				<category><![CDATA[生活感悟]]></category>
		<category><![CDATA[y460]]></category>

		<guid isPermaLink="false">http://www.ryanote.com/?p=145</guid>
		<description><![CDATA[前几天由于自己的不小心,把跟了自己多年的台式机的主板给弄坏了,本来想去保修的,结果看了一下标签,保修期居然刚过了2个月,杯具啊&#8230;
其实早就想买本本了,只不过对那台式机有深厚的感情,而且一直工作地非常稳定,也不忍心将它打入冷宫.这一次虽然它受伤了,但我还是会把它救回来的,只不过接下来它要退居二线了.
小Y!一次不经意地懈逅,让我深深地爱上了它.它那时尚的外表,再加上强劲的配置,真让人欲罢不能.虽然它侧边那条橙色的条纹让我有点别扭,但瑕不掩瑜,仍然非常值得拥有.
昨天,y460被我收入囊中&#8230;特写篇博文记念一下:)

买来后,迫不及待试了一下它的卖点之一:JBL专业音响.果然名不虚传,比我那个创新的2.1还要好,音质清晰浑厚.大喜之外,还体验了一下许多酷酷的功能:slidebar的拉链式的锁屏效果与win7的aero效果相得益彰;双显卡一键切换的功能让我在性能和节能上能自由选择&#8230;.太多太多了,更多的功能还要在以后慢慢发掘.
其实买本本最主要的目的还是为了方便工作,由于今后的工作平台更多的会在linux下,于是,在体验了y460的几个主要功能后,我开始装上了久闻大名的lucid lynx(ubuntu 10.04 LTS),这只清醒的猞猁作为LTS版本,其重要性可见一斑.一改之前的土黄色，这一次用上了更为悦目清新的紫色，其特效丝毫不逊色于win7.而且与社区的结合非常紧密，像Twitter和Facebook都无缝地整合在里面，不过由于国情，这些功能就有点打折扣了.由于本篇博文是为了记念本本的到来,ubuntu的功能我就不详细介绍了。
我相信我会充分利用好如此优秀的装备，开启事业的新篇章，迎接更美好的未来。

原创文章，转载请注明： 转载自Ryan&#039;s note
本文链接地址: 终于成为本本一族！

热门日志我的技术旅程(一)终于成为本本一族！关于揭秘Java中的String5个你必须掌握的maven命令]]></description>
			<content:encoded><![CDATA[<p>前几天由于自己的不小心,把跟了自己多年的台式机的主板给弄坏了,本来想去保修的,结果看了一下标签,保修期居然刚过了2个月,杯具啊&#8230;</p>
<p>其实早就想买本本了,只不过对那台式机有深厚的感情,而且一直工作地非常稳定,也不忍心将它打入冷宫.这一次虽然它受伤了,但我还是会把它救回来的,只不过接下来它要退居二线了.</p>
<p>小Y!一次不经意地懈逅,让我深深地爱上了它.它那时尚的外表,再加上强劲的配置,真让人欲罢不能.虽然它侧边那条橙色的条纹让我有点别扭,但瑕不掩瑜,仍然非常值得拥有.</p>
<p>昨天,y460被我收入囊中&#8230;特写篇博文记念一下:)</p>
<p><a href="http://www.ryanote.com/wordpress/wp-content/uploads/2010/05/Y460_I3.jpg"><img class="alignnone size-full wp-image-146" title="Y460_I3" src="http://www.ryanote.com/wordpress/wp-content/uploads/2010/05/Y460_I3.jpg" alt="" width="600" height="600" /></a></p>
<p>买来后,迫不及待试了一下它的卖点之一:JBL专业音响.果然名不虚传,比我那个创新的2.1还要好,音质清晰浑厚.大喜之外,还体验了一下许多酷酷的功能:slidebar的拉链式的锁屏效果与win7的aero效果相得益彰;双显卡一键切换的功能让我在性能和节能上能自由选择&#8230;.太多太多了,更多的功能还要在以后慢慢发掘.</p>
<p>其实买本本最主要的目的还是为了方便工作,由于今后的工作平台更多的会在linux下,于是,在体验了y460的几个主要功能后,我开始装上了久闻大名的lucid lynx(ubuntu 10.04 LTS),这只清醒的猞猁作为LTS版本,其重要性可见一斑.一改之前的土黄色，这一次用上了更为悦目清新的紫色，其特效丝毫不逊色于win7.而且与社区的结合非常紧密，像Twitter和Facebook都无缝地整合在里面，不过由于国情，这些功能就有点打折扣了.由于本篇博文是为了记念本本的到来,ubuntu的功能我就不详细介绍了。</p>
<p>我相信我会充分利用好如此优秀的装备，开启事业的新篇章，迎接更美好的未来。
<div style="margin-top: 25px;color:#666; ">
<p><strong>原创文章，转载请注明：</strong> 转载自<a href="http://www.ryanote.com/wordpress/">Ryan&#039;s note</a></p>
<p><strong>本文链接地址:</strong> <a href="http://www.ryanote.com/archives/145">终于成为本本一族！</a></p>
</div>
<h2  class="related_post_title">热门日志</h2><ul class="related_post"><li><a href="http://www.ryanote.com/archives/68" title="我的技术旅程(一)">我的技术旅程(一)</a></li><li><a href="http://www.ryanote.com/archives/145" title="终于成为本本一族！">终于成为本本一族！</a></li><li><a href="http://www.ryanote.com/%e5%85%b3%e4%ba%8e" title="关于">关于</a></li><li><a href="http://www.ryanote.com/archives/158" title="揭秘Java中的String">揭秘Java中的String</a></li><li><a href="http://www.ryanote.com/archives/11" title="5个你必须掌握的maven命令">5个你必须掌握的maven命令</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.ryanote.com/archives/145/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>《Maven权威指南》学习笔记(三)</title>
		<link>http://www.ryanote.com/archives/139</link>
		<comments>http://www.ryanote.com/archives/139#comments</comments>
		<pubDate>Sun, 02 May 2010 13:18:08 +0000</pubDate>
		<dc:creator>Ryan</dc:creator>
				<category><![CDATA[Maven]]></category>
		<category><![CDATA[学习笔记]]></category>

		<guid isPermaLink="false">http://www.ryanote.com/?p=139</guid>
		<description><![CDATA[
构建生命周期

Maven使用POM描述项目，将其建模成一些名词.在Maven中这些“动词”是由Maven插件包装的一些目标，它们绑定到一个构建生命周期的阶段中.当你让Maven构建一个项目的时候，你其实是让它一步步通过那些预定义的有序的阶段，并且运行所有注册到某个特定阶段的目标

Maven中有三种标准的生命周期：清理（clean），默认（default）(有时候也称为构建)，和站点（site）

清理生命周期 (clean):它包含了三个生命周期阶段pre-clean,clean,post-clean

简单的运行clean:clean目标不会完整的执行该生命周期，但是指定clean阶段就能使用clean生命周期，并且逐个的经过生命周期阶段，直到到达clean阶段(可能未到post-clean阶段就停了)
指定post-clean阶段能经过完整的clean生命周期,直到post-clean阶段.
直接运行pre-clean阶段会提示:[INFO] No goals needed for project &#8211; skipping.可以在它的构建配置中，绑定了某个目标至pre-clean阶段
可以自定义Clean插件的行为去删除构建输出目录以外的文件


默认生命周期 (default):它是一个软件应用程序构建过程的总体模型。第一个阶段是validate，最后一个阶段是deploy
站点生命周期 (site):它包含了四个阶段：1. pre-site 2. site  3. post-site  4. site-deploy  默认绑定到站点生命周期的目标是：1. site &#8211; site:site  2. site-deploy -site:deploy
在上述这些生命周期里,如果某个生命周期阶段没有目标绑定在其上,运行该阶段会提示[INFO] No goals needed for project &#8211; skipping
 


打包相关生命周期

绑定到每个阶段的特定目标默认根据项目的打包类型设置

JAR打包默认的目标
生命周期阶段 目标
process-resources resources:resources
compile compiler:compile
process-test-resources resources:testResources
test-compile compiler:testCompile
test surefire:test
package jar:jar
install install:install
deploy deploy:deploy



通用生命周期目标

Process Resources:

大部分生命周期将resources:resources目标绑定到process-resources阶段.。process-resources阶段处理资源并将资源复制到输出目录,同时也会在资源上应用过滤器，能让你替换资源文件中的一些符号(而不是指pom.xml)
要配置使用该default.properties文件的资源过滤，我们需要在这个项目的POM中指定两样东西：构建配置的filters元素中的属性文件列表，以及一个标记告诉Maven资源目录需要过滤。默认的Maven行为会跳过过滤，只是将资源复制到输出目录；你需要显式的配置资源过滤，否则Maven就会置之不理
添加资源目录列表&#60;resource&#62;      &#60;directory&#62;src/main/images&#60;/directory&#62;    &#60;/resource&#62;
也可以声明两个资源目录，给它们提供不同的过滤配置和目标目录配置


Compile:

大部分生命周期将Compiler插件的compile目标绑定到compile阶段
可以为Compiler插件设置source和target版本
如果你想要存储项目的源码至src/java而非src/main/java，让构建输出至classes而非target/classes，你可以覆盖定义在超级POM中的sourceDirectory的默认值


Process Test Resources:  调用resources:testResources
Test Compile:调用compile:testCompile编译测试源代码目录至测试构建构建输出目录
Test:大部分生命周期绑定Surefire插件的test目标至test阶段

maven.test.skip变量同时控制Compiler和Surefire插件，如果你传入maven.test.skip，就等于告诉Maven整个的跳过测试


Install:Install插件的install目标基本上都是绑定到install生命周期阶段。install:install目标只不过是将项目的主要构件安装到本地仓库,如果这个项目的打包类型是POM，那么该目标就仅仅复制POM到本地仓库
Deploy:Deploy插件的deploy目标通常绑定到deploy生命周期阶段。该阶段用来将一个构件部署到远程Maven仓库，当你执行一次发布的时候通常需要更新远程仓库




第11章 构建Profile 和 第12章 Maven套件 先跳过不看(profile能解决产品环境和开发环境数据库地址不同的问题)
属性和资源过滤

属性

你可以在pom.xml文件或者资源文件中使用属性，资源文件被会Maven [...]]]></description>
			<content:encoded><![CDATA[<ol>
<li><strong>构建生命周期</strong>
<ol>
<li>Maven使用POM描述项目，将其建模成一些名词.在Maven中这些“动词”是由Maven插件包装的一些目标，它们绑定到一个构建生命周期的阶段中.当你让Maven构建一个项目的时候，你其实是让它一步步通过那些预定义的有序的阶段，并且运行所有注册到某个特定阶段的目标</li>
<li>
<div>Maven中有三种标准的生命周期：清理（clean），默认（default）(有时候也称为构建)，和站点（site）</div>
<ol>
<li>清理生命周期 (clean):它包含了三个生命周期阶段pre-clean,clean,post-clean
<ol>
<li>简单的运行clean:clean目标不会完整的执行该生命周期，但是指定clean阶段就能使用clean生命周期，并且逐个的经过生命周期阶段，直到到达clean阶段(可能未到post-clean阶段就停了)</li>
<li>指定post-clean阶段能经过完整的clean生命周期,直到post-clean阶段.</li>
<li>直接运行pre-clean阶段会提示:[INFO] No goals needed for project &#8211; skipping.可以在它的构建配置中，绑定了某个目标至pre-clean阶段</li>
<li>可以自定义Clean插件的行为去删除构建输出目录以外的文件</li>
</ol>
</li>
<li>默认生命周期 (default):它是一个软件应用程序构建过程的总体模型。第一个阶段是validate，最后一个阶段是deploy</li>
<li>站点生命周期 (site):它包含了四个阶段：1. pre-site 2. site  3. post-site  4. site-deploy  默认绑定到站点生命周期的目标是：1. site &#8211; site:site  2. site-deploy -site:deploy</li>
<li><strong>在上述这些生命周期里,如果某个生命周期阶段没有目标绑定在其上,运行该阶段会提示[INFO] No goals needed for project &#8211; skipping<br />
<span id="more-139"></span> </strong></li>
</ol>
</li>
<li>打包相关生命周期
<ol>
<li>绑定到每个阶段的特定目标默认根据项目的打包类型设置</li>
<li>
<div>JAR打包默认的目标</div>
<div>生命周期阶段 目标</div>
<div>process-resources resources:resources</div>
<div>compile compiler:compile</div>
<div>process-test-resources resources:testResources</div>
<div>test-compile compiler:testCompile</div>
<div>test surefire:test</div>
<div>package jar:jar</div>
<div>install install:install</div>
<div>deploy deploy:deploy</div>
</li>
</ol>
</li>
<li>通用生命周期目标
<ol>
<li>Process Resources:
<ol>
<li>大部分生命周期将resources:resources目标绑定到process-resources阶段.。process-resources阶段处理资源并将资源复制到输出目录,同时也会在资源上应用过滤器，能让你替换<span style="color: #ff0000;">资源文件中的一些符号(而不是指pom.xml)</span></li>
<li>要配置使用该default.properties文件的资源过滤，我们需要在这个项目的POM中指定两样东西：构建配置的filters元素中的属性文件列表，以及一个标记告诉Maven资源目录需要过滤。默认的Maven行为会跳过过滤，只是将资源复制到输出目录；你需要显式的配置资源过滤，否则Maven就会置之不理</li>
<li>添加资源目录列表&lt;resource&gt;      &lt;directory&gt;src/main/images&lt;/directory&gt;    &lt;/resource&gt;</li>
<li>也可以声明两个资源目录，给它们提供不同的过滤配置和目标目录配置</li>
</ol>
</li>
<li>Compile:
<ol>
<li>大部分生命周期将Compiler插件的compile目标绑定到compile阶段</li>
<li>可以为Compiler插件设置source和target版本</li>
<li>如果你想要存储项目的源码至src/java而非src/main/java，让构建输出至classes而非target/classes，你可以覆盖定义在超级POM中的sourceDirectory的默认值</li>
</ol>
</li>
<li>Process Test Resources:  调用resources:testResources</li>
<li>Test Compile:调用compile:testCompile编译测试源代码目录至测试构建构建输出目录</li>
<li>Test:大部分生命周期绑定Surefire插件的test目标至test阶段
<ol>
<li>maven.test.skip变量同时控制Compiler和Surefire插件，如果你传入maven.test.skip，就等于告诉Maven整个的跳过测试</li>
</ol>
</li>
<li>Install:Install插件的install目标基本上都是绑定到install生命周期阶段。install:install目标只不过是将项目的主要构件安装到本地仓库,如果这个项目的打包类型是POM，那么该目标就仅仅复制POM到本地仓库</li>
<li>Deploy:Deploy插件的deploy目标通常绑定到deploy生命周期阶段。该阶段用来将一个构件部署到远程Maven仓库，当你执行一次发布的时候通常需要更新远程仓库</li>
</ol>
</li>
</ol>
</li>
<li>第11章 构建Profile 和 第12章 Maven套件 先跳过不看(profile能解决产品环境和开发环境数据库地址不同的问题)</li>
<li><strong>属性和资源过滤</strong>
<ol>
<li>属性
<ol>
<li><span style="color: #ff0000;">你可以在pom.xml文件或者资源文件中使用属性，资源文件被会Maven Resource插件的过滤特性处理</span></li>
<li>隐式的属性:project.*,settings.*env.*,Java系统属性</li>
<li>Maven项目的属性:
<ol>
<li>任何在Maven POM 中的东西都可以用属性来引用(project.groupId 和 project.version)</li>
</ol>
</li>
<li>如果你试图在Maven中引用输出目录，你绝不应该使用如target/classes的字面量，而是应该使用属性来引用这些目录(project.build.*)
<ol>
<li>关于Maven Model对象可用属性的完整列表(关于model对象的属性还不是很清楚,应该是诸如model.*)</li>
</ol>
</li>
<li>Maven的Settings属性</li>
<li>环境变量属性</li>
<li>Java系统属性:任何你能从System.getProperty()获取的属性都能以Maven属性的形式引用,如:java.version</li>
<li>用户定义的属性:
<ol>
<li>用户定义的属性可以在POM中引用，也可以由Maven Resource插件用来过滤资源</li>
</ol>
</li>
</ol>
</li>
<li>资源过滤:
<ol>
<li>你可以使用Maven来对项目资源进行变量替换。在资源过滤被激活的时候，Maven会扫描资源，寻找由${ 和}包围的Maven属性的引用。一旦它找到这些引用，它就会使用合适的值去替换它们，就像前一节中定义的属性可以在POM中引用一样</li>
<li>该节和profile有点关联,因为第11章未看,理解不够深.</li>
</ol>
</li>
</ol>
</li>
<li>第 14 章 Maven和Eclipse: m2eclipse  没有IDE,跳过</li>
<li>第15章及其以后的章节都先跳过.</li>
<li>附录A稍微过了一遍.附录B没看.</li>
</ol>
<p><strong>要点:</strong></p>
<ol>
<li>Maven 不知道如何打包 WAR 文件，也不知道如何运行单元测试，Maven大部分的智能是由插件实现的，而插件从 Maven 仓库获得.当你下载Maven的时候，你得到的是一个包含了基本躯壳的Maven核心，它知道如何解析命令行，管理classpath，解析POM文件，在需要的时候下载Maven插件</li>
<li>conf/ 目录包含了一个全局的settings.xml文件，该文件用来自定义你机器上Maven的一些行为。如果你需要自定义Maven，更通常的做法是覆写~/.m2目录下的settings.xml文件，每个用户都有对应的这个目录</li>
<li>
<div>当Maven运行一个目标的时候，每个目标都会访问定义在项目POM里的信息</div>
</li>
<li>在一个Java项目中，Java类放在src/main/java下面，而classpath资源文件放在src/main/resources下面</li>
<li>Maven自带了一个用来下载Maven核心插件和依赖的远程仓库地址（http://repo1.maven.org/maven2）</li>
<li>Maven仓库的标准是按照下面的目录格式来存储构件，相对于仓库的根目录：/&lt;groupId&gt;/&lt;artifactId&gt;/&lt;version&gt;/&lt;artifactId&gt;-&lt;version&gt;.&lt;packaging&gt;</li>
<li>一旦Maven已经从远程仓库下载了一个构件，它将永远不需要再下载一次，因为maven会首先在本地仓库查找插件，然后才是其它地方</li>
<li>它支持了传递性依赖（transitive dependencies）,Maven会隐式的把这些库间接依赖的库也加入到你的项目中.</li>
<li>添加一些关于项目许可证，组织以及项目相关开发人员的一些信息.，licenses，organization 和 developers 等元素</li>
<li><span style="color: #ff0000;">一个插件目标也被认为是一个 “Mojo”</span></li>
<li>
<div>开启调试输出允许你看到Maven 工作时的依赖机制,查看完整的依赖踪迹: <strong>mvn install -X</strong></div>
</li>
</ol>
<div>PS:</div>
<ol>
<li>学习如何浏览邮件列表</li>
<li>artifact:人工制品;手工艺品;加工品</li>
<li>archetype:原型</li>
<li>snapshot:快照</li>
</ol>
<p>问题:</p>
<ol>
<li>在向create目标传入了packageName参数,与不传入没什么区别,生成的pom.xml没有变化,最后打包的名称也没有不同.</li>
<li>一开始构建前将conf/setting.xml下的repository地址改过后,将不会生成默认的~/.m2文件夹,而且针对每个用户的配置文件~/.m2/setting.xml也没有生成.</li>
</ol>
<div style="margin-top: 25px;color:#666; ">
<p><strong>原创文章，转载请注明：</strong> 转载自<a href="http://www.ryanote.com/wordpress/">Ryan&#039;s note</a></p>
<p><strong>本文链接地址:</strong> <a href="http://www.ryanote.com/archives/139">《Maven权威指南》学习笔记(三)</a></p>
</div>
<h2  class="related_post_title">相关日志</h2><ul class="related_post"><li><a href="http://www.ryanote.com/archives/134" title="《Maven权威指南》学习笔记(二)">《Maven权威指南》学习笔记(二)</a></li><li><a href="http://www.ryanote.com/archives/127" title="《Maven权威指南》学习笔记(一)">《Maven权威指南》学习笔记(一)</a></li><li><a href="http://www.ryanote.com/archives/11" title="5个你必须掌握的maven命令">5个你必须掌握的maven命令</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.ryanote.com/archives/139/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>《Maven权威指南》学习笔记(二)</title>
		<link>http://www.ryanote.com/archives/134</link>
		<comments>http://www.ryanote.com/archives/134#comments</comments>
		<pubDate>Sun, 02 May 2010 13:12:35 +0000</pubDate>
		<dc:creator>Ryan</dc:creator>
				<category><![CDATA[Maven]]></category>
		<category><![CDATA[学习笔记]]></category>

		<guid isPermaLink="false">http://www.ryanote.com/?p=134</guid>
		<description><![CDATA[
POM 

POM是Maven中一个项目的描述性陈述；也是当Maven构建项目的时候需要理解的一份“地图”
我们已经确定了POM是描述性和声明性的，它不像Ant或者Make那样提供显式的指令，我们也注意到POM的概念不是特定于Java的
超级POM:它是Maven安装的一部分，可以在/usr/local/maven/lib中的maven-2.0.9-uber.jar文件中找到。如果你看一下这个JAR文件，你会看到在包org.apache.maven.project下看到一个名为pom-4.0.0.xml的文件

默认的超级POM定义了一个单独的远程Maven仓库,该配置可以通过一个自定义的settings.xml文件来覆盖.注意这个默认的超级POM关闭了从中央Maven仓库下载snapshot构件的功能
默认的插件仓库就是这个中央仓库。Snapshot被关闭了，而且更新策略被设置成了“从不”，这意味着Maven将永远不会自动更新一个插件，即使新版本的插件发布了。
build元素设置Maven标准目录布局中那些目录的默认值
从Maven 2.0.9开始，超级POM为核心插件提供了默认版本
所有的Maven POM都继承自超级POM


Maven开始于超级POM，然后使用一个或多个父POM覆盖默认配置，最后使用当前项目的POM来覆盖之前生成的配置结果。最后你得到了一个混合了各个POM配置的有效POM。如果你想要查看项目的有效POM，你需要运行Maven Help插件的effective-pom目标
项目版本

Maven中的版本包含了以下部分：主版本，次版本，增量版本，和限定版本号

限定版本用来标识里程碑构建：alpha和beta发布，限定版本通过连字符与主版本，次版本或增量版本隔离


如果你的版本号与格式&#60;主版本&#62;.&#60;次版本&#62;.&#60;增量版本&#62;-&#60;限定版本&#62;相匹配，它就能被正确的比较,这种比较基于主版本，次版本，和增量版本的数值,如果不标准,就会使用字符串进行比较.

Maven会将限定版本后面的数字认作一个构建版本.但构建版本的解析还是使用字符串进行比较.可以使用“alpha-02”和“alpha-10”来解决

如果一个版本包含字符串“SNAPSHOT”，Maven就会在安装或发布这个组件的时候将该符号展开为一个日期和时间值，转换为UTC（协调世界时）(没试过)


LATEST是指某个特定构件最新的发布版或者快照版(snapshot)，最近被部署到某个特定仓库的构件。RELEASE是指仓库中最后的一个非快照版本.如果你处于软件开发过程中，你可能想要使用RELEASE或者LATEST，这么做十分方便，你也不用为每次一个第三方类库新版本的发布而去更新你配置的版本号。但当你发布软件的时候，你总是应该确定你的项目依赖于某个特定的版本




属性引用

一个POM可以通过一对大括弧和前面一个美元符号来包含 对属性的引用

Maven提供了三个隐式的变量，可以用来访问环境变量，POM信息，和Maven Settings

env:env.*   环境变量如PATH和M2_HOME可以使用env.*前缀来引用
project:你可以使用点标记（.）的路径来引用POM元素的值,如${project.artifactId}
settings:例如，${settings.offline}会引用~/.m2/settings.xml文件中offline元素的值



你还可以引用系统属性，以及任何在Maven POM中和构建profile中自定义的属性组

Java系统属性:所有可以通过java.lang.System中getProperties()方法访问的属性都被暴露成POM属性

我们还可以通过pom.xml或者settings.xml中的properties元素设置自己的属性，或者还可以使用外部载入的文件中属性





项目依赖

依赖范围

compile（编译范围）.compile是默认的范围；如果没有提供一个范围，那该依赖的范围就是编译范围。编译范围依赖在所有的classpath中可用，同时它们也会被打包
provided（已提供范围）.当你的开发过程只有在编译和测试时需要一个类库，而该类库在运行的时候由容器提供，那么你就需要使用已提供范围的依赖.已提供范围的依赖在编译classpath（不是运行时）可用。它们不是传递性的，也不会被打包。
runtime（运行时范围）.runtime依赖在运行和测试系统的时候需要，但在编译的时候不需要
test（测试范围).在一般的 编译和运行时都不需要，它们只有在测试编译和测试运行阶段可用
system（系统范围）system范围依赖与provided类似，但是你必须显式的提供一个对于本地系统中JAR文件的路径


可选依赖(使用不多,不推荐)
依赖版本界限

(, )不包含量词
[, ]包含量词
在逗号前面或者后面的版本不是必须的，这种空缺意味着正无穷或者负无穷


传递性依赖:其中的&#8221;传递性依赖和范围&#8221;有点绕,待实际需要了解时再做进一步了解.
冲突解决

排除一个传递性依赖
排除并替换一个传递性依赖


依赖管理


Maven在dependencyManagement元素中为你提供了一种方式来统一依赖版本号,使用pom.xml中的dependencyManagement元素能让你在子项目中引用一个依赖而不用显式的列出版本号


如果子项目定义了一个版本，它将覆盖顶层POM的dependencyManagement元素中的版本

顶层POM中的依赖管理与在一个广泛共享的父POM中定义一个依赖是不同的:所有依赖都会被继承。如果mysql-connector-java在顶层父项目中被作为一个依赖列出，这个层次中的所有项目都将引用该依赖。为了不添加一些不必要的依赖，使用dependencyManagement能让你统一并集中化依赖版本的管理，而不用添加那些会被所有子项目继承的依赖


项目关系


你应该避免在artifactId中使用它。因为在解析一个完整限定名字至子模块的时候，这会引发问题

坐标:groupId，artifactId，和version.还有第四个，也是最少用到的限定符：classifier
多模块项目:

多模块项目是那些包含一系列待构建模块的项目。一个多模块项目的打包类型总是pom，很少生成一个构件。一个模块项目的存在只是为了将很多项目归类在一起，成为一个构建


项目继承:


Maven假设父POM在本地仓库中可用，或者在当前项目的父目录(../pom.xml) 中可用。如果两个位置都不可用，默认行为还可以通过relativePath元素被覆盖



POM最佳实践

依赖归类:如果你有一组逻辑上归类在一起的依赖。你可以创建一个打包方式为pom项目来将这些依赖归在一起.当你添加这个项目作为一个依赖,不要忘了指定依赖类型为pom(&#60;type&#62;pom&#60;/type&#62;)
多模块 vs. 继承.多模块构建用来将模块聚集到一个单独的构建中,父子关系更多的是处理一个特定项目的定义.介绍了两个例子,它们都综合运用了多模块和继承,这两个例子的思想各有不同,要好好研究.










原创文章，转载请注明： 转载自Ryan&#039;s note
本文链接地址: 《Maven权威指南》学习笔记(二)

相关日志《Maven权威指南》学习笔记(三)《Maven权威指南》学习笔记(一)5个你必须掌握的maven命令]]></description>
			<content:encoded><![CDATA[<ol>
<li><strong>POM </strong>
<ol>
<li>POM是Maven中一个项目的描述性陈述；也是当Maven构建项目的时候需要理解的一份“地图”</li>
<li>我们已经确定了POM是描述性和声明性的，它不像Ant或者Make那样提供显式的指令，我们也注意到POM的概念不是特定于Java的</li>
<li>超级POM:它是Maven安装的一部分，可以在/usr/local/maven/lib中的maven-2.0.9-uber.jar文件中找到。如果你看一下这个JAR文件，你会看到在包org.apache.maven.project下看到一个名为pom-4.0.0.xml的文件
<ol>
<li>默认的超级POM定义了一个单独的远程Maven仓库,该配置可以通过一个自定义的settings.xml文件来覆盖.注意这个默认的超级POM关闭了从中央Maven仓库下载snapshot构件的功能</li>
<li>默认的插件仓库就是这个中央仓库。Snapshot被关闭了，而且更新策略被设置成了“从不”，这意味着Maven将永远不会自动更新一个插件，即使新版本的插件发布了。</li>
<li>build元素设置Maven标准目录布局中那些目录的默认值</li>
<li>从Maven 2.0.9开始，超级POM为核心插件提供了默认版本</li>
<li>所有的Maven POM都继承自超级POM</li>
</ol>
</li>
<li>Maven开始于超级POM，然后使用一个或多个父POM覆盖默认配置，最后使用当前项目的POM来覆盖之前生成的配置结果。最后你得到了一个混合了各个POM配置的有效POM。如果你想要查看项目的有效POM，你需要运行Maven Help插件的effective-pom目标</li>
<li>项目版本
<ol>
<li>Maven中的版本包含了以下部分：主版本，次版本，增量版本，和限定版本号</li>
<li>
<div>限定版本用来标识里程碑构建：alpha和beta发布，限定版本通过连字符与主版本，次版本或增量版本隔离</div>
</li>
<li>
<div>如果你的版本号与格式&lt;主版本&gt;.&lt;次版本&gt;.&lt;增量版本&gt;-&lt;限定版本&gt;相匹配，它就能被正确的比较,这种比较基于主版本，次版本，和增量版本的数值,如果不标准,就会使用字符串进行比较.</div>
</li>
<li>Maven会将限定版本后面的数字认作一个构建版本.但构建版本的解析还是使用字符串进行比较.可以使用“alpha-02”和“alpha-10”来解决</li>
<li>
<div>如果一个版本包含字符串“SNAPSHOT”，Maven就会在安装或发布这个组件的时候将该符号展开为一个日期和时间值，转换为UTC（协调世界时）(没试过)</div>
</li>
<li>
<div>LATEST是指某个特定构件最新的发布版或者快照版(snapshot)，最近被部署到某个特定仓库的构件。RELEASE是指仓库中最后的一个非快照版本.如果你处于软件开发过程中，你可能想要使用RELEASE或者LATEST，这么做十分方便，你也不用为每次一个第三方类库新版本的发布而去更新你配置的版本号。但当你发布软件的时候，你总是应该确定你的项目依赖于某个特定的版本<br />
<span id="more-134"></span></div>
</li>
</ol>
</li>
<li>属性引用
<ol>
<li>一个POM可以通过一对大括弧和前面一个美元符号来包含 对属性的引用</li>
<li>
<div>Maven提供了三个隐式的变量，可以用来访问环境变量，POM信息，和Maven Settings</div>
<ol>
<li>env:env.*   环境变量如PATH和M2_HOME可以使用env.*前缀来引用</li>
<li>project:你可以使用点标记（.）的路径来引用POM元素的值,如${project.artifactId}</li>
<li>settings:例如，${settings.offline}会引用~/.m2/settings.xml文件中offline元素的值</li>
</ol>
</li>
<li>
<div>你还可以引用系统属性，以及任何在Maven POM中和构建profile中自定义的属性组</div>
<ol>
<li>Java系统属性:所有可以通过java.lang.System中getProperties()方法访问的属性都被暴露成POM属性</li>
<li>
<div>我们还可以通过pom.xml或者settings.xml中的properties元素设置自己的属性，或者还可以使用外部载入的文件中属性</div>
</li>
</ol>
</li>
</ol>
</li>
<li>项目依赖
<ol>
<li>依赖范围
<ol>
<li>compile（编译范围）.compile是默认的范围；如果没有提供一个范围，那该依赖的范围就是编译范围。编译范围依赖在所有的classpath中可用，同时它们也会被打包</li>
<li>provided（已提供范围）.当你的开发过程只有在编译和测试时需要一个类库，而该类库在运行的时候由容器提供，那么你就需要使用已提供范围的依赖.已提供范围的依赖在编译classpath（不是运行时）可用。它们不是传递性的，也不会被打包。</li>
<li>runtime（运行时范围）.runtime依赖在运行和测试系统的时候需要，但在编译的时候不需要</li>
<li>test（测试范围).在一般的 编译和运行时都不需要，它们只有在测试编译和测试运行阶段可用</li>
<li>system（系统范围）system范围依赖与provided类似，但是你必须显式的提供一个对于本地系统中JAR文件的路径</li>
</ol>
</li>
<li>可选依赖(使用不多,不推荐)</li>
<li>依赖版本界限
<ol>
<li>(, )不包含量词</li>
<li>[, ]包含量词</li>
<li>在逗号前面或者后面的版本不是必须的，这种空缺意味着正无穷或者负无穷</li>
</ol>
</li>
<li>传递性依赖:其中的&#8221;传递性依赖和范围&#8221;有点绕,待实际需要了解时再做进一步了解.</li>
<li>冲突解决
<ol>
<li>排除一个传递性依赖</li>
<li>排除并替换一个传递性依赖</li>
</ol>
</li>
<li>依赖管理
<ol>
<li>
<div>Maven在dependencyManagement元素中为你提供了一种方式来统一依赖版本号,使用pom.xml中的dependencyManagement元素能让你在子项目中引用一个依赖而不用显式的列出版本号</div>
</li>
<li>
<div>如果子项目定义了一个版本，它将覆盖顶层POM的dependencyManagement元素中的版本</div>
</li>
<li>顶层POM中的依赖管理与在一个广泛共享的父POM中定义一个依赖是不同的:所有依赖都会被继承。如果mysql-connector-java在顶层父项目中被作为一个依赖列出，这个层次中的所有项目都将引用该依赖。为了不添加一些不必要的依赖，使用dependencyManagement能让你统一并集中化依赖版本的管理，而不用添加那些会被所有子项目继承的依赖</li>
</ol>
</li>
<li>项目关系
<ol>
<li>
<div>你应该避免在artifactId中使用它。因为在解析一个完整限定名字至子模块的时候，这会引发问题</div>
</li>
<li>坐标:groupId，artifactId，和version.还有第四个，也是最少用到的限定符：classifier</li>
<li>多模块项目:
<ol>
<li>多模块项目是那些包含一系列待构建模块的项目。一个多模块项目的打包类型总是pom，很少生成一个构件。一个模块项目的存在只是为了将很多项目归类在一起，成为一个构建</li>
</ol>
</li>
<li>项目继承:
<ol>
<li>
<div>Maven假设父POM在本地仓库中可用，或者在当前项目的父目录(../pom.xml) 中可用。如果两个位置都不可用，默认行为还可以通过relativePath元素被覆盖</div>
</li>
</ol>
</li>
<li>POM最佳实践
<ol>
<li>依赖归类:如果你有一组逻辑上归类在一起的依赖。你可以创建一个打包方式为pom项目来将这些依赖归在一起.当你添加这个项目作为一个依赖,不要忘了指定依赖类型为pom(&lt;type&gt;pom&lt;/type&gt;)</li>
<li>多模块 vs. 继承.多模块构建用来将模块聚集到一个单独的构建中,父子关系更多的是处理一个特定项目的定义.介绍了两个例子,它们都综合运用了多模块和继承,这两个例子的思想各有不同,要好好研究.</li>
</ol>
</li>
</ol>
</li>
</ol>
</li>
</ol>
</li>
</ol>
<div style="margin-top: 25px;color:#666; ">
<p><strong>原创文章，转载请注明：</strong> 转载自<a href="http://www.ryanote.com/wordpress/">Ryan&#039;s note</a></p>
<p><strong>本文链接地址:</strong> <a href="http://www.ryanote.com/archives/134">《Maven权威指南》学习笔记(二)</a></p>
</div>
<h2  class="related_post_title">相关日志</h2><ul class="related_post"><li><a href="http://www.ryanote.com/archives/139" title="《Maven权威指南》学习笔记(三)">《Maven权威指南》学习笔记(三)</a></li><li><a href="http://www.ryanote.com/archives/127" title="《Maven权威指南》学习笔记(一)">《Maven权威指南》学习笔记(一)</a></li><li><a href="http://www.ryanote.com/archives/11" title="5个你必须掌握的maven命令">5个你必须掌握的maven命令</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.ryanote.com/archives/134/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>《Maven权威指南》学习笔记(一)</title>
		<link>http://www.ryanote.com/archives/127</link>
		<comments>http://www.ryanote.com/archives/127#comments</comments>
		<pubDate>Thu, 29 Apr 2010 12:10:33 +0000</pubDate>
		<dc:creator>Ryan</dc:creator>
				<category><![CDATA[Maven]]></category>
		<category><![CDATA[学习笔记]]></category>

		<guid isPermaLink="false">http://www.ryanote.com/?p=127</guid>
		<description><![CDATA[该文章是我最近阅读《Maven权威指南》这本电子书以来整理的一些笔记，方便自己今后的复习和回顾]]></description>
			<content:encoded><![CDATA[<div>
<ol>
<li><strong>Maven的生命周期怎么理解? </strong>
<ol>
<li>
<div>一个阶段是“构建生命周期”中的一个步骤。生命周期是指包含在一个项目构建中的一系列有序的阶段</div>
</li>
<li><strong>插件目标可以附着在生命周期阶段上。随着Maven沿着生命周期的阶段移动，它会执行附着在特定阶段上的目标</strong></li>
<li>生命周期:第10章</li>
</ol>
</li>
<li><strong>学习使用Help插件 </strong>
<ol>
<li>help:active-profiles<br />
列出当前构建中活动的Profile（项目的，用户的，全局的）。</li>
<li><span style="color: #ff0000;">help:effective-pom<br />
<span style="color: #000000;">显示当前构建的实际POM，包含活动的Profile。</span></span></li>
<li><span style="color: #000000;">help:effective-settings<br />
打印出项目的实际settings, 包括从全局的settings和用户级别settings继承的配置。</span></li>
<li><span style="color: #ff0000;">help:describe<br />
<span style="color: #000000;">描述插件的属性。它不需要在项目目录下运行,但是你必须提供你想要描述插件的 groupId 和 artifactId。也可以传入插件的前缀(如help)如: mvn help:describe -Dplugin=help -Ddetail(书上用-Dfull)</span></span></li>
</ol>
</li>
<li><strong>运行mvn的方式 </strong>
<ol>
<li>mvn archetype:create 这里archetype是一个插件标识而create是目标标识,一个Maven插件是一个单个或者多个目标的集合.该命令没有创建 src/main/resources目录</li>
<li>
<div>create目标定义了一个配置属性archetypeArtifactId，不指定时它有一个默认值为maven-archetype-quickstart,生成的目录名与artifactId匹配.指定 archetypeArtifactId 为 maven-archetype-webapp,将创建一个web项目.</div>
</li>
<li>mvn package 命令行并没有指定一个插件目标，而是指定了一个Maven生命周期阶段.生命周期是包含在一个项目构建中的一系列有序的阶段<br />
<span id="more-127"></span></li>
</ol>
</li>
<li><strong>插件 </strong>
<ol>
<li>Maven Surefire 插件是负责运行单元测试的插件.测试报告:target\surefire-reports</li>
<li>Maven Archetype 插件</li>
<li>Maven Exec 插件.它不是 Maven 核心插件，但它可以从Codehaus 的 Mojo 项目得到.虽然 Exec 插件很有用，你不应该依赖它来运行你的应用程序.<br />
Exec 插件让我们能够在不往 classpath 载入适当的依赖的情况下，运行这个程序。Exec 能做这样的工作是因为 Maven 已经知道如何创建和管理你的 classpath 和你的依赖.</li>
<li>Maven Dependency 插件.
<ol>
<li>打印已解决依赖的列表: mvn dependency:resolve</li>
<li>如果你想知道你项目的整个依赖树，你可以运行 dependency:tree 目标</li>
</ol>
</li>
<li>Maven Assembly 插件:是一个用来创建你应用程序特有分发包的插件.需要在 pom.xml 中的build 配置中添加plugin 配置,再运行 mvn assembly:assembly 来构建这个装配</li>
</ol>
</li>
<li><strong>项目坐标 </strong>
<ol>
<li>groupId, artifactId, version和packaging。这些组合的标识符拼成了一个项目的坐标.</li>
<li>groupId以创建这个项目的组织名称的逆向域名(reverse domain name)开头</li>
<li>version:正在开发中的项目可以用一个特殊的标识，这种标识给版本加上一个“SNAPSHOT”的标记</li>
<li>packaging:也是Maven坐标的重要组成部分(不过在书上的后半部分又把它排除在坐标之外)，但是它不是项目唯一标识符的一个部分.你不能同时有一个拥有同样的groupId, artifactId和version标识的项目</li>
</ol>
</li>
<li><strong>依赖范围 </strong>
<ol>
<li>当一个依赖的范围是test的时候，说明它在Compiler插件运行compile目标的时候是不可用的。它只有在运行compiler:testCompile和surefire:test目标的时候才会被加入到classpath中.测试范围依赖是一个只在测试编译和测试运行时在 classpath 中有效的依赖。如果你的项目是以 war 或者 ear 形式打包的，测试范围依赖就不会被包含在项目的打包输出中。</li>
</ol>
</li>
<li><strong>单元测试 </strong>
<ol>
<li>忽略单元测试失败:1)设置 Surefire 的testFailureIgnore 这个配置属性为 true;2) mvn test -Dmaven.test.failure.ignore=true</li>
<li>跳过单元测试:1)设置 Surefire 的skip这个配置属性为 true;2) mvn install -Dmaven.test.skip=true</li>
</ol>
</li>
<li><strong>web应用 </strong>
<ol>
<li>可以通过mvn tomcat:run来启动web,并且不需要在pom.xml配置相应的插件.
<ol>
<li>跳过测试:-Dmaven.test.skip(=true)</li>
<li>指定端口:-Dmaven.tomcat.port=9090</li>
<li>忽略测试失败:-Dmaven.test.failure.ignore=true</li>
</ol>
</li>
<li>也可以通过mvn jetty:run来实现相同的目的,不过需要在pom.xml中做相应的插件配置.</li>
</ol>
</li>
<li><strong>POM优化 </strong>
<ol>
<li>优化依赖
<ol>
<li>依赖重复声明:找出所有被用于一个以上模块的依赖，然后将其向上移到父POM的dependencyManagement片段,在这些依赖配置被上移之后，我们需要为每个POM移除这些依赖的版本，否则它们会覆盖定义在父项目中的dependencyManagement.父POM包含一个版本和一组排除配置，所有的子POM需要使用groupId和artifactId引用这个依赖。</li>
<li>版本重复问题:创建&lt;properties&gt;&lt;hibernate.annotations.version&gt;3.3.0.ga&lt;/hibernate.annotations.version&gt;&lt;/properties&gt;属性,然后在&lt;dependency&gt;配置节里加入&lt;version&gt;${hibernate.annotations.version}&lt;/version&gt;</li>
<li>兄弟依赖不匹配:为兄弟项目使用内置的项目version和groupId</li>
</ol>
</li>
<li>优化插件
<ol>
<li>
<div>使用元素顶层POM build元素下的pluginManagement元素</div>
</li>
<li>通过属性来解决插件里的依赖的版本重复问题.</li>
</ol>
</li>
<li>使用Maven Dependency插件进行优化
<ol>
<li>总是为你代码引用的类显式声明依赖</li>
<li>运行dependency:analyze,该目标分析这个项目，查看是否有直接依赖，或者一些引用了但不是直接声明的依赖。</li>
<li>
<div>为了进一步调查，运行dependency:tree目标，该目标会列出项目中所有的直接和传递性依赖。</div>
</li>
</ol>
</li>
<li>大部分复杂的Maven多模块项目倾向于在顶层POM中定义所有的版本</li>
</ol>
</li>
</ol>
</div>
<div style="margin-top: 25px;color:#666; ">
<p><strong>原创文章，转载请注明：</strong> 转载自<a href="http://www.ryanote.com/wordpress/">Ryan&#039;s note</a></p>
<p><strong>本文链接地址:</strong> <a href="http://www.ryanote.com/archives/127">《Maven权威指南》学习笔记(一)</a></p>
</div>
<h2  class="related_post_title">相关日志</h2><ul class="related_post"><li><a href="http://www.ryanote.com/archives/139" title="《Maven权威指南》学习笔记(三)">《Maven权威指南》学习笔记(三)</a></li><li><a href="http://www.ryanote.com/archives/134" title="《Maven权威指南》学习笔记(二)">《Maven权威指南》学习笔记(二)</a></li><li><a href="http://www.ryanote.com/archives/11" title="5个你必须掌握的maven命令">5个你必须掌握的maven命令</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.ryanote.com/archives/127/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>浅谈网站缓存架构</title>
		<link>http://www.ryanote.com/archives/120</link>
		<comments>http://www.ryanote.com/archives/120#comments</comments>
		<pubDate>Sun, 18 Apr 2010 07:29:59 +0000</pubDate>
		<dc:creator>Ryan</dc:creator>
				<category><![CDATA[Memcached]]></category>
		<category><![CDATA[缓存]]></category>

		<guid isPermaLink="false">http://www.ryanote.com/?p=120</guid>
		<description><![CDATA[缓存的主要目的是降低数据库的读写压力,是维护大型网站稳定运行必不可少的优化手段之一,下面,结合我近段时间的工作经验,谈谈我对缓存设计的一些想法]]></description>
			<content:encoded><![CDATA[<p>缓存的主要目的是降低数据库的读写压力,是维护大型网站稳定运行必不可少的优化手段之一,下面,结合我近段时间的工作经验,谈谈我对缓存设计的一些想法:</p>
<p>缓存主要分为页面缓存和数据缓存:</p>
<h2>页面缓存</h2>
<p style="padding-left: 30px;">分为整体缓存和局部缓存</p>
<h4 style="padding-left: 30px;">优点:</h4>
<ol>
<li>实现简单</li>
<li>能有效降低数据库的查询压力</li>
</ol>
<h4 style="padding-left: 30px;">缺点:</h4>
<ol>
<li>一个网页的各个区域的内容更新频率及对实时性的要求不一样,结果为了迁就更新频率的区域,要让整个页面都跟着更新,导致性能的浪费.</li>
<li>局部缓存能解决上一个缺点,但如果页面区域过多,维护这么多个区域的更新策略将是件痛苦的事</li>
<li>只能缓存最终生成的HTML,一些动态数据无法缓存,如用户登录后的session</li>
<li>只能减轻数据的读取压力,无法降低写入的压力</li>
</ol>
<p>综合考虑上面的优缺点,将页面缓存在memcached里面显得意义不大,我决定将页面缓存主要<a title="结合Filter和Servlet实现真正的静态化" href="http://www.ryanote.com/archives/102">通过生成静态文本来实现</a>,而数据缓存则用memcached来实现.</p>
<h2>数据缓存</h2>
<p style="padding-left: 30px;">memcached使用key-value来存储数据,  通过简单的get/set方法即可实现缓存的读取/写入,并且可以针对每个缓存项设置数据过期时间.</p>
<h3 style="padding-left: 30px;">读取缓存</h3>
<p style="padding-left: 60px;">需要读取缓存的数据,只需从数据库取出并将其封装在一个对象里,再将该对象存入memcached即可实现数据的缓存,从而有效地降低数据库的读取压力.</p>
<h3 style="padding-left: 30px;">写入缓存</h3>
<p style="padding-left: 60px;">有些数据写入很频繁(如页面的访问量统计),这时就可以将待更新的数据先放入memcached中,等累积到一定程度后再一次性写入数据库,就拿访问量统计来说,可以每访问1000次后将数据写回数据库一次,从而有效降低数据库的写入压力,并且,memcached提供了原子加法,能有效解决线程安全上面的问题.</p>
<h3 style="padding-left: 30px;">分布式缓存</h3>
<p style="padding-left: 60px;">当网站规模变大,势必要增加多台memcached服务器,那么,如何有效地规范数据的缓存方案呢?<br />
一种方案是根据业务规则来区分,不同的业务放在不同的服务器里,不过这种方案很难保证压力的均衡,并且很难扩展.<br />
另一种方案是用类似于&#8221;取模&#8221;的方法来实现.可以将键值经过特定的算法运算后,对N取模,余数便是最终要存入的memcached服务器的编号.其中,N表示服务器的数量,以后要扩展,只需把N做相应的增加即可.</p>
<div style="margin-top: 25px;color:#666; ">
<p><strong>原创文章，转载请注明：</strong> 转载自<a href="http://www.ryanote.com/wordpress/">Ryan&#039;s note</a></p>
<p><strong>本文链接地址:</strong> <a href="http://www.ryanote.com/archives/120">浅谈网站缓存架构</a></p>
</div>
<h2  class="related_post_title">热门日志</h2><ul class="related_post"><li><a href="http://www.ryanote.com/archives/68" title="我的技术旅程(一)">我的技术旅程(一)</a></li><li><a href="http://www.ryanote.com/archives/145" title="终于成为本本一族！">终于成为本本一族！</a></li><li><a href="http://www.ryanote.com/%e5%85%b3%e4%ba%8e" title="关于">关于</a></li><li><a href="http://www.ryanote.com/archives/158" title="揭秘Java中的String">揭秘Java中的String</a></li><li><a href="http://www.ryanote.com/archives/11" title="5个你必须掌握的maven命令">5个你必须掌握的maven命令</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.ryanote.com/archives/120/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Linux下安装FTP服务器(vsftpd)(二)</title>
		<link>http://www.ryanote.com/archives/113</link>
		<comments>http://www.ryanote.com/archives/113#comments</comments>
		<pubDate>Fri, 16 Apr 2010 12:46:28 +0000</pubDate>
		<dc:creator>Ryan</dc:creator>
				<category><![CDATA[安装部署]]></category>
		<category><![CDATA[ftp]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[ubuntu]]></category>
		<category><![CDATA[vsftpd]]></category>

		<guid isPermaLink="false">http://www.ryanote.com/?p=113</guid>
		<description><![CDATA[在上一篇Linux下安装FTP服务器(vsftpd)(一)中,我向大家介绍如何了在Linux(Ubuntu)下搭建vsftpd,并实现文件的上传下载,但如果你想要更多的控制,比如你想只能让ryan可以上传文件,而其它用户不可以,那么,是时候用到我们先前设置的user_config_dir,之前我们指定的值为/etc/vsftpd_user_conf,那么要在该文件上加上如下内容:
local_root=/usr/ftp_store
write_enable=YES
anon_upload_enable=YES
anon_mkdir_write_enable=YES
运行sudo invoke-rc.d vsftpd reload重新加载一下,现在,ryan可以上传文件了,如果你还希望只能上传到限定目录,那么
sudo mkdir /home/ftp/incoming
sudo chown ftp:nogroup incoming
sudo chmod 770 /home/ftp/incoming
sudo chmod -w /home/ftp
这样,ftp用户就不可以上传文件到home/ftp了(ftp是FTP服务目录的拥有者,无法在终端登录,是隐藏在所有虚拟用户背后的真实用户),同时,一般用户也无法列出/home/ftp/incoming下的文件,如果希望ryan能看到自己上传的文件,那么还要在/etc/vsftpd_user_conf加上anon_world_readable_only=NO,这样ryan就能看到自己上传的文件了.

原创文章，转载请注明： 转载自Ryan&#039;s note
本文链接地址: Linux下安装FTP服务器(vsftpd)(二)

相关日志Linux下安装FTP服务器(vsftpd)(一)Linux下Apache与Tomcat的集成Linux下的svn命令大全Linux下的vi(vim)命令大全]]></description>
			<content:encoded><![CDATA[<p>在上一篇<a title="Linux下安装FTP服务器(vsftpd)(一)" href="http://www.ryanote.com/archives/88">Linux下安装FTP服务器(vsftpd)(一)</a>中,我向大家介绍如何了在Linux(Ubuntu)下搭建vsftpd,并实现文件的上传下载,但如果你想要更多的控制,比如你想只能让ryan可以上传文件,而其它用户不可以,那么,是时候用到我们先前设置的user_config_dir,之前我们指定的值为/etc/vsftpd_user_conf,那么要在该文件上加上如下内容:</p>
<blockquote><p>local_root=/usr/ftp_store<br />
write_enable=YES<br />
anon_upload_enable=YES<br />
anon_mkdir_write_enable=YES</p></blockquote>
<p>运行sudo invoke-rc.d vsftpd reload重新加载一下,现在,ryan可以上传文件了,如果你还希望只能上传到限定目录,那么</p>
<blockquote><p>sudo mkdir /home/ftp/incoming<br />
sudo chown ftp:nogroup incoming<br />
sudo chmod 770 /home/ftp/incoming<br />
sudo chmod -w /home/ftp</p></blockquote>
<p>这样,ftp用户就不可以上传文件到home/ftp了(ftp是FTP服务目录的拥有者,无法在终端登录,是隐藏在所有虚拟用户背后的真实用户),同时,一般用户也无法列出/home/ftp/incoming下的文件,如果希望ryan能看到自己上传的文件,那么还要在/etc/vsftpd_user_conf加上anon_world_readable_only=NO,这样ryan就能看到自己上传的文件了.
<div style="margin-top: 25px;color:#666; ">
<p><strong>原创文章，转载请注明：</strong> 转载自<a href="http://www.ryanote.com/wordpress/">Ryan&#039;s note</a></p>
<p><strong>本文链接地址:</strong> <a href="http://www.ryanote.com/archives/113">Linux下安装FTP服务器(vsftpd)(二)</a></p>
</div>
<h2  class="related_post_title">相关日志</h2><ul class="related_post"><li><a href="http://www.ryanote.com/archives/88" title="Linux下安装FTP服务器(vsftpd)(一)">Linux下安装FTP服务器(vsftpd)(一)</a></li><li><a href="http://www.ryanote.com/archives/81" title="Linux下Apache与Tomcat的集成">Linux下Apache与Tomcat的集成</a></li><li><a href="http://www.ryanote.com/archives/77" title="Linux下的svn命令大全">Linux下的svn命令大全</a></li><li><a href="http://www.ryanote.com/archives/73" title="Linux下的vi(vim)命令大全">Linux下的vi(vim)命令大全</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.ryanote.com/archives/113/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

