上一節(jié)我們分析了廣告索引的維護(hù)有2種,全量索引加載和增量索引維護(hù)。因為廣告檢索是廣告系統(tǒng)中最為重要的環(huán)節(jié),大家一定要認(rèn)真理解我們索引設(shè)計的思路,接下來我們來編碼實現(xiàn)索引維護(hù)功能。
我們來定義一個接口,來接收所有index的增刪改查操作,接口定義一個范型,來接收2個參數(shù),K代表我們索引的健值,V代表返回值。
/*** IIndexAware for 實現(xiàn)廣告索引的增刪改查** @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang | 若初</a>*/
public interface IIndexAware<K, V> {/*** 通過key 獲取索引*/V get(K key);/*** 添加索引* @param key* @param value*/void add(K key, V value);/*** 更新索引*/void update(K key, V value);/*** 刪除索引*/void delete(K key, V value);
}
我們一定要知道,并不是所有的數(shù)據(jù)庫表都需要創(chuàng)建索引,比如User表我們在數(shù)據(jù)檢索的時候其實是不需要的,當(dāng)然也就沒必要創(chuàng)建索引,并且,也不是表中的所有字段都需要索引,這個也是根據(jù)具體的業(yè)務(wù)來確定字段信息,比如我們接下來要編寫的推廣計劃索引中,推廣計劃名稱就可以不需要。下面,我們來實現(xiàn)我們的第一個正向索引。
/*** AdPlanIndexObject for 推廣計劃索引對象* 這個索引對象我們沒有添加 推廣計劃名稱* @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang | 若初</a>*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class AdPlanIndexObject {private Long planId;private Long userId;private Integer planStatus;private Date startDate;private Date endDate;/*** 根據(jù)實際字段來更新索引*/public void update(AdPlanIndexObject newObject) {if (null != newObject.getPlanId()) {this.planId = newObject.getPlanId();}if (null != newObject.getUserId()) {this.userId = newObject.getUserId();}if (null != newObject.getPlanStatus()) {this.planStatus = newObject.getPlanStatus();}if (null != newObject.getStartDate()) {this.startDate = newObject.getStartDate();}if (null != newObject.getEndDate()) {this.endDate = newObject.getEndDate();}}
}
- 然后創(chuàng)建推廣計劃索引實現(xiàn)類,并實現(xiàn)IIndexAware接口。
/*** AdPlanIndexAwareImpl for 推廣計劃索引實現(xiàn)類** @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang | 若初</a>*/
@Slf4j
@Component
public class AdPlanIndexAwareImpl implements IIndexAware<Long, AdPlanIndexObject> {private static Map<Long, AdPlanIndexObject> planIndexObjectMap;/*** 因為操作索引的過程中有可能對索引進(jìn)行更新,為了防止多線程造成的線程不安全問題,我們不能使用hashmap,需要實現(xiàn)ConcurrentHashMap*/static {planIndexObjectMap = new ConcurrentHashMap<>();}@Overridepublic AdPlanIndexObject get(Long key) {return planIndexObjectMap.get(key);}@Overridepublic void add(Long key, AdPlanIndexObject value) {log.info("AdPlanIndexAwareImpl before add::{}", planIndexObjectMap);planIndexObjectMap.put(key, value);log.info("AdPlanIndexAwareImpl after add::{}", planIndexObjectMap);}@Overridepublic void update(Long key, AdPlanIndexObject value) {log.info("AdPlanIndexAwareImpl before update::{}", planIndexObjectMap);//查詢當(dāng)前的索引信息,如果不存在,直接新增索引信息AdPlanIndexObject oldObj = planIndexObjectMap.get(key);if (null == oldObj) {planIndexObjectMap.put(key, value);} else {oldObj.update(value);}log.info("AdPlanIndexAwareImpl after update::{}", planIndexObjectMap);}@Overridepublic void delete(Long key, AdPlanIndexObject value) {log.info("AdPlanIndexAwareImpl before delete::{}", planIndexObjectMap);planIndexObjectMap.remove(key);log.info("AdPlanIndexAwareImpl after delete::{}", planIndexObjectMap);}
}
至此,我們已經(jīng)完成了推廣計劃的索引對象和索引操作的代碼編寫,大家可以參考上面的示例,依次完成推廣單元、推廣創(chuàng)意、地域、興趣、關(guān)鍵詞以及推廣創(chuàng)意和推廣單元的關(guān)聯(lián)索引,或者可直接從 Github傳送門 / Gitee傳送門 下載源碼。
按照上述代碼展示,我們已經(jīng)實現(xiàn)了所有的索引操作的定義,但是實際情況中,我們需要使用這些服務(wù)的時候,需要在每一個Service中@Autowired注入,我們那么多的索引操作類,還不包含后續(xù)還有可能需要新增的索引維度,工作量實在是太大,而且不方便維護(hù),作為一個合格的程序員來說,這是非常不友好的,也許會讓后續(xù)的開發(fā)人員罵娘。
為了防止后續(xù)被罵,我們來編寫一個索引緩存工具類com.sxzhongf.ad.index.IndexDataTableUtils,通過這個索引緩存工具類來實現(xiàn)一次注入,解決后顧之憂。要實現(xiàn)這個工具類,我們需要實現(xiàn)2個接口:org.springframework.context.ApplicationContextAware和org.springframework.core.PriorityOrdered
- org.springframework.context.ApplicationContextAware, 統(tǒng)一通過實現(xiàn)該接口的類,來操作Spring容器以及其中的Bean實例。
在Spring中,以Aware為后綴結(jié)束的類,大家可以簡單的理解為應(yīng)用程序想要XXX,比如ApplicationContextAware代表應(yīng)用程序想要ApplicationContext,BeanFactoryAware 表示應(yīng)用程序想要BeanFactory...等等 - org.springframework.core.PriorityOrdered組件加載順序,也可以使用org.springframework.core.Ordered
以下代碼為我們的工具類:
package com.sxzhongf.ad.index;import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.PriorityOrdered;
import org.springframework.stereotype.Component;import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;/*** IndexDataTableUtils for 所有索引服務(wù)需要緩存的Java Bean** 使用方式:* 獲取{@link com.sxzhongf.ad.index.creative.CreativeIndexAwareImpl}索引服務(wù)類* 如下:* {@code* IndexDataTableUtils.of(CreativeIndexAwareImpl.class)* }* @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang | 若初</a>*/
@Component
public class IndexDataTableUtils implements ApplicationContextAware, PriorityOrdered {//注入ApplicationContextprivate static ApplicationContext applicationContext;/*** 定義用于保存所有Index的Map* Class標(biāo)示我們的索引類*/private static final Map<Class, Object> dataTableMap = new ConcurrentHashMap<>();@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {IndexDataTableUtils.applicationContext = applicationContext;}/*** 獲取索引服務(wù)緩存*/public static <T> T of(Class<T> klass) {T instance = (T) dataTableMap.get(klass);//如果獲取到索引bean,直接返回當(dāng)前beanif (null != instance) {return instance;}//首次獲取索引bean為空,寫入MapdataTableMap.put(klass, bean(klass));return (T) dataTableMap.get(klass);}/*** 獲取Spring 容器中的Bean對象*/private static <T> T bean(String beanName) {return (T) applicationContext.getBean(beanName);}/*** 獲取Spring 容器中的Bean對象*/private static <T> T bean(Class klass) {return (T) applicationContext.getBean(klass);}@Overridepublic int getOrder() {return PriorityOrdered.HIGHEST_PRECEDENCE;}
}
轉(zhuǎn)載于:https://www.cnblogs.com/zhangpan1244/p/11318481.html
總結(jié)
以上是生活随笔為你收集整理的[Spring cloud 一步步实现广告系统] 13. 索引服务编码实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。