Aop指面向切面編程双妨,在spring mvc 里已經(jīng)出現(xiàn),springBoot作為體系之一叮阅,也包含AOP刁品。在一個Web應(yīng)用中,我希望記錄所有請求的遠(yuǎn)端地址浩姥,請求客戶端類型挑随,請求URI等記錄,一方面是為了做安全記錄勒叠,同時也可以提供后期考慮數(shù)據(jù)分析的基礎(chǔ)數(shù)據(jù)兜挨,具體可以通過Headers信息獲取。常見的比較重要的頭信息包括 user-agent, accept等眯分,其他如URI拌汇,queryString 等在serveletRequest中得到桑涎。如果單獨考慮每個方法里附加方法棵红,太過笨拙,AOP的特性提供了很好的方案壕探∑可以按照包与倡,類,方法昆稿,注解各個級別作為切點纺座,攔截訪問請求,做附加處理溉潭。當(dāng)然比驻,現(xiàn)實中各種項目也是通過AOP實現(xiàn)類似的功能该溯,包括訪問日志記錄,驗證頭信息别惦,數(shù)據(jù)庫SQL分析統(tǒng)計狈茉,redis請求統(tǒng)計等。
基本功能已經(jīng)完成掸掸,中間有遇到AOP不生效的情況氯庆,查找相關(guān)資料,有建議添加配置項spring.aop.auto=true , spring.aop.proxy-target-class=true
扰付,后者是使用CGLIB代理堤撵,可能有性能下降。其實都不需要這些配置羽莺,默認(rèn)是生效的实昨,后面解釋原因;還有建議添加@EnableProxyTargetClass
盐固,原因也類似荒给;以及建議添加@ComponentScan
覆蓋AOP目錄。以上可能是在某些情況下的適用方案刁卜。這次遇到的問題其實是切入條件不正確志电,在相關(guān)例子中缺少了public前綴,導(dǎo)致的不生效蛔趴。正確是:@Pointcut("execution (public * com.igoso.me.gallery.controller.*.*(..))")
挑辆。
另外有個缺陷是,為查詢記錄孝情,添加了查詢的HTTP請求鱼蝉,本身也會被記錄其中,后續(xù)再考慮在入庫之前進(jìn)行過濾箫荡,目前沒有影響蚀乔。
補充:多個Aop可以使用
@Order(n)
,來控制順序菲茬。
如下是整個Aspect的代碼:
/**
* created by igoso at 2018/5/26
**/
@Aspect
@Component
public class HttpLogAspect {
private static final Logger LOGGER = LoggerFactory.getLogger("HTTP_LOG");
@Resource
private HeaderDetailDao headerDetailDao;
@Pointcut("execution (public * com.igoso.me.gallery.controller.*.*(..))")
public void log() {
}
@Before("log()")
public void doBefore(JoinPoint joinPoint) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (null == attributes) {
LOGGER.error("get servlet request attributes null");
return;
}
HttpServletRequest request = attributes.getRequest();
Map<String,String> headers = new HashMap<>();
String name;
request.getAttributeNames();
for (Enumeration e = request.getHeaderNames(); e.hasMoreElements();) {
name = e.nextElement().toString();
headers.put(name, request.getHeader(name));
}
headers.put("uri", request.getRequestURI());
headers.put("queryString", request.getQueryString());
headers.put("remoteAddr", request.getRemoteAddr());
headers.put("method", request.getMethod());
headers.put("remoteHost",request.getRemoteHost());
headers.put("remotePort",String.valueOf(request.getRemotePort()));
headers.put("protocol",request.getProtocol());
HeaderDetail headerDetail = new HeaderDetail(headers, JSON.toJSONString(headers));
LOGGER.debug(JSON.toJSONString(headers,true));
try {
headerDetailDao.insert(headerDetail);
} catch (Exception e) {
LOGGER.error("insert header detail error:{}",e);
}
}
}
/**
* created by igoso at 2018/5/26
**/
@Getter
@Setter
@NoArgsConstructor
public class HeaderDetail extends Entity{
private String acceptLanguage;
private String method;
private String remoteHost;
private String remotePort;
private String remoteAddr;
private String queryString;
private String uri;
private String accept;
private String localHost;
private String acceptEncoding;
private String userAgent;
private String protocol;
private String extensions;//json
public HeaderDetail(Map<String,String> origin, String extensions) {
this.acceptLanguage = origin.get(HeaderAttributes.ACCEPT_LANGUAGE);
this.method = origin.get(HeaderAttributes.METHOD);
this.remoteAddr = origin.get(HeaderAttributes.REMOTE_ADDR);
this.remoteHost = origin.get(HeaderAttributes.REMOTE_HOST);
this.remotePort = origin.get(HeaderAttributes.REMOTE_PORT);
this.queryString = origin.get(HeaderAttributes.QUERY_STRING);
this.uri = origin.get(HeaderAttributes.URI);
this.accept = origin.get(HeaderAttributes.ACCEPT);
this.localHost = origin.get(HeaderAttributes.LOCAL_HOST);
this.acceptEncoding = origin.get(HeaderAttributes.ACCEPT_ENCODING);
this.userAgent = origin.get(HeaderAttributes.USER_AGENT);
this.protocol = origin.get(HeaderAttributes.PROTOCOL);
this.extensions = extensions; //other
}
private class HeaderAttributes{
static final String ACCEPT_LANGUAGE = "accept-language";
static final String METHOD = "method";
static final String REMOTE_ADDR = "remoteAddr";
static final String REMOTE_HOST = "remoteHost";
static final String REMOTE_PORT = "remotePort";
static final String QUERY_STRING = "queryString";
static final String URI = "uri";
static final String ACCEPT = "accept";
static final String LOCAL_HOST = "host";
static final String ACCEPT_ENCODING = "accept-encoding";
static final String USER_AGENT = "user-agent";
static final String PROTOCOL = "protocol";
}
}