SpringAOP筆記

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"/>  



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章