目前 Spring v3.1 在 nGrinder 中被广泛的应用,从它的Ioc 到 Cache 都有涉及。
Spring Data 在前文已经介绍,不在叙述。
Spring Cache
在nGrinder 2.X中已经引入cache机制,但在简单性和效率方面还有一定的欠缺。
在nGrinder 3.X 中引进SpringCache。它使用起来非常简单,只要在方法上添加
@Cacheable //从而让方法很快返回数据,避免重复处理
如下是nGrinder 3.0 中的Spring Cache 应用。
- /ngrinder-controller/src/main/resources/applicationContext-ehcache.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:cache="http://www.springframework.org/schema/cache" xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache-3.1.xsd">
<cache:annotation-driven />
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="ehcache" />
</bean>
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache.xml" />
<property name="shared" value="true" />
</bean>
</beans>
- /ngrinder-controller/src/main/resources/ehcache.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
<defaultCache eternal="false" maxElementsInMemory="100" overflowToDisk="false" timeToIdleSeconds="900"
timeToLiveSeconds="1800" />
<cache name="users" maxElementsInMemory="100" eternal="false" overflowToDisk="false" timeToIdleSeconds="900"
timeToLiveSeconds="1800" />
<cache name="perftest" maxElementsInMemory="100" eternal="false" overflowToDisk="false" timeToIdleSeconds="900"
timeToLiveSeconds="1800" />
<cache name="perftestlist" maxElementsInMemory="100" eternal="false" overflowToDisk="false" timeToIdleSeconds="900"
timeToLiveSeconds="1800" />
<cache name="file_entry_search_cache" maxElementsInMemory="100" eternal="false" overflowToDisk="false" timeToIdleSeconds="60"
timeToLiveSeconds="60" />
</ehcache>
applicationContext-ehcache.xml 为Spring 配置文件,ehcache.xml 是 详细的 Cache 配置文件以下为nGrinder的代码
public class PerfTestService {
/**
* Save performance test with given status
*
* @param test
* @param status
* @return
*/
@CacheEvict(value = { "perftest", "perftestlist" }, allEntries = true)
public PerfTest savePerfTest(PerfTest test, Status status) {
checkNotNull(test);
test.setStatus(status);
return perfTestRepository.save(test);
}
@Cacheable(value = "perftest")
public PerfTest getPerfTest(long testId) {
return perfTestRepository.findOne(testId);
}
@Cacheable(value = "perftest")
public PerfTest getPerfTestCandiate() {
return perfTestRepository.findOneByStatusOrderByCreatedDateAsc(Status.READY);
}
....
}
在代码中不管调用 getPerfTest(long testId) 还是getPerfTestCandiate(),系统都会从cache中直接读取数据。
只有savePerfTest()被调用后,所有的cache数据都会无效,缓存将会重新建立。
Spring Task
在开发过程中,有时会遇到需要调用比较耗时的方法,且又要很快的响应用户。一般在这种情况下,我们会用 Quartz 或者 数据库 程序实现异步调用。但是现在可以使用 SpringTask。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.1.xsd">
<task:annotation-driven executor="myExecutor" scheduler="myScheduler" />
<task:executor id="myExecutor" pool-size="1" />
<task:scheduler id="myScheduler" pool-size="1" />
</beans>
在代码中的实现
@Service
public class FileEntryService {
/**
* Create user svn repo.
*
* This method is executed async way.
*
* @param user
* newly created user.
*/
@Async
public void prepare(User user) {
File newUserDirectory = getUserRepoDirectory(user);
try {
if (!newUserDirectory.exists()) {
svnClientManager.getAdminClient().doCreateRepository(newUserDirectory, user.getUserId(), true, true);
}
} catch (SVNException e) {
LOG.error("Error while prepare user {}'s repo", user.getUserName(), e);
}
}
....
}
prepare(User user)方法会耗时1~2s,因为需要在nGrinder文件系统中创建基于SVN管理库。这个方法通常会和新用户一起创建。我们可以加
@Async 注释。这样就可以让这个过程在后台运行,不必让使用者感觉到。
SpringTask还可以很方便的创建定时任务。
/**
* perf test run scheduler.
*
* @author JunHo Yoon
* @since 3.0
*/
@Component
public class PerfTestRunnable implements NGrinderConstants {
/**
* Scheduled method for test execution.
*/
@Scheduled(fixedDelay = PERFTEST_RUN_FREQUENCY_MILLISECONDS)
@Transactional
public void startTest() {
PerfTest runCandidate = perfTestService.getPerfTestCandiate();
if (runCandidate == null) {
return;
}
// If there are too many trials, cancel running.
if (runCandidate.getTestTrialCount() > PERFTEST_MAXIMUM_TRIAL_COUNT) {
perfTestService.savePerfTest(runCandidate, Status.CANCELED);
}
doTest(runCandidate);
}
....
}
@Scheduled 还支持事物控制并且非常稳定。