AOP記錄, 它可以做很多的事情. 留着查看
1.日誌處理
2.權限處理
3.限制,異常控制
package com.pahaoche.portal.qiantai.weizhang.aop;
import java.lang.reflect.Method;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.pahaoche.portal.base.memcached.MemcachedService;
@Aspect
@Component("systemLogAspect")
public class SystemLogAspect {
private Log logger = LogFactory.getLog(SystemLogAspect.class);
@Autowired
@Qualifier("memcachedService")
private MemcachedService memcachedService;
/**
* 頻繁請求控制
*/
@Pointcut("@annotation(com.pahaoche.portal.qiantai.weizhang.aop.FrequentRequestAsp)")
public void pointCutFrequentLog(){}
@Pointcut("@annotation(com.pahaoche.portal.qiantai.weizhang.aop.SystemControllerLog)")
public void pointCutMethod() {}
/**
* controller 執行消耗時間ms
*/
@Pointcut("execution(public * com.pahaoche.portal.qiantai.weizhang.controller.*Controller.*(..))")
public void pointCutUseTime(){}
/**
* service 方法執行消耗時間ms
*/
@Pointcut("execution(public * com.pahaoche.portal.base.weizhang.service..*.*(..))")
public void pointCutServiceUseTime(){}
@Before("pointCutMethod()")
public void doBefore() {
}
@Around("pointCutUseTime()")
public Object doAroundUseTime(ProceedingJoinPoint pjp) throws Throwable{
Long startTime = System.currentTimeMillis();
String ip = getRemoteAddr();
String className = pjp.getSignature().getDeclaringType().getName();
String methodName = pjp.getSignature().getName();
Object o = pjp.proceed();
Long endTime = System.currentTimeMillis();
logger.info("controller:"+methodName+"(),useTime:"+(endTime-startTime)+"ms."+"path:"+className+"."+methodName+"()"+";IP:"+ip);
return o;
}
@Around("pointCutServiceUseTime()")
public Object doAroundServiceUseTime(ProceedingJoinPoint pjp) throws Throwable{
Long startTime = System.currentTimeMillis();
String className = pjp.getSignature().getDeclaringType().getName();
String methodName = pjp.getSignature().getName();
Object o = pjp.proceed();
Long endTime = System.currentTimeMillis();
logger.info("service:"+methodName+"(),useTime:"+(endTime-startTime)+"ms."+"path:"+className+"."+methodName+"()");
return o;
}
@Around("pointCutFrequentLog()")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
String ip = getRemoteAddr();
String methodName = pjp.getSignature().getName();
Object o = null;
//IP不爲null時做判斷
if(StringUtils.isNotEmpty(ip) && checkIpMemcached(ip, methodName)){
logger.info("頻繁請求不處理. IP:"+ip+";methodName:"+methodName);
}else{
o = pjp.proceed();
}
return o;
}
private String getRemoteAddr(){
String ip = "";
if(null == RequestContextHolder.getRequestAttributes()
|| null == ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest()){
return ip;
}
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
ip = request.getHeader("x-forwarded-for");
if(StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
if(StringUtils.isNotEmpty(ip) && !"unknown".equalsIgnoreCase(ip)){
ip +="#Proxy-Client-IP";
}
}
if(StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
if(StringUtils.isNotEmpty(ip) && !"unknown".equalsIgnoreCase(ip)){
ip +="#WL-Proxy-Client-IP";
}
}
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
if(StringUtils.isNotEmpty(ip) && !"unknown".equalsIgnoreCase(ip)){
ip +="#HTTP_CLIENT_IP";
}
}
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
if(StringUtils.isNotEmpty(ip) && !"unknown".equalsIgnoreCase(ip)){
ip +="#HTTP_X_FORWARDED_FOR";
}
}
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
if(StringUtils.isNotEmpty(ip) && !"unknown".equalsIgnoreCase(ip)){
ip +="#RemoteAddr";
}
}
return ip;
/*
*
* 可是,如果通過了多級反向代理的話,X-Forwarded-For的值並不止一個,而是一串IP值,究竟哪個纔是真正的用戶端的真實IP呢?
答案是取X-Forwarded-For中第一個非unknown的有效IP字符串。
如:
X-Forwarded-For:192.168.1.110, 192.168.1.120, 192.168.1.130, 192.168.1.100
用戶真實IP爲: 192.168.1.110
*
*/
}
/**
* 如果6秒內同一個IP對同一個方法有請求,則不作處理
* @param ip
* @param methodName
* @return
*/
private boolean checkIpMemcached(String ip,String methodName){
String key =(ip+":"+methodName).replace(",", "%").replace(".", "$");
//wwwtest.pahaoche.com:202.69.18.197, 172.30.50.250:resultViolation
if(key.length() > 40){
logger.warn("Key too long. key="+key);
return false;
}
Long currentTime = System.currentTimeMillis();
int exp = 20 ; //過期時間, 單位秒
if(null == memcachedService.get(key)){
memcachedService.set(key,exp,currentTime);
}else{
Long oldTime = (Long)memcachedService.get(key);
if(currentTime - oldTime < (6*1000)){
return true;
}else{
memcachedService.set(key,exp,currentTime);
logger.info("更新IP:methodName緩存. key="+key);
}
}
return false;
}
/**
* 獲取註解中對方法的描述信息 用於Controller層註解
*
* @param joinPoint
* 切點
* @return 方法描述
* @throws Exception
*/
public static String getControllerMethodDescription(ProceedingJoinPoint joinPoint) throws Exception {
String targetName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
Class targetClass = Class.forName(targetName);
Method[] methods = targetClass.getMethods();
String description = "";
for (Method method : methods) {
if (method.getName().equals(methodName)) {
Class[] clazzs = method.getParameterTypes();
if (clazzs.length == arguments.length) {
description = method.getAnnotation(SystemControllerLog.class).description();
break;
}
}
}
return description;
}
}
applicationContext.xml中加入aop註解掃描,如果controller需要用到aop,將spring-mvc.xml配置即可。
<aop:aspectj-autoproxy proxy-target-class="true"/>