??xml version="1.0" encoding="utf-8" standalone="yes"?> eclilpseQ日蚀, 月蚀Q??sun hibernateQ冬眠) ?spring jakartaQ雅加达Q与java tomcat里各个组件从上到下:catalinaQ远E蘪炸机QtomcatQ雄猫蘪炸机f14Qbootstap
(引导Qengine(发动机)host context
]]>
而checked exception是像IOExceptionq样的异?通常是需要程序员抛出?也是通过try catch或者throw来抛出的
]]>
import org.apache.struts.util.MessageResources;
MessageResources messages =MessageResources.getMessageResources("cn/edu/ouc/ky2/ApplicationResources");
messages.getMessage("experts.MAJOR_NAME")
2.普通的javac?q样更ؓ通用一?/p>
MessageResources resources =(MessageResources) pageContext.getServletContext().getAttribute(Globals.MESSAGES_KEY);
out.println(resources.getMessage("experts.MAJOR_NAME"));
by zhlmmc
Log4j实在是很熟悉Q几乎所有的Java目都用它啊。但是我一直没有搞明白。终于有一天我受不了了Q定下心ȝ了一把文,才两个小Ӟ我终于搞明白了。一般情况下Log4jL?/span>Apache Commons-logging一L的,我也׃起介l吧。多了个东西不是更麻烦,而是更简单!
<!--[if !supportLists]-->一?/span><!--[endif]-->Log4j的简单思想
Log4j真的很简单,单到令h发指的地步。不是要记录日志吗?那就l你一?/span>LogQ然后你?/span>Log来写东西p了,先来一个完整类CZQ?/span>
package test;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class Test {
static Log log = LogFactory.getLog(Test.class);
public void log(){
log.debug("Debug info.");
log.info("Info info");
log.warn("Warn info");
log.error("Error info");
log.fatal("Fatal info");
}
/**
* @param args
*/
public static void main(String[] args) {
Test test = new Test();
test.log();
}
}
别怕,看完q篇文章你就会觉得很单了?/span>
Log4j默认把日志信息分Z个等U?/span>
debug < info < warn < error < fatal
虽然可以自己d{Q但是我觉得没有必要Q五个够用了吧!你要写入信息的时候就把信息归Z个等U中的一个,然后调用相应的函数即可?/span>
分五个等U到底有什么用呢?日志信息到底写到哪里MQ?/span>
“LogFactory.getLog(Test.class)”又是什么意思捏Q接着往下看吧!
Log4j的关键之处在于它的承思想。也是一?/span>Log可以l承另外一?/span>Log的属性(输出到哪里,日志{Q日志格式等{)。怎么l承Q?/span>
Log4j是根?/span>Log的名字来判断l承关系的,比如Q?/span>
名字?#8220;com.zhlmmc.lib”?/span>Log是“com.zhlmmc.lib.log”?/span>parentQ明白了吧!Log4jq有一?/span>rootLoggerQ相当于Java?/span>Object?/span>
回过头来?#8220;LogFactory.getLog(Test.class)”q里?#8220;Test.class”事实上传q去的是Testq个cȝ完整路径Q包?/span>+cdQ,“test.Test”。这样如果存?#8220;test”q个Log那么Testq个Logq承它Q否则就l承rootLogger?/span>
那具体的Log属性是在哪里定义的呢?
<!--[if !supportLists]-->二?/span><!--[endif]-->常见的配|文?/span>
虽然可以?/span>xml或者在q行时用Java来配|?/span>Log4jQ但q是properties文g好用啊!
log4j.rootLogger=info, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
# Pattern to output the caller's file name and line number.
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n
分析一下:
W一行,配置log4j.rootLogger你明白吧。应为它是根Qd配置一下,否则别的Logl承什么啊。其他的Log可以配置也可以不配置。等号后面的W一个参数表C日志别,可以填五个别中的一U,后面的参数都是让Log知道输出到哪里,如果你想让日志输出到两个地方加两个输出参数Q比如:
log4j.rootLogger=info, stdout, file
q里?/span>info表示Q该Log的日志别ؓinfoQ所有别小?/span>info的日志都不会被记录。比如用这个配|文件的话,我刚开始D的那个类?/span>
log.debug("Debug info.");
q句话是不v作用的,因ؓdebug的别小?/span>info。这样就很容易控制什么信息在调试的时候要昄Q什么信息在发布的时候要L。这些都不用改代码,很方便吧?/span>
但,stdout?/span>file又是什么呢Q?/span>
接着往下看Q就是配|?/span>stdout了,q个名字是随便取的,你可以叫?/span>AQ?/span>
log4j.appender.A=org.apache.log4j.ConsoleAppender
那么上面?/span>rootLogger的参?/span>stdout也要ҎAQ其他用到的地方当然也要攏V这里的关键不是名字Q而是appendercdQ比如这里的“ConsoleAppender”Q看明白了吧Q输出到Console。后面两行都是设|日志格式的Q一般情况下你就照抄吧。既然是最入门x于理?/span>Log4j的工作原理,我就不介l?/span>filecd?/span>appender了,一搜一大把?/span>
在实际的目开发中Q很可能遇到所引用的包?/span>Log4j来记录日志,比如Hibernate。那么在q里你可以很Ҏ的控制这个包如何记录日志。比如在上面的配|文件中加一行:
log4j.logger.org.hibernate=fatal
那么所?/span>org.hibernate包下面的cd只会昄很少的信息,因ؓfatal的别最高啊?/span>
<!--[if !supportLists]-->三?/span><!--[endif]-->部v
别怕,q可不是部vTomcat。把log4j的包?/span>commons-logging的包Q加在一h两个Q放?/span>classpath下面。然后把配置文g保存?/span>log4j.propertiesQ也攑֜classpath下面Q如果用Eclipse的话Q放?/span>src目录下即可)。然后你可以跑了?/span>
Z使用?
工厂模式是我们最常用的模式了,著名的Jive论坛 ,大量用了工厂模式Q工厂模式在JavaE序pȝ可以说是随处可见?/span>
Z么工厂模式是如此常用Q因为工厂模式就相当于创建实例对象的newQ我们经常要ҎcClass生成实例对象Q如A a=new A() 工厂模式也是用来创徏实例对象的,所以以后new时就要多个心|是否可以考虑实用工厂模式Q虽然这样做Q可能多做一些工作,但会l你pȝ带来更大的可扩展性和量的修改量?/span>
我们以类SampleZQ?如果我们要创建Sample的实例对?
Sample sample=new Sample();
可是Q实际情冉|Q通常我们都要在创?span lang="EN-US">sample实例时做点初始化的工?比如赋?查询数据库等?/span>
首先Q我们想到的是,可以使用Sample的构造函敎ͼq样生成实例写?
Sample sample=new Sample(参数);
但是Q如果创?span lang="EN-US">sample实例时所做的初始化工作不是象赋DL单的事,可能是很长一D代码,如果也写入构造函CQ那你的代码很难看了Q就需要Refactor重整Q?/span>
Z么说代码很难看,初学者可能没有这U感觉,我们分析如下Q初始化工作如果是很长一D代码,说明要做的工作很多,很多工作装入一个方法中Q相当于很多鸡蛋放在一个篮子里Q是很危险的Q这也是有背?span lang="EN-US">Java面向对象的原则,面向对象的封?Encapsulation)和分z?Delegation)告诉我们Q尽量将长的代码分派“切割”成每D,每D再“装”h(减少D和D之间偶合联pL?Q这P׃风险分散,以后如果需要修改,只要更改每段Q不会再发生牵一动百的事情?/span>
在本例中Q首先,我们需要将创徏实例的工作与使用实例的工作分开, 也就是说Q让创徏实例所需要的大量初始化工作从Sample的构造函C分离出去?/span>
q时我们需?span lang="EN-US">Factory工厂模式来生成对象了Q不能再用上面简单new Sample(参数)?/span>q有,如果Sample有个l承如MySample, 按照面向接口~程,我们需要将Sample抽象成一个接?现在Sample是接?有两个子cMySample 和HisSample .我们要实例化他们?如下:
Sample mysample=new MySample();
Sample hissample=new HisSample();
随着目的深?span lang="EN-US">,Sample可能q会"生出很多儿子出来", 那么我们要对q些儿子一个个实例?更糟p的?可能q要对以前的代码q行修改:加入后来生出儿子的实?q在传统E序中是无法避免?
但如果你一开始就有意识用了工厂模式,q些ȝ没有了.
工厂Ҏ
你会建立一个专门生?span lang="EN-US">Sample实例的工?
public class Factory{ public static Sample creator(int which){ //getClass 产生Sample 一般可使用动态类装蝲装入cR?br />
if (which==1) } } |
那么在你的程序中,如果要实例化Sample?׃?/span>
Sample sampleA=Factory.creator(1);
q样,在整个就不涉及到Sample的具体子c?辑ֈ装效果,也就减少错误修改的机?q个原理可以用很通俗的话来比?是具体事情做得多,容易范错误.q每个做q具体工作的人都深有体会,相反,官做得越?说出的话抽象越W统,范错误可能性就少.好象我们从编E序中也能悟Zh生道?呵呵.
使用工厂Ҏ 要注意几个角Ԍ首先你要定义产品接口Q如上面的Sample,产品接口下有Sample接口的实现类,如SampleA,其次要有一个factoryc,用来生成产品SampleQ如下图Q最双是生产的对象SampleQ?/p>
q一步稍微复杂一点,是在工厂类上进行拓展,工厂cM有承它的实现类concreteFactory?strong>?/em>
抽象工厂
工厂模式中有: 工厂Ҏ(Factory Method) 抽象工厂(Abstract Factory).
q两个模式区别在于需要创建对象的复杂E度上。如果我们创建对象的Ҏ变得复杂?如上面工厂方法中是创Z个对象Sample,如果我们q有新的产品接口Sample2.
q里假设QSample有两个concretecSampleA和SamleBQ而Sample2也有两个concretecSample2A和SampleB2
那么Q我们就上例中Factory变成抽象c?共同部分封装在抽象cM,不同部分使用子类实现Q下面就是将上例中的Factory拓展成抽象工?
public abstract class Factory{ public abstract Sample creator(); public abstract Sample2 creator(String name); } public class SimpleFactory extends Factory{ public Sample creator(){ public Sample2 creator(String name){ } public class BombFactory extends Factory{ public Sample creator(){ public Sample2 creator(String name){ }
|
从上面看C个工厂各自生产出一套Sample和Sample2,也许你会疑问Qؓ什么我不可以用两个工厂方法来分别生Sample和Sample2?
抽象工厂q有另外一个关键要点,是因?SimpleFactory内,生Sample和生产Sample2的方法之间有一定联p,所以才要将q两个方法捆l在一个类中,q个工厂cL其本w特征,也许刉过E是l一的,比如Q制造工艺比较简单,所以名U叫SimpleFactory?/span>
在实际应用中Q工厂方法用得比较多一些,而且是和动态类装入器组合在一起应用,
举例
我们?span lang="EN-US">Jive的ForumFactoryZQ这个例子在前面的Singleton模式中我们讨Q现在再讨论其工厂模?
public abstract class ForumFactory { private static Object initLock = new Object(); public static ForumFactory getInstance(Authorization authorization) { try { //Now, q回 proxy.用来限制授权对forum的访?br />
return new ForumFactoryProxy(authorization, factory, //真正创徏forum的方法由l承forumfactory的子cd完成. .... }
|
因ؓ现在?span lang="EN-US">Jive是通过数据库系l存放论坛帖子等内容数据,如果希望更改为通过文gpȝ实现,q个工厂ҎForumFactory提供了提供动态接?
private static String className = "com.jivesoftware.forum.database.DbForumFactory";
你可以用自己开发的创徏forum的方法代替com.jivesoftware.forum.database.DbForumFactory可?
在上面的一D代码中一q了三U模?span lang="EN-US">,除了工厂模式?q有Singleton单态模?以及proxy模式,proxy模式主要用来授权用户对forum的访?因ؓ讉Kforum有两Uh:一个是注册用户 一个是游客guest,那么那么相应的权限就不一?而且q个权限是诏I整个系l的,因此建立一个proxy,cM|关的概?可以很好的达到这个效?
看看Java宠物店中的CatalogDAOFactory:
public class CatalogDAOFactory {
/** * 本方法制定一个特别的子类来实现DAO模式?br /> * 具体子类定义是在J2EE的部|描q器中?br /> */ public static CatalogDAO getDAO() throws CatalogDAOSysException { CatalogDAO catDao = null; try { InitialContext ic = new InitialContext(); String className =(String) ic.lookup(JNDINames.CATALOG_DAO_CLASS); catDao = (CatalogDAO) Class.forName(className).newInstance(); } catch (NamingException ne) { throw new CatalogDAOSysException(" } catch (Exception se) { throw new CatalogDAOSysException(" } return catDao; } } |
CatalogDAOFactory是典型的工厂ҎQcatDao是通过动态类装入器className获得CatalogDAOFactory具体实现子类Q这个实现子cdJava宠物店是用来操作catalog数据库,用户可以Ҏ数据库的cd不同Q定制自q具体实现子类Q将自己的子cdl与CATALOG_DAO_CLASS变量可以?/span>
由此可见Q工厂方法确实ؓpȝl构提供了非常灵zd大的动态扩展机Ӟ只要我们更换一下具体的工厂ҎQ系l其他地Ҏ需一点变换,有可能系l功能进行改头换面的变化?/p>
设计模式如何在具体项目中应用?a target="_blank">《Java实用pȝ开发指南?/a>