spring拦截方法的配置和实现

来源:互联网 发布:淘宝衣服款式怎么设置 编辑:程序博客网 时间:2024/05/16 08:19

最近项目要求,对于某个某些方法执行异步任务,就是说,对于那些接口(调用时间长,没必要立刻得到接口执行结果的接口)执行异步调用,这样主线程就会执行的时间就很短了,我的实现呢是用spring环绕通知拦截所有的方法(这些方法先用spring aop进行切片)、

配置如下:

 <!-- 方法拦截器 -->   <!--  <bean id="methodInterceptor" class="com.paic.icore.aops.common.biz.util.MethodInterceptor"></bean>    <aop:config>            <aop:pointcut expression="execution(* com.paic.icore.aops.*.service.impl.*.*(..))" id="servicePointCut"/>            <aop:aspect id="loggeraspect" ref="methodInterceptor">                <aop:around method="logger" pointcut-ref="servicePointCut"/>            </aop:aspect>    </aop:config> -->
相应的拦截器的代码为:

package com.paic.icore.aops.common.biz.util;import java.lang.reflect.Method;import java.util.HashMap;import java.util.Map;import net.sf.json.JSONArray;import net.sf.json.JSONObject;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.reflect.MethodSignature;import org.springframework.beans.factory.annotation.Autowired;import com.paic.icore.aops.common.jedis.message.MsgRedisPoolUtils;public class MethodInterceptor {@Autowiredprivate AopsLogger logger;@Autowiredprivate MsgRedisPoolUtils msgRedis;public Object logger(ProceedingJoinPoint pjp) throws Throwable {Object obj = null;MethodSignature joinPointObject = (MethodSignature) pjp.getSignature();          Method method = joinPointObject.getMethod();    boolean flag = method.isAnnotationPresent(AsynchTask.class) ;            if(flag){        //这里要判断是否是异步线程调用,还是程序调用        String flagValue = method.getName()+JSONArray.fromObject(pjp.getArgs()).toString();        String isDo = msgRedis.get(flagValue);        if(null==isDo || "".equals(isDo))//表示是程序调用        {        // 获取目标对象类名        String clazzName = pjp.getTarget().getClass().getName();        // 获取方法名String methodName = pjp.getSignature().getName();logger.trace("================拦截到" + clazzName + "的" + methodName + "方法");        // 获取执行方法的参数        Object[] args = pjp.getArgs();            StringBuffer params =new StringBuffer();//参数的数组            Object[] paramsType = method.getParameterTypes();            for(int i=0;i<paramsType.length;i++)            {            String type = (paramsType[i].toString()).substring((paramsType[i].toString()).lastIndexOf(".")+1);            params.append(type+"|"+args[i]);            logger.trace(i+"=================params.length()="+params.length());            if(i!=(paramsType.length-1)){            params.append("#");            }            System.out.println("***********" + args[i]);logger.trace("====方法"+methodName+"的参数为:"+args[i]);            }        long taskId = System.currentTimeMillis();            msgRedis.saveStrToListJedis("asynchTask", String.valueOf(taskId));            Map<String,String> map =new HashMap<String, String>();            AsynchTask methodInterceptor = method.getAnnotation(AsynchTask.class);                 String interfaceName = methodInterceptor.value();            map.put("className", clazzName);            map.put("methodName", methodName);            map.put("params", params.toString());            map.put("interfaceName", interfaceName);//这里把那个方法所在的接口别名拿到            msgRedis.saveHashMapToJedis(String.valueOf(taskId), map, -1);            obj = true;        }        else if(null!=isDo)//表示是异步任务调用        {        obj = pjp.proceed();//放方法过去        }        }        else//没有加那个拦截方法的注解的        {        obj = pjp.proceed();//放方法过去        }return obj;}}

把执行的方法放进缓存系统后,再合适的时机反射调用即可(这里用得是spring的task任务机制,1秒一次滴)


package com.paic.icore.aops.task.apptask.action;import java.lang.reflect.Method;import java.util.Date;import java.util.Map;import net.sf.json.JSONArray;import org.springframework.beans.factory.BeanFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.scheduling.annotation.Scheduled;import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import org.springframework.stereotype.Component;import com.paic.icore.aops.common.biz.util.AopsLogger;import com.paic.icore.aops.common.biz.util.DateUtil;import com.paic.icore.aops.common.jedis.message.MsgRedisPoolUtils;import com.paic.icore.aops.points.service.IncomePointService;import com.paic.pafa.app.lwc.core.context.support.PafaApplicationContext;import com.paic.pafa.biz.AppContext;import com.paic.pafa.web.BaseRest;//测试异步调用程序@Componentpublic class AsynchTaskAction extends BaseRest {@Autowiredprivate AopsLogger logger;//注入线程池@Autowiredprivate ThreadPoolTaskExecutor taskExecutor;@Autowiredprivate MsgRedisPoolUtils msgRedis;@Autowiredprivate IncomePointService incomePointService;@Scheduled(cron = "0/1 * * * * ?")public void doAsynchTask(){int count =taskExecutor.getActiveCount(); int maxpollsize = taskExecutor.getMaxPoolSize();count =taskExecutor.getActiveCount();logger.tasklog("调用接口:doTest:当前活动线程数:count="+count);logger.tasklog("线程池允许的最大线程数:maxpollsize="+maxpollsize);if(count<maxpollsize){taskExecutor.execute(new Runnable() {@Overridepublic void run() {String taskId ="";synchronized (this) {taskId=msgRedis.rpopFromList("asynchTask");}if(taskId!=null && !"".equals(taskId)){logger.tasklog("从处理序列asynchTask抛出的taskId="+taskId);//新建一个线程IDlong threadId = Thread.currentThread().getId();//保存当前线程的IDmsgRedis.saveStrToStringJedis(String.valueOf(threadId), String.valueOf(threadId), 0);Map<String, String> paramsMap = msgRedis.getHashMapFromJedis(taskId, "doEstablishAccount");if(paramsMap!=null){String className =  paramsMap.get("className");String methodName = paramsMap.get("methodName");String params =  paramsMap.get("params");String interfaceName = paramsMap.get("interfaceName");logger.tasklog("====调用类"+className);logger.tasklog("====调用方法"+methodName);logger.tasklog("=======相关参数"+params);logger.tasklog("=======接口别名字"+interfaceName);try {//得到对象 Class c = Class.forName(className); Object[] methodPramas;Class[] parameterTypes =new Class[]{};if(null==params || "".equals(params))//执行的方法没有参数{methodPramas = new Object[]{};}else{String[] paramStr = params.split("#");logger.tasklog("===========参数paramStr的长度="+paramStr.length);parameterTypes = new Class[paramStr.length];methodPramas = new Object[paramStr.length];for(int i=0;i<paramStr.length;i++){String[] str = paramStr[i].split("\\|");String type = str[0];String param = str[1];logger.tasklog("===========参数param"+param);logger.tasklog("===========参数type"+type);if(type.equals("String")){methodPramas[i]=param;parameterTypes[i] = String.class;}else if(type.equals("int")){methodPramas[i]=Integer.parseInt(param);parameterTypes[i] = int.class;}else if(type.equals("Date")){Date date = DateUtil.formatStringToDate(param, "yyyy-MM-dd HH:mm:ss");methodPramas[i]=date;parameterTypes[i] = Date.class;}else if(type.equals("Long")){methodPramas[i]=Long.parseLong(param);parameterTypes[i] = Long.class;}}}logger.tasklog("#################参数parameterTypes"+parameterTypes);//获取到方法对象,假设方法的参数是一个int,method名为setAge Method interfaceMethod = c.getMethod(methodName, parameterTypes);//执行方法 logger.tasklog("#################开始反射调用方法)))))))");PafaApplicationContext context = (PafaApplicationContext) AppContext.getInstance().getApplicationContext();BeanFactory factory = (BeanFactory) context; Object obj = factory.getBean(interfaceName);  Method method = getImplMehodByInterMehtod(obj, interfaceMethod);//开始往redis里面增加识别标示String flag = method.getName()+JSONArray.fromObject(methodPramas).toString();String isDo = msgRedis.get(flag);if(null==isDo || "".equals(isDo))//异步第一次执行{msgRedis.saveStrToStringJedis(flag, String.valueOf(1), 0);}else if(null!=isDo && (Integer.parseInt(isDo)<6))//异步1~5次执行{msgRedis.saveStrToStringJedis(flag, String.valueOf(Integer.parseInt(isDo)+1), 0);}else{logger.tasklog("此异步任务已经执行了5次,将不再 执行,taskId="+taskId);msgRedis.deleteJedisByKey(taskId, "doTest");//这里删掉hash里面的值return;}Object resultObj = method.invoke(obj, methodPramas);boolean invokeResult = (Boolean) resultObj;if(invokeResult){//成功了msgRedis.deleteJedisByKey(taskId, "doAsynchTask");//这里删掉hash里面的值}else{//失败了(下次再来一次,直到成功)msgRedis.saveStrToListJedis("asynchTask", taskId);}logger.tasklog("#########resultObj="+resultObj);logger.tasklog("#########invokeResult="+invokeResult);} catch (Exception e) {logger.error("======反射调用"+className+"类的"+methodName+"异常,参数为"+params+"e="+e);}}}else{logger.tasklog("###处理序列asynchTask没有内容,本次操作停止...");return;}}});logger.tasklog("AsynchTaskAction --> doTest");}}//通过接口方法名,拿到实现类的方法private Method getImplMehodByInterMehtod(Object obj,Method interfaceMethod ) throws SecurityException, NoSuchMethodException{return obj.getClass().getMethod(interfaceMethod.getName(), interfaceMethod.getParameterTypes());}}

其中方法上用到了一个注解,就是自定义注解

注解定义如下:

package com.paic.icore.aops.common.biz.util;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME)public @interface AsynchTask {//接口的实现类的别名String value();}

这个注解必须加在service所对应的接口方发上,就是说,拦截那个方法把这个注解加上即可


经测试功能ok

0 0
原创粉丝点击