تُستخدم عملية التخزين المؤقت(caching) لتخزين البيانات المطلوبة بشكل متكررواسترجاعها بسرعة عند الحاجة.
يقدم SAP Commerce RegionCache إمكانية تقسيمالمحتوى إلى ما يُسمى بالمناطق (regions). تتيح هذه الطريقة التحكم في حجم الذاكرة المخصصة لتخزين عناصر معينةواستراتيجية إزالتها (eviction strategy).
كما نرى في الوثائق الرسمية، يستخدمSAP Commerce الأنواع التالية للإزالة من الكاش:
- الأقل استخدامًا مؤخرًا (Least Recently Used – LRU): يتم تحديث الطابع الزمني لآخر استخدام عند وضع عنصر في الكاش أو عند استرجاعه عبر استدعاء GET.
- الأقل استخدامًا تكرارًا (Least Frequently Used – LFU): يتم تحديث عدد مرات الوصول لكل استدعاء GET على العنصر. عند إجراء PUT لعنصر جديد، وإذا تم الوصول إلى الحد الأقصى لذاكرة التخزين، يتم إزالة العنصر الأقل استخدامًا.
- الأول دخل، الأول خرج (First In, First Out – FIFO): يتم إزالة العناصر بنفس ترتيب دخولها. عند إجراء PUT لعنصر جديد، وإذا تم الوصول إلى الحد الأقصى لذاكرة التخزين، يكون العنصر الذي تم وضعه أولاً هو المرشح للإزالة.
في الأسطر التالية، سنستعرض مثالًا عمليًا علىاستخدام Hybris Region Cache مخصص.
توسيعEHCacheRegion وتنفيذ الطرق المطلوبة:
CacheAccessImpl.java
| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99 |
public class CacheAccessImpl extends EHCacheRegion implements CacheAccess{
private static final Logger LOG = LoggerFactory.getLogger(CacheAccessImpl.class);
// Insert Constructors
@Override
public Object get(Object key) {
final GenericCacheKey genericCacheKey = generateGenericCacheKey(key);
try {
return super.get(genericCacheKey);
} catch (final IllegalStateException e) {
LOG.error("IllegalStateException occured", e);
return null;
}
}
@Override
public void put(Object key, Object object) throws CacheAccessException {
final GenericCacheKey genericCacheKey = generateGenericCacheKey(key);
final DefaultCacheValueLoaderImpl<Object> loader = new DefaultCacheValueLoaderImpl<>();
loader.setValue(object);
remove(genericCacheKey);
LOG.debug("Object with following key(s) {} put into cache region {} ", genericCacheKey.toString(), this.getName());
super.getWithLoader(genericCacheKey, loader);
}
@Override
public void putIfAbsent(final Object key, final Object object) throws CacheAccessException {
if (isAbsent(key)) {
put(key, object);
}
}
@Override
public void remove(Object key) throws CacheAccessException {
final GenericCacheKey genericCacheKey = generateGenericCacheKey(key);
LOG.debug("Object with following key(s) {} removed from cache region {} ", genericCacheKey.toString(), this.getName());
super.remove(genericCacheKey, false);
}
/**
* Generates a {@link GenericCacheKey} from key object.
*
* @param key to be converted
* @return {@link GenericCacheKey}
*/
private GenericCacheKey generateGenericCacheKey(final Object key) {
if (key instanceof GenericCacheKey) {
return (GenericCacheKey) key;
} else {
return new GenericCacheKey(key, GenericCacheKey.DEFAULT_CACHE_TYPECODE);
}
}
/**
* Checks if the key is in cache.
*
* @param key the key for which the absence is checked
* @return true if key is not in cache, false if it is in cache
*/
private boolean isAbsent(final Object key) {
final GenericCacheKey genericCacheKey = generateGenericCacheKey(key);
return !super.containsKey(genericCacheKey);
}
/**
* Inner implementation of the {@link CacheValueLoader} which is used for method <code>put</code>.
*
* @param <V>
*/
private static class DefaultCacheValueLoaderImpl<V> implements CacheValueLoader<V> {
private V obj;
/**
* Standard constructor.
*/
public DefaultCacheValueLoaderImpl() {
super();
}
@Override
public V load(final CacheKey arg0) {
return this.obj;
}
/**
* Set value to be loaded from {@link CacheValueLoader}.
*
* @param obj value to be loaded.
*/
@SuppressWarnings("unchecked")
public void setValue(final Object obj) {
this.obj = (V) obj;
}
}
} |
تكوين منطقة الكاش الجديدة
قم بإنشاء ملف تكوين Spring Cache جديد (مثال:devistacore/resources/devistacore-spring-cache.xml):
spring-beans.xml
| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 |
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<alias alias="devistaPriceCacheRegion" name="defaultDevistaPriceCacheRegion"/>
<bean id="defaultDevistaPriceCacheRegion" parent="priceCacheRegion">
<constructor-arg name="name" value="devistaPriceCacheRegion"/>
<constructor-arg name="maxEntries" value="1000"/>
<constructor-arg name="evictionPolicy" value="FIFO"/>
<constructor-arg name="statsEnabled" value="true"/>
<constructor-arg name="exclusiveComputation" value="false"/>
<property name="handledTypes">
<array>
<value></value>
</array>
</property>
</bean>
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="cacheRegionsList"/>
<property name="targetMethod" value="add"/>
<property name="singleton" value="true"/>
<property name="arguments">
<ref bean="devistaPriceCacheRegion"/>
</property>
</bean>
<alias alias="priceCacheRegion" name="priceDefaultCacheRegion"/>
<bean abstract="true" class="com.devista.core.cache.CacheAccessImpl" id="priceDefaultCacheRegion">
<constructor-arg name="evictionPolicy" value="LRU"/>
<constructor-arg name="statsEnabled" value="true"/>
<constructor-arg name="exclusiveComputation" value="false"/>
</bean>
</beans> |
بعد هذه الخطوة، يجب أن تتمكن من رؤية ملف منطقةالكاش الجديد في HAC Console.
لا تنسى إضافة ملف التكوين الجديد إلى السياقالعام للتطبيق:
devistacore.global-context=devistacore-spring-cache.xml
إنشاء خدمة الكاش:
DevistaPriceCacheServiceImpl.java
| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 |
public class DevistaPriceCacheServiceImpl implements DevistaPriceCacheService {
private CacheAccess cacheAccess;
@Override
public void add(String key, PriceInformation object) {
try {
cacheAccess.putIfAbsent(key, object);
} catch (CacheAccessException e) {
LOGGER.error("Unable to cache the price information", e);
}
}
@Override
public PriceInformation get(String key) {
if (Objects.isNull(key)) {
return null;
} else {
PriceInformation chachedInfo = (PriceInformation) cacheAccess.get(key);
return chachedInfo;
}
}
public void setCacheAccess(CacheAccess cacheAccess) {
this.cacheAccess = cacheAccess;
}
} |
استخدام الخدمة عند الحاجة:
getWebPriceForProduct.java
| 1
2
3
4
5
6
7
8
9
10
11 |
public PriceInformation getWebPriceForProduct(ProductModel product) {
validateParameterNotNull(product, "Product model cannot be null");
PriceInformation priceInformation = devistaPriceCacheService.get(product.getCode());
if (Objects.isNull(priceInformation)) {
// retrieve PriceInformation
return null; // TODO replace with real retrieval result
} else {
return priceInformation;
}
} |
هذا مثال موجز على استخدام Hybris Reg
ion Cache.
إذا وجدت المحتوى مفيدًا، تأكد من متابعتنا لمزيدمن الشروحات العملية.