??xml version="1.0" encoding="utf-8" standalone="yes"?>
比如Q在业务操作中的pȝ日志和权限日志,很好的体现了事务原子性和事务隔离的应用?/span>
q里Q主要讲一下事务隔?/span>
EJB
的用?/span>
Z能在h事务?/span>
action
中调用不允许事务支持的外部系l?/span>
EJB
Q如
UMSAO
Q增加了事务隔离
EJB
?br />
需要在相关文g中配|:
biz-context.xml
"ejb/test/Facade4IsolateService"在weblogic-ejb-jar.xml中配|,必须同名?br />
weblogic-ejb-jar.xml
Facade4IsolateServiceEJB在ejb-jar.xml文g中设|?br />
ejb-jar.xml
1、熟lantq行java工程~译Q参考本人“ant~译java工程”一文)
2、junit知识Q看看www.junit.org
准备Q?/p>
1、www.junit.org下蝲junit.jar
2、xml.apache.org下蝲xalan.jarQant ?juntreport需要用刎ͼxalan最好版本大?.0Q不然你q要下蝲其他的java库)
把junit.jar、xalan.jar拯?ANT_HOME/lib/下面Qƈ且最好加到系lCLASSPATHQjunit.jar是肯定要的,xalan.jar׃清楚了)?br />
对自qE序djunit试E序Q此处请参考www.junit.org的文档,很简单的?br />
然后在build.xml中添加如下指?很多东西略过Q所以强烈要求读者先完成本h“ant~译java工程”一文)
<!-- 单元试Q需要完成compiled -->
<target name="test" depends="compile">
<junit printsummary="yes">
<!-- 需要的classpath -->
<classpath refid="classpath"/>
<batchtest>
<!-- 单元试文g为所有src目录下的*Test.java文g -->
<fileset dir="${srcDir}"><include name="**/*Test.java"/></fileset>
<!-- 生成格式为xmlQ也可以用plain或者brief -->
<!-- Z么生成xmlQ是Z下一步做report?-->
<formatter type="xml"/>
</batchtest>
</junit>
<!-- 对xml文g生成相应的html文g在reports目录?-->
<!-- 如果指定于web可访问的目录Q就可以使整个项目组看到单元试情况 -->
<junitreport todir="reports">
<fileset dir=".">
<include name="TEST-*.xml"/>
</fileset>
<!-- 带有框架Q可以用noframes选不带框?-->
<report format="frames" todir="reports/html"/>
</junitreport>
</target>
现在q行ant testQ看看reports/下面是不是有了生成的单元试l果的文件了Q?/p>
如果有问题可以用ant -debug test看看问题出在哪里Q?/p>
另外更改源程序,让程序通过试和通不q测试看看生成的l果如何Q?/p>
代码: |
public class SomeBusinessClass extends OtherBusinessClass { // 核心数据成员 // 其它数据成员Q日志流Q保证数据完整性的标志位等 // 重蝲基类的方? public void performSomeOperation(OperationInformation info) { // 安全性验? // 查传入数据是否满_? // 锁定对象以保证当其他U程讉K时的数据完整? // 查缓存中是否为最C? // U录操作开始执行时? // 执行核心操作 // U录操作完成旉 // l对象解? } // 一些类似操? public void save(PersitanceStorage ps) { } public void load(PersitanceStorage ps) { } } |
代码: |
public class CreditCardProcessor { public void debit(CreditCard card, Currency amount) throws InvalidCardException, NotEnoughAmountException, CardExpiredException { // 取出逻辑 } public void credit(CreditCard card, Currency amount) throws InvalidCardException { // 存入逻辑 } } |
代码: |
public interface Logger { public void log(String message); } |
代码: |
public class CreditCardProcessorWithLogging { Logger _logger; public void debit(CreditCard card, Money amount) throws InvalidCardException, NotEnoughAmountException, CardExpiredException { _logger.log("Starting CreditCardProcessor.credit(CreditCard, Money) " + "Card: " + card + " Amount: " + amount); // 取出逻辑 _logger.log("Completing CreditCardProcessor.credit(CreditCard, Money) " + "Card: " + card + " Amount: " + amount); } public void credit(CreditCard card, Money amount) throws InvalidCardException { System.out.println("Debiting"); _logger.log("Starting CreditCardProcessor.debit(CreditCard, Money) " + "Card: " + card + " Amount: " + amount); // 存入逻辑 _logger.log("Completing CreditCardProcessor.credit(CreditCard, Money) " + "Card: " + card + " Amount: " + amount); } } |
代码: |
public aspect LogCreditCardProcessorOperations { Logger logger = new StdoutLogger(); pointcut publicOperation(): execution(public * CreditCardProcessor.*(..)); pointcut publicOperationCardAmountArgs(CreditCard card, Money amount): publicOperation() && args(card, amount); before(CreditCard card, Money amount): publicOperationCardAmountArgs(card, amount) { logOperation("Starting", thisjoin point.getSignature().toString(), card, amount); } after(CreditCard card, Money amount) returning: publicOperationCardAmountArgs(card, amount) { logOperation("Completing", thisjoin point.getSignature().toString(), card, amount); } after (CreditCard card, Money amount) throwing (Exception e): publicOperationCardAmountArgs(card, amount) { logOperation("Exception " + e, thisjoin point.getSignature().toString(), card, amount); } private void logOperation(String status, String operation, CreditCard card, Money amount) { logger.log(status + " " + operation + " Card: " + card + " Amount: " + amount); } } |
代码: |
package com.company.springaop.test; import java.lang.reflect.Method; import org.springframework.aop.MethodBeforeAdvice; public class TestBeforeAdvice implements MethodBeforeAdvice { public void before(Method m, Object[] args, Object target) throws Throwable { System.out.println("Hello world! (by " + this.getClass().getName() + ")"); } } |
代码: |
package com.company.springaop.test; public class BeanImpl implements Bean { public void theMethod() { System.out.println(this.getClass().getName() + "." + new Exception().getStackTrace()[0].getMethodName() + "()" + " says HELLO!"); } } |
代码: |
package com.company.springaop.test; public interface Bean { public void theMethod(); } |
代码: |
package com.company.springaop.test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.FileSystemXmlApplicationContext; public class Main { public static void main(String[] args) { //Read the configuration file ApplicationContext ctx = new FileSystemXmlApplicationContext("springconfig.xml"); //Instantiate an object Bean x = (Bean) ctx.getBean("bean"); //Execute the public method of the bean (the test) x.theMethod(); } } |
代码: |
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <!--CONFIG--> <bean id="bean" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces"> <value>com.company.springaop.test.Bean</value> </property> <property name="target"> <ref local="beanTarget"/> </property> <property name="interceptorNames"> <list> <value>theAdvisor</value> </list> </property> </bean> <!--CLASS--> <bean id="beanTarget" class="com.company.springaop.test.BeanImpl"/> <!--ADVISOR--> <!--Note: An advisor assembles pointcut and advice--> <bean id="theAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="advice"> <ref local="theBeforeAdvice"/> </property> <property name="pattern"> <value>com\.company\.springaop\.test\.Bean\.theMethod</value> </property> </bean> <!--ADVICE--> <bean id="theBeforeAdvice" class="com.company.springaop.test.TestBeforeAdvice"/> </beans> |
by:http://opensource.atlassian.com/confluence/spring/display/DISC/AOP+Cache
I've written an AOP interceptor which allows you to specify which methods to cache for Spring beans.
Different cache providers are available: Memory HashMap, EHCache, OSCache (which is clusterable) and SwarmCache.
We start by defining a bookManager object which has one method
which returns a List of Books that are related to the Book that is specified. This method is ideally suited for caching, since the related books will not change that often.<bean id="bookManager" class="com.example.BookManager"/>
Next we define the AOP interceptor which will cache the results. This example will return a cached result (the List of Books) instead of a call to bookManager.getRelated(Book), if the method is called with the same Book argument.
Available implementations of CacheInterceptor are:
The cache in the example is expired after 15 minutes.
refreshPeriods and defaultRefreshPeriod are properties that are specific for the OSCacheInterceptor. The best way to know how to configure a specific CacheInterceptor implementation is by having a look in the Javadoc (see the project.zip file).
refreshPeriods indicates how long the results will be cached in seconds. So a call to com.example.BookManager.getRelated() will be cached for 900 seconds (15 minutes).
When a method is intercepted that is not defined under refreshPeriods, the value of defaultRefreshPeriod will be used.
In order to be able to identify a call to the method with the same parameter, we use the identifiers property. Here you can list the function that needs to be called in order to get a unique identifier for this class. For each class that is used as an argument for the cached methods, specify the method name (which may not have any parameters). This is a better aproach than using the toString() method, since this method can produce long lines while most of the time a simple identifier is available. So in this example, book.getId() will be used to identify separate Book arguments. There is no need to specify arguments that are primitives (float, int), Strings or Numbers (Float, Integer, ...).
Now we wire the cacheInterceptor to the bookManager bean and we're done! Calls to bookManager.getRelated() will from now on be cached for 15 minutes.
Of course you can add as many beans to the cache as you want.
The first version was written quite some time ago, but since 2006/03/21 there is a new version
(2.0.18).
I've used this code already in three projects, but not all implementations of the cache (SwarmCache) are well tested. The code is written in the org.springframework.aop.interceptor.cache package and may be copied/used for free.
This code is written by Pieter Coucke for Onthoo.com
, but may be used for free. Of course, if the Spring core developers are interested in integrating this, they are free to do so. If you find this code useful or have any remarks, please let me know!
See this XML file for a sample configuration.
Eclipse project and source code. More info is available in the javadocs
.
Caching the result of methods using Spring and EHCache
My AOP cache blog
and a post about version 2.0.18.
Attribute based caching
从解压羃目录取得oscache.jar 文g攑ֈ /WEB-INF/lib 或相应类库目录?目录中,
jar文g名可能含有版本号和该版本的发布日期信息等Q如oscache-2.0.2-22Jan04.jar
如果你的jdk版本?.3.x,在lib中加入Apache Common Lib 的commons-collections.jar包?br />如jdk?.4以上则不?/p>
从src或etc目录取得oscache.properties 文gQ放入src根目录或发布环境?WEB-INF/classes 目录
如你需要徏立磁盘缓存,M改oscache.properties 中的cache.path信息 (L前面?注释)?br />winc\径类gؓc:\app\cache
unixc\径类gؓ/opt/myapp/cache
拯OSCache标签库文件oscache.tld?WEB-INF/classes目录?/p>
现在你的应用目录cM如下Q?br />$WEB_APPLICATIONWEB-INFliboscache.jar
$WEB_APPLICATIONWEB-INFclassesoscache.properties
$WEB_APPLICATIONWEB-INFclassesoscache.tld
下列代码加入web.xml文g?br />E序代码Q?br /><taglib>
<taglib-uri>oscache</taglib-uri>
<taglib-location>/WEB-INF/classes/oscache.tld</taglib-location>
</taglib>
Z便于调试日志输出Q须加入commons-logging.jar和log4j-1.2.8.jar到当前类库\径中
在src目录加入下面两个日志输出配置文gQ?/p>
log4j.properties 文g内容为:
E序代码Q?br />log4j.rootLogger=DEBUG,stdout,file
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[start]%d{yyyy/MM/dd/ HH:mm:ss}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD] n%c[CATEGORY]%n%m[MESSAGE]%n%n
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=oscache.log
log4j.appender.file.MaxFileSize=100KB
log4j.appender.file.MaxBackupIndex=5
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[start]%d{yyyy/MM/dd/ HH:mm:ss}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD] n%c[CATEGORY]%n%m[MESSAGE]%n%n
log4j.logger.org.apache.commons=ERROR
log4j.logger.com.opensymphony.oscache.base=INFO
commons-logging.properties 文g内容?br />org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JCategoryLog
2.oscache.properties 文g配置向导
cache.memory
gؓtrue 或?false Q默认ؓ在内存中作缓存,
如设|ؓfalseQ那cache只能~存到数据库或硬盘中Q那cacheq有什么意义:Q?/p>
cache.capacity
~存元素个数
cache.persistence.class
持久化缓存类Q如此类打开Q则必须讄cache.path信息
cache.cluster 相关
为集设|信息?br />?br />cache.cluster.multicast.ip为广播IP地址
cache.cluster.properties为集属?/p>
3.OSCache的基本用?/p>
cache1.jsp 内容如下
E序代码Q?br /><%@ page import="java.util.*" %>
<%@ taglib uri="oscache" prefix="cache" %>
<html>
<body>
没有~存的日? <%= new Date() %><p>
<!--自动h-->
<cache:cache time="30">
?0U刷新缓存一ơ的日期: <%= new Date() %>
</cache:cache>
<!--手动h-->
<cache:cache key="testcache">
手动h~存的日? <%= new Date() %> <p>
</cache:cache>
<a href="cache2.jsp">手动h</a>
</body>
</html>
cache2.jsp 执行手动h面如下
< %@ taglib uri="oscache" prefix="cache" % >
<html>
<body>
~存已刷?..<p>
<cache:flush key="testcache" scope="application"/>
<a href="cache1.jsp">q回</a>
</body>
</html>
你也可以通过下面语句定义Cache的有效范?如不定义scope,scope默认为Applcation
E序代码Q?br /><cache:cache time="30" scope="session">
...
</cache:cache>
4. ~存qo器?CacheFilter
你可以在web.xml中定义缓存过滤器Q定义特定资源的~存?br />E序代码Q?br /><filter>
<filter-name>CacheFilter</filter-name>
<filter-class>com.opensymphony.oscache.web.filter.CacheFilter</filter-class>
<init-param>
<param-name>time</param-name>
<param-value>60</param-value>
</init-param>
<init-param>
<param-name>scope</param-name>
<param-value>session</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CacheFilter</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
上面定义缓存所?jsp面Q缓存刷新时间ؓ60U,~存作用域ؓSession
注意QCacheFilter只捕获Http头ؓ200的页面请求,卛_Ҏ错误h作缓存,
而不对其他请求(?00,404,400Q作~存处理
OSCache?
OSCache是OpenSymphonyl织提供的一个J2EE架构中Web应用层的~存技术实现组Ӟ它的出现解决了我们面临的问题?OSCache目前最新的E_版本?.0Q本文中的例子都是基于这个版本的Q如果大家运行例子的q程中发生问题,请首先确认是否采用了正确的Y件版本?
2.1 主要特征
1. 兼容多种支持JSP的web服务?
已经通过兼容试的web服务器包括OrionServer (1.4.0或者以上版? 、Macromedia JRun (3.0或者以上版? 、BEA Weblogic (7.x或者以上版? 、IBM Websphere (5.0版本)、Silverstream (3.7.4版本)、Caucho Resin (1.2.3或者以上版?、Tomcat (4.0或者以上版? Q其他支持servlet2.3、jsp1.2的web服务器应该都是完全兼?/font>OSCache的?
2. 可选的~存?
你可以用内存、硬盘空间、同时用内存和盘或者提供自q其他资源Q需要自己提供适配器)作ؓ~存区?
使用内存作ؓ~存区将可以提供更好的性能
使用盘作ؓ~存区可以在服务器重起后q速恢复缓存内?
同时使用内存和硬盘作为缓存区则可以减对内存的占?
3. 灉|的缓存系l?
OSCache支持寚w分页面内Ҏ者对面U的响应内容q行~存Q编E者可以根据不同的需求、不同的环境选择不同的缓存别?
4. 定w
在一般的web应用中,如果某个面需要和数据库打交道Q而当客户h到达Ӟweb应用和数据库之间无法q行交互Q那么将q回l用?pȝ出错"或者类似的提示信息Q如果用了OSCache的话Q你可以使用~存提供l用Pl自p得维护系l或者采取其他补救的旉?
其它Ҏ还包括寚w的支持、缓存主动刷新等Ҏ,大家可以参考OpenSymphony|站上的其他资源获取更多的信息?
3 OSCachelg的安?
OSCache是一个基于web应用的组Ӟ他的安装工作主要是对web应用q行配置Q大概的步骤如下Q?
1. 下蝲、解压羃OSCache
请到OSCache的主http://www.opensymphony.com/oscache/download.html下蝲Oscache的最新版本,作者下载的?/font>OSCache的最新稳定版?.0?
下载后的。Zip文g解压~到c:\oscacheQ后面的章节中将使用%OSCache_Home%来表C个目录)目录?
2. 新徏立一个web应用
3. 主要组?OSCache_Home%\oscache.jar攑օWEB-INF\lib目录
4. commons-logging.jar、commons-collections.jar的处?
OSCachelg用Jakarta Commons Logging来处理日志信息,所以需要commons-logging.jar的支持,请将%OSCache_Home%\lib\core\commons-logging.jar攑օclasspathQ通常意味着这个文件放入WEB-INF\lib目录Q?
如果使用JDK1.3,请将%OSCache_Home%\lib\core\commons-collections.jar攑օclasspathQ如果用JDK1.4或者以上版本,则不需要了
5. ?/font>oscache.properties?/font>oscache.tld攑օWEB-INF\class目录
%OSCache_Home%\oscache.properties包含了对OSCacheq行特征值的讄信息
%OSCache_Home%\oscache.tld包含?/font>OSCache提供的标{ֺ的定义内?
6. 修改web.xml文g
在web.xml文g中增加下面的内容Q增加对OSCache提供的taglib的支持:
<taglib>
<taglib-uri>oscache</taglib-uri>
<taglib-location>/WEB-INF/classes/ oscache.tld</taglib-location>
</taglib>
4 开始?/font>OSCache中的~存lg
OSCache中按照缓存范围的不同分ؓ两种不同的方式:一U是~存JSP面中部分或者全部内容,一U是Z整个面文g的缓存?
4.1 JSP部分内容~存
4.1.1 Cache-OSCache提供的缓存标{?
q是OSCache提供的标{ֺ中最重要的一个标{,包括在标{中的内容将应用~存机制q行处理Q处理的方式取决于~程者对cache标签属性的讄?
W一ơ请求到达时Q标{中的内容被处理q且~存hQ当下一个请求到达时Q缓存系l会查这部分内容的缓存是否已l失效,主要是以下几:
1. ~存旉过了cache标签讄的time或者duration属性规定的时旉
2. cron属性规定的旉比缓存信息的开始时间更?
3. 标签中缓存的内容在缓存后又被重新hq?
4. 其他~存期讑֮
如果W合上面四项中的M一,被缓存的内容视ؓ已经失效Q这时被~存的内容将被重新处理ƈ且返回处理过后的信息Q如果被~存的内Ҏ有失效,那么q回l用L是~存中的信息?
cache标签的属性说?
key - 标识~存内容的关键词。在指定的作用范围内必须是唯一的。默认的key是被讉K面的URI和后面的h字符丌Ӏ?
你可以在同一个页面中使用很多cache标签而不指定他的key属性,q种情况下系l用该面的URI和后面的h字符Ԍ另外再自动给q些key增加一个烦引值来区分q些~存内容。但是不推荐采用q样的方式?
scope - ~存发生作用的范_可以是application或者session
time - ~存内容的时间段Q单位是U,默认?600U,也就是一个小Ӟ如果讑֮一个负|那么q部分被~存的内容将永远不过期?
duration - 指定~存内容失效的时_是相对time的另一个选择Q可以用简单日期格式或者符合USO-8601的日期格式。如Qduration='PT5M' duration='5s'{?
refresh - false 或者true?
如果refresh属性设|ؓtrueQ不其他的属性是否符合条Ӟq部分被~存的内定w被更新Q这l编E者一U选择Q决定什么时候必d新?
mode - 如果~程者不希望被缓存的内容增加到给用户的响应中Q可以设|mode属性ؓ"silent"
其它可用的属性还包括Qcron 、groups、language、refreshpolicyclass、refreshpolicyparam?
上面的这些属性可以单独用,也可以根据需要组合用,下面的例子将讲解q些常用属性的使用方式?
4.1.2 Cache标签实例分析:
1. 最单的cache标签用法
使用默认的关键字来标识cache内容Q超时时间是默认?600U?
<cache:cache>
<%
//自己的JSP代码内容
%>
</cache:cache>
2. 用自己指定的字符串标识缓存内容,q且讑֮作用范围为session?
<cache:cache key="foobar" scope="session">
<%
//自己的JSP代码内容
%>
</cache:cache>
3.动态设定key|使用自己指定的time属性设定缓存内容的时旉Q用动态refresh值决定是否强制内容刷新?
因ؓOSCache使用key值来标识~存内容Q用相同的key值将会被认ؓ使用相同的的~存内容Q所以用动态的key值可以自qҎ不同的角艌Ӏ不同的要求军_使用不同的缓存内宏V?
<cache:cache key="<%= product.getId() %>" time="1800" refresh="<%= needRefresh %>">
<%
//自己的JSP代码内容
%>
</cache:cache>
4. 讄time属性ؓ负数使缓存内Ҏ不过?
<cache:cache time="-1">
<%
//自己的JSP代码内容
%>
5. 使用duration属性设|超期时?
<cache:cache duration='PT5M'>
<%
//自己的JSP代码内容
%>
6. 使用mode属性被缓存的内容不加入给客户的响应中
<cache:cache mode='silent'>
<%
//自己的JSP代码内容
%>
4.2 用CashFilter实现面U缓?
?/font>OSCachelg中提供了一个CacheFilter用于实现面U的~存Q主要用于对web应用中的某些动态页面进行缓存,其是那些需要生成pdf格式文g/报表、图片文件等的页面,不仅减少了数据库的交互、减数据库服务器的压力Q而且对于减少web服务器的性能消耗有很显著的效果?
q种功能的实现是通过在web.xml中进行配|来军_~存哪一个或者一l页面,而且q可以设|缓存的相关属性,q种Z配置文g的实现方式对于J2EE来说应该是一U标准的实现方式了?
[注] 只有客户讉K时返回http头信息中代码?00Q也是讉K已经成功Q的面信息才能够被~存
1. ~存单个文g
修改web.xmlQ增加如下内容,定?testContent.jsp面q行~存?
<filter>
<filter-name>CacheFilter</filter-name>
<filter-class>com.opensymphony.oscache.web.filter.CacheFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CacheFilter</filter-name>
<!-?testContent.jsp面内容q行~存-->
<url-pattern>/testContent.jsp</url-pattern>
</filter-mapping>
2. ~存URL pattern
修改web.xmlQ增加如下内容,定?.jsp面q行~存?
<filter>
<filter-name>CacheFilter</filter-name>
<filter-class>com.opensymphony.oscache.web.filter.CacheFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CacheFilter</filter-name>
<!-Ҏ有jsp面内容q行~存-->
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
3. 自己讑֮~存属?
在页面~存的情况下Q可以通过讄CacheFilter的初始属性来军_~存的一些特性:time属性设|缓存的旉D,默认?600U,可以Ҏ自己的需要只有的讄Q而scope属性设|,默认为applicationQ可选项包括application、session
<filter>
<filter-name>CacheFilter</filter-name>
<filter-class>com.opensymphony.oscache.web.filter.CacheFilter</filter-class>
<init-param>
<param-name>time</param-name>
<param-value>600</param-value>
</init-param>
<init-param>
<param-name>scope</param-name>
<param-value>session</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CacheFilter</filter-name>
<!-Ҏ有jsp面内容q行~存-->
<url-pattern>*.jsp</url-pattern>
</filter-mapping>