??xml version="1.0" encoding="utf-8" standalone="yes"?>
另外Q作为架构设计者,非常非常不赞成动辄就把很底层的概忉|q高层设计中Q例如行U,数据库什么的Q,很容易把自己和别人搞胡涂?br />可以最q状态不好,要不好好blog一,8q,有句话怎么说来着Q“都素那云而已。。。?/p>
情况Q子公司Q部分,人员{已完成所有编码(界面Q商业逻辑Q数据逻辑Q?br />变化Q需要把q个机构体系l成Z颗树状结?br />{略Q鉴于除了树l构外的其他部分代码已经完成Q那么应该首先保持这些代码不予改动。复用修改的优先U从高到低的序如下Q?br /> 界面×JSPQAction?br /> 商业逻辑 Service?br /> 数据逻辑?br /> 数据物理?br />有经验的人知道,大部分情况下Q越是下层的改动Q越是媄响越q泛Q注意不是修攚w度)Q所以我们只有在无计可施的情况下Q才q行低层的修攏V?/p>
分析: 回到我们的需?从功能上看,l护一个组l机构的需求,已经늛了每一个子l构的维护需求,以部门的建立ZQ在新徏一个部门时Q同时也必须建立机构树上的节点, p?我们完成了新增,修改l织机构的功能合?虽然有点拖沓,但是q是辑ֈ了复?修改原有代?而且扩展性也很好的目标。这上篇说的是两个简单业务的功能揉合问题,下篇我们来看看稍微复杂点的情?看看q能不能l箋依葫芦画瓢来完成功能合的?br /> 首先我们搞清楚log4j能干什么,单来说就是提供一个记录不同别信息内容的日志工具Q?br />可以把不同别,不同包\径的信息Q以指定格式输出到多U设备(控制収ͼ文g{) ==========log4j.properties================== log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.fileout=org.apache.log4j.RollingFileAppender log4j.rootCategory=INFO, stdout, fileout q个文g可以划ؓ三小?/p> ===========W一块定义了一个名?stdout 的appender和layout (appender,layout的概念后面再解释Q目前先记着有这样两个名?Q?/p> log4j.appender.stdout=org.apache.log4j.ConsoleAppender ============W三块定义了名字分别为rootCategory,log4j.logger.com.wolfsquare.log2的两个logger rootCategory logger是缺省的loggerQ记录所有的包的信息输出?br />W二个logger是只输出指定包com.wolfsquare.log2下的日志信息?br />那么INFO,DEBUG又是什么意思呢Q他们是信息的分U标识,通过l承实现q个实现自定义别的分?br />W三块配|两句的意思是q样的: 输出信息的分cȝ别是DEBUG > INFO > WARN > ERROR,信息l节q到粗Q指定输出某一U别的信息时Q?br />q细的信息输出将会被忽略 如果一个配|中有多个loggerQ他们之间会有什么关pdQ答案是Q在输出上,他们没有M关系Q都是独立运作的Q?br />不相关的Q但是在配置上,父包的配|会传给子包Q如果子包没有另外定义配|的话?br />例如上面配置文g中的两个loggerQ?br />log4j.logger.com.wolfsquare q里认ؓ log4j.logger.com.wolfsquare.log2 l承?log4j.logger.com.wolfsquareQ他们的配置声明如下Q?br />log4j.rootCategory=INFO, stdout, fileout 同时需要强调的是,如果两个logger有承关p,且输出到同一个appenderQ根据输出独立原则,那么会出现两行一L信息Q?br />例如上面的两个logger定义会导致这L情况?br />最后以一q图来概括: <bean id="serviceA" class="A" autowire="byName" lazy-init="true"> ׃两个业务服务互相调用的\径是不相交的Q所以采用了一U变通的ҎQ在声明serviceAӞ
原文在这:http://www.aygfsteel.com/RongHao/archive/2006/07/03/56258.html
仔细分析一,??四权限背后的实质可以发现:
一pȝ权限的概忉|一些冗?很难惌q样一U情?你已l有了子pȝ下的很多权限,l果因ؓ没有模块权限而得无法用该模块q行M操作,分配权限的h要非常小心才?q个世界已经够复杂了,不要再给开?部v人员增加复杂度了.很明白的,q个权限是不需要资源的权限
二数据库操作权限的概?有一点疑?不知道ؓ什么要建立q样的一个概?和行U权限有什么区别呢? 从你的上下文理解来看,g是这样子?有操作X表的业务,如果用户有增加权?则可以Q意增加数?如果用户有编辑权?则可以编辑Q意数?实际上对应标准权限模型ؓ:不需要限定资源的操作,即不需要资源标识的权限.
三行U数据权?q个概念很直?对应标准权限模型是: 资源(行数?+操作
四列U数据权?׃不是针对某特定行数据,所以它也是无资源型权限
p?所有的权限最l可划ؓ需要资源标识和不需要资源标?换句话说,所有权限可划分为控制某些集合的权限和控制单体的权限两种,在某些时?也称之ؓ 功能权限和数据权?/p>
谈到把权限分l别?很自然的是如何控制权限的权限的问题?很拗?是吧?仔细x,q样很直?也没有什么后遗症,权限自递归控制和自解释,真是一个完的循环.
有爱思考的同学x?会觉得非帔R?隑֮?当然,概念上一回事,具体实现上可以是另一回事,可以做很多的变通来辑ֈ目的.只要保持概念上的单?p以得非常多的h得以解脱了?/p>
q样Q如果需要直接用原有的创徏部门的所有代码,需要在其上加上创徏l织机构所需要的父节点,以及当前节点名称信息(在这里department的增加界 面JSP是需要修改的,不过实际上我没有修改该文?而是利用DHTML来动态加入需要新增加的信?,然后提交l原创徏部门的URI QdepartmentSave.actionQ和l织机构创徏URI(orgCreate.action)Q在q里我们利用ww提供的action chain功能来完成这两个操作?br /> q里需要修改department.action的配|?拦截saveҎ使其执行完后跌原来的relistl果面转向l织l构的创建orgCreate.actionQ?br /> <action name="unitSave" class="com.wolfsquare.ibase.org.action.UnitAction" method="save">
<result name="input">/org/unit/input.jsp</result>
<result name="relist" type="chain">
<param name="actionName">orgCreate</param>
<param name="namespace">/org</param>
</result>
<result name="xxx" type="redirect">/org/unit.action?start=${start}</result>
<interceptor-ref name="validationStack"/>
</action>
可能有同学看到这里会问:创徏l织节点时应该还需要关联前面创建的部门对象啊,q个操作是如何实现的Q信息是如何传递的Q?br />在这里,׃整个架构体系q没有支持这U信息传递的功能Q所以只好以一U比较”脏“的方式实现Q?br /> 在department.actionc里增加了一个方法getModel()q回刚刚创徏的部门对象,然后在org.actioncM增加一个接收的ҎsetModel(object o)q样在整action chain执行的时候,ww会自动将getModel后的数据填入setModel中,q样做的后果是以后增加新的机构类型的功能Ӟaction必须也照q样的语意设|getModelҎ。(如果要解册个问题,q能需要用一个特定的ContextQ然后拦截指定Service的创建方法,把创建结果放入ContextQ不q这又带来如何清除Context的问题,于是又要求助与ww的interspectorQ专门写一个拦截器来擦屁股Q够ȝ。。。)
(未完待箋)
理解了log4j的配|用法,以下是我对log4j配置的一点认识,如有谬误q请不吝赐教.
在程序中Q可以以以下方式来?br /> Log log = org.apache.commons.logging.LogFactory.LogFactory.getLog(yourClassName.class);
log.debug("debug message -------------------");
log.info("info message ******************");
log.warn("warn message +++++++++++++++");
log.error("error msg=================");
本文主要讲的是如何配|log4jQ先让我们先看看一个典型的log4j配置Q ?
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{MM-dd HH\:mm\:ss.SSS} %-5p [%F\:%L]%x %m%n
log4j.appender.fileout.File=D:/workspace/log4jtest/log/application.log
log4j.appender.fileout.MaxFileSize=10000KB
log4j.appender.fileout.MaxBackupIndex=10
log4j.appender.fileout.layout=org.apache.log4j.PatternLayout
log4j.appender.fileout.layout.ConversionPattern=%d{MM-dd HH:mm:ss.SSS}[%24F:%-3L:%-5p]%x %m%n
log4j.logger.com.wolfsquare.log2=DEBUG,stdout
===================================
定义stdout的实际输出实现类Q从q个appender实现cd可以猜到Q这个类是负责控制台输出的?br />log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
定义stdout的输饰器
log4j.appender.stdout.layout.ConversionPattern=%d{MM-dd HH\:mm\:ss.SSS} %-5p [%F\:%L]%x %m%n
装饰器参数配|?/p>
============W二块定义了一个名?fileout 的appender和layout:
log4j.appender.fileout=org.apache.log4j.RollingFileAppender
同理可猜q个实现cL输出到文件的
log4j.appender.fileout.File=D:/workspace/log4jtest/log/application.log
log4j.appender.fileout.MaxFileSize=10000KB
log4j.appender.fileout.MaxBackupIndex=10
log4j.appender.fileout.layout=org.apache.log4j.PatternLayout
log4j.appender.fileout.layout.ConversionPattern=%d{MM-dd HH:mm:ss.SSS}[%24F:%-3L:%-5p]%x %m%n
log4j.rootCategory=INFO, stdout, fileout
log4j.logger.com.wolfsquare.log2=DEBUG,stdout
rootCategory 把所有类的INFOU别以上的信息输出到stdout和fileout两个appender中,
logger.com.wolfsquare.log2Q把com.wolfsquare.log2包中的所有类Q包括子包)DEBUGU别Q含Q以上的信息输出到stdout ?br />一个logger可以输出到很多个讑֤中(appenderQ?如果需要增加输备则用分号分隔开appender名称卛_?/p>
log4j.logger.com.wolfsquare.log2
log4j.logger.com.wolfsquare.log2=,stdout
注意W二句没有指定输出?那么Ҏ配置l承规则会承父logger的配|,在这里就是INFO?/p>
<property name="serviceB"><ref local="serviceB"/></property>
</bean>
<bean id="serviceB" class="B" autowire="byName" lazy-init="true">
<property name="serviceA"><ref bean="serviceA"/></property>
</bean>
但是作ؓ一个业务接口,它应该是不需要关心事务,回滚q些无关的东西,
但现实又有这L需求,所以我们必M证透明的实现这个功能,于是?BR>入了AOP方式解决该问题,利用的是Spring自带的org.springframework.t
ransaction.interceptor.TransactionProxyFactoryBean.
重新声明文g如下Q?BR> <bean id="baseTxProxy" lazy-init="true"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="proxyTargetClass"><value>true</value></property>
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<bean id="serviceA" parent="baseTxProxy">
<property name="target"><ref local="serviceAImpl"/></property>
</bean>
<bean id="serviceAImpl" class="serviceA" autowire="byName" lazy-init="true">
<property name="serviceB">
<ref bean="serviceB"/>
</property>
</bean>
<bean id="serviceB" parent="baseTxProxy" lazy-init="true">
<property name="target"><ref local="serviceBImpl"/></property>
</bean>
<bean id="serviceBImpl" class="D" lazy-init="true">
<property name="serviceA">
<ref bean="serviceA"/>
</property>
</bean>
于是问题出CQSpring报了FactoryBeanCircularReferenceExceptionQ无法l完成设|工作?BR>查看TransactionProxyFactoryBean源码Q其实现了FactoryBean和InitializingBean接口Q应该是
做了代理之后Q两个代理Bean需要等待所有Bean讄完成后才会标识状态ؓ初始化完毕,于是造成?BR>冲突?/P>
直接定义serviceBQ?BR> <bean id="serviceAImpl" class="serviceA" autowire="byName" lazy-init="true">
<property name="serviceB">
<bean class="B" autowire="byName"/>
</property>
</bean>
相当于serviceB和serviceA中用的serviceB不是同一个实例?BR>
但是如果实调用重合时怎么办?
解决Ҏ是这LQ?BR>
<bean id="serviceAImpl" class="serviceA" autowire="byName" lazy-init="true">
<property name="serviceB">
<ref bean="serviceBImpl"/>
</property>
</bean>
非常单,serviceAImpl调用Ӟ可能已经在事务环境中了,不需再用serviceB代理的事务支持,
于是直接引用serviceB实例。这个方法是我写q篇文章时想到的Q?_-!!!Q看来知识果真还是好?BR> 整理呀?/P>
hbm文g采用通配W获取:
问题症状Q?/P>
应用启动报错说不能重复定义某c,L该类后仍然报下一个类重复定义?/P>
仔细查看Log输出发现Q所有的hbm文g均找C两䆾 -_-!!!
目l认为应该是websphere不太厚道Q在classpath中用了多处目录(web-inf & classes)Qƈ以这些目录ؓ根进行递归搜烦匚w文gQ可是如果这些目录有包含关系QWebSphere没有处理重复查扄文g了?/P>
于是在以上配|中改ؓQ?/P>
问题虽然解决了,可是tomcat中却又无效了?Q(
什么时候,企业应用才能一ơ拷贝,到处q行啊~?/P>
环境Q?JDBC驱动inet tds驱动(版本不明),SQLServer2K
问题症状Q对于数据库声明为varchar的长度大?56的字D,可以正常保存Q但是无法取出多?56字符以后的内?/P>
问题2Q用Hibernate映射?长度字符串保存后Q取出多加了一个空?/P>
环境Qinet tds驱动Hibernate2.1.8,SQL Server2K
问题症状Q保?长度字符串后Q取出增加了多余的空根{?/P>
以上两个问题都是因ؓ没有使用最新的通讯协议引v的,修改URL声明方式如下Q?/P>
jdbc:inetdae7:127.0.0.1:1433?database=xxx
问题解决Q收工?/P>
ps:发现协议inetdaeӞ数据库字DؓNullӞHibernate取出声明为基本类型(例如booleanQ的对象属性ƈ不会报错Q实际上在其他数据库如Oracle和新协议上是会报错的。ؓ了避免此c问题出玎ͼ最好还是严格遵守:Hibernate声明对象的基本类型属性,一定不能在数据库端|ؓI倹{?/P>
ps2:在解决以上问题中发现,Oracle居然对传?长度字符Ԍ会{为空?不知道是Z节省I间q是别的什么理由?_-!!!
Q?STRONG>全文?/FONT>Q?/P>
以上做法形象的说应该是这P把需要生的囑Ş对象先放大,d一张“纸上”,然后整体~小Q这L度就提高了?/P>
tips 1Q在一般企业报表表格打CQ?44DPI得到的表格线的宽度看h最舒服?BR> tips 2Q现在号U?00DPI的打印机其实?76DPIQ如果想使用q个分L率的_ֺQ需要用好一点的U张Q因为已l到极限了,U张E差点,打印墨粉沾不上Q导致线体残~?/P>
附源码(修改分L率就改动变量iResMul好Q:
Q?STRONG>全文?/FONT>Q?nbsp;
// 订单服务只负责做好自q?BR>
而ؓ了拦截Q何的Ҏ调用Q则实现了拦截器EventBrocasterQ?BR>
事g侦听器:
然后Q在Spring配置里将q些lg全部q接hQ?/P>
1.OrderService实现:
<bean id="orderServiceImpl" class="OrderService" autowire="byName">
</bean>
2. 声明OrderService代理:
<bean id="orderService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref local="orderServiceImpl"/>
</property>
<property name="interceptorNames"> <!--拦截器列?->
<list>
<value>eventBrocaster</value>
</list>
</property>
<property name="singleton">
<value>true</value>
</property>
</bean>
3.事gq播拦截?BR> <bean id="eventBrocaster" class="com.wolfsquare.core.service.EventBrocaster" singleton="true">
<property name="lifecycleListeners">
<list>
<ref bean="orderEventListener"/>
</list>
</property>
</bean>
4.具体的胦务子pȝ的侦听器实现与胦务系l的通讯Q?BR> <bean id="orderEventListener" class="OrderEventListener" autowire="byName">
<propety name="financialService"><ref bean="financialService"/></property>
</bean>
q样Q我们与具体实现无关的事件广播就做到了,聪明的朋友看到这里,肯定惛_了拦截器方式不仅仅适用与事件广播,q可以实C务的l一理Q事实上Spring的事务管理就是这样完成的Q还可以实现权限的控制例如AcegiQ简直有点象万能的胶_呵呵?/P>
从两文章的逐步探讨下,同一个机器,同一个虚拟机之内的数据通讯都可以实CQ那么异构系l和多虚拟机间的通讯又如何处理呢Q于是ESBQ企业服务ȝQ的概念慢慢Q现出来了Q不q这个不在本文探讨的范畴了,也许在不久的来Q我会补上这一?/P>
Q全文完Q?/STRONG>