注解结合AOP在方法前后打印日志
来源:互联网 发布:大学网络课程怎么快进 编辑:程序博客网 时间:2024/06/06 00:25
亮点:直接在方法上添加一行注解,就可以实现统计方法的执行时间,另外根据注解参数中属性来控制是否进行方法入参的校验
知识点:java注解+AOP+java 反射机制
特别注意点:如果要进行方法入参的校验,返回参数类定义中必须要有 A(Stirng a,String b)的构造方法,否则会报错,如果方法没有返回参数 请修改红色部分,为防止隐私我已经将所有类中包路径去除,使用时请自行修改。
步骤一:创建注解类
import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** * 计算方法调用时间注解 * name是业务名称描述,比如:调用下单接口 * isCheckParams 是否校验接口入参,如果是会调用BeanValidator.validate(obj);进行参数的校验 * Created by yunpeng.zhao on 2017/8/15. */@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.METHOD})public @interface TimeDiff { /** * 业务名称描述 * @return */ String name() default ""; /** * 是否对请求参数进行校验 * @return */ boolean isCheckParams() default false;}
步骤二:定义aop实现类
import org.aspectj.lang.JoinPoint;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.After;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.aspectj.lang.reflect.MethodSignature;import org.springframework.stereotype.Component;import java.lang.reflect.Constructor;import java.lang.reflect.Method;import java.lang.reflect.Type;import java.util.Date;/** * 计算方法调用时间切面 * @author yunpeng.zhao * @version $Id TimeDiffAop.java, v 0.1 2017-08-15 上午11:25 yp-tc-m-2651 Exp $$ */@Aspect@Componentpublic class TimeDiffAop { /** * 记录耗时变量 */ ThreadLocal<Long> time = new ThreadLocal<Long>(); private static final Logger LOGGER = LoggerFactory.getLogger(TimeDiffAop.class); /** * 在方法前记录时间并根据注解,是否校验参数 * @param joinPoint * @return */ @Before("@annotation(com.yeepay.g3.core.bc.trade.aop.TimeDiff)") public void beforeMethod(JoinPoint joinPoint){ } /** * 方法执行前后拦截 * @param pjp * @return */ @Around("@annotation(TimeDiff)") public Object aroundMethod(ProceedingJoinPoint pjp) throws Throwable { time.set(System.currentTimeMillis()); //获取TimeDiff注解中是否需要校验参数 try { Method method = getObjMethod(pjp); String name = method.getAnnotation(TimeDiff.class).name(); LOGGER.info("{}开始执行,开始时间:{}",name,DateUtils.getTimeStampStr(new Date(time.get()))); boolean isCheckParams = method.getAnnotation(TimeDiff.class).isCheckParams(); if (isCheckParams){ Type type = method.getGenericReturnType(); Object[] args = pjp.getArgs(); LOGGER.info("{}请求参数:{}",name, JSONUtils.toJsonString(args)); for (Object o : args) { try { BeanValidator.validate(o); } catch (IllegalArgumentException e) { LOGGER.error("参数验证错误", e); return getResponseObj(type, BCErrorInfoConstants.PARAM_VALIDATE_ERROR, e.getMessage()); } } } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (Throwable throwable) { throwable.printStackTrace(); } return pjp.proceed(); } private Method getObjMethod(JoinPoint joinPoint) throws ClassNotFoundException, NoSuchMethodException { String targetName = joinPoint.getTarget().getClass().getName(); Class targetClass = Class.forName(targetName); MethodSignature ms= (MethodSignature)joinPoint.getSignature(); String methodName = ms.getMethod().getName(); Class<?>[] par=ms.getParameterTypes(); return targetClass.getMethod(methodName,par); } /*此处根据方法的返回类型进行拼装返回,所以在返回参数中必须有构造函数
public Object getResponseObj(Type type,String retCode,String retMsg){ try { if (type != null){ String returnName = type.toString().replace("class ",""); LOGGER.info("返回类型是:{}",returnName); Class cls = Class.forName(returnName); Constructor con = cls.getConstructor(String.class, String.class); Object responseObj = con.newInstance(retCode, retMsg); return responseObj; } return null; } catch (Exception e) { throw BCException.PAY_PARAM_CVRT_ERROR; } } /** * 在方法后打印总耗时 * @param joinPoint */ @After("@annotation(com.yeepay.g3.core.bc.trade.aop.TimeDiff)") public void afterMethod(JoinPoint joinPoint){ try { Method method = getObjMethod(joinPoint); String name = method.getAnnotation(TimeDiff.class).name(); LOGGER.info("{}执行结束,结束时间:{},总耗时:{}ms",name, DateUtils.getLongDateStr(),System.currentTimeMillis()-time.get()); } catch (Exception e) { LOGGER.error("打印总耗时出现异常:{}",e); } }}
步骤三 在spring配置文件中开启aop 并能扫描到切面类
<aop:aspectj-autoproxy proxy-target-class="true"/><context:component-scanbase-package="com.yeepay.g3.core.bc.trade" />
步骤四:在方法上添加这个牛逼的注解就可以了
@Servicepublic class CompensateOrderFacadeImpl implements CompensateOrderFacade{ private static final Logger LOGGER = LoggerFactory.getLogger(CompensateOrderFacadeImpl.class); @Autowired private CompensateOrderBiz compensateOrderBiz; @TimeDiff(name = "赔付反查接口",isCheckParams = true) @Override public CompensateQueryResponseDTO queryOrgOrder(CompensateQueryRequestDTO query) { CompensateQueryResponseDTO response = new CompensateQueryResponseDTO(BCException.FAIL.getDefineCode(),BCException.FAIL.getMessage()); try { //1.反查流程 response = compensateOrderBiz.queryOrgOrder(query); } catch (BCException e) { LOGGER.error("赔付反查接口参数校验异常:{}",e); response.setRetCode(e.getDefineCode()); response.setRetMsg(e.getMessage()); } catch (Exception e) { LOGGER.error("赔付反查接口出现系统异常:{}",e); response.setRetCode(BCErrorInfoConstants.TRADE_COMPENSATE_QUERY_ERROR); response.setRetMsg(e.getMessage()); } return response; } @TimeDiff(name = "赔付接口",isCheckParams = true) @Override public CompensateOrderResponseDTO createCompensateOrder(CompensateOrderDTO order) { CompensateOrderResponseDTO responseDTO = new CompensateOrderResponseDTO(); return null; }}
步骤五;参数校验类
import java.util.Locale;import java.util.Set;import javax.validation.ConstraintViolation;import javax.validation.Validation;import javax.validation.Validator;import javax.validation.ValidatorFactory;import org.springframework.context.i18n.LocaleContextHolder;public class BeanValidator {private static Validator validator;static {ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();validator = validatorFactory.getValidator();}public static String getMergedMessage(Set set) {StringBuilder sb = new StringBuilder("");for (Object obj : set) {if (obj instanceof ConstraintViolation) {ConstraintViolation constraintViolation = (ConstraintViolation) obj;sb.append(constraintViolation.getPropertyPath());sb.append(" ");sb.append(constraintViolation.getMessage());sb.append("; ");}}return sb.toString();}/** * 根据Bean中的注解配置验证Bean的参数合法性 * * @param <E> * @param obj * 待验证对象 */@SuppressWarnings("unchecked")public static <E> void validate(Object obj) {Set<ConstraintViolation<E>> set = validator.validate((E) obj);if (set.size() != 0) {throw new IllegalArgumentException("验证参数合法性时出现异常["+ getMergedMessage(set)+ "]");}}}
大功告成:看效果图
2017-08-16 09:28:52,768 - com.yeepay.g3.core.bc.trade.aop.TimeDiffAop -10764 [main] INFO - 赔付反查接口开始执行,开始时间:2017-08-16 09:28:522017-08-16 09:28:52,775 - com.yeepay.g3.core.bc.trade.aop.TimeDiffAop -10771 [main] INFO - 赔付反查接口请求参数:[{"customerRequestId":"2017081000004","customerNumber":"10040007799"}]2017-08-16 09:28:52,795 - org.hibernate.validator.util.Version -10791 [main] INFO - Hibernate Validator 4.2.0.Final2017-08-16 09:28:53,005 - com.yeepay.g3.core.bc.trade.aop.TimeDiffAop -11001 [main] INFO - 赔付反查接口执行结束,结束时间:2017-08-16 09:28:53,总耗时:244ms
相关参考文章:
http://www.cnblogs.com/peida/archive/2013/04/24/3036689.html 注解相关
http://www.xdemo.org/springmvc-aop-annotation/ AOP相关
http://blog.csdn.net/meiyang1990/article/details/50562046 获取method方法
http://blog.csdn.net/shenyunsese/article/details/51133065 获取注解属性,此处主要是直接通过 下面代码 无法获取到annotation,怀疑跟JDK版本有关
MethodSignature ms=(MethodSignature) joinPoint.getSignature();
Method method=ms.getMethod();
method.getAnnotation(Log.
class
).name()
阅读全文
0 0
- 注解结合AOP在方法前后打印日志
- java注解结合aspectj AOP进行日志打印
- spring AOP切面编程在方法执行前后切入日志
- 从头认识Spring-3.5 简单的AOP日志实现(注解版)-某方法之前的前后记录日志
- aop注解简单日志
- 从头认识Spring-3.1 简单的AOP日志实现-某方法之前的前后记录日志
- 自定义注解和aop结合使用---自定义日志记录的实现
- spring mvc +spring aop结合注解的 用户操作日志记录
- JNI 在native方法中打印日志
- AOP实现数据库日志打印
- Tricks(二十五)—— decorator(在函数调用前后打印日志)
- 使用spring aop结合log4j做日志
- 使用spring aop结合log4j做日志
- 通过自定义注解利用AOP在springmvc中实现记录日志
- Spring2.5那些事之基于 AOP的方法级注解式日志配置
- Spring2.5那些事之基于AOP的方法级注解式日志配置
- Spring AOP 使用注解的方式实现用户日志的两种方法
- Spring MVC 集成 AOP,自定义注解,在切面获得方法参数,以及自定义注解的参数。
- Node.js基本模块crypto(加解密)
- Monthly Expense (最大值最小化+二分法)
- 博士第一年的计划
- 【BZOJ 1217】[HNOI2003]消防局的设立(贪心)
- python创建目录(文件夹)
- 注解结合AOP在方法前后打印日志
- jQuery实现div左右滑动
- mysql5.7解压版安装及重置密码(亲试,自整理)
- Sting&&StringBuffer&StringBuilder三者区别
- 全国省市联动
- 腾讯云免流搭建教程免流服务…
- 暑期ssh框架spring学习笔记五
- (整理)自动化测试(Cucumber+Watir)
- Java compiler level does not match the version of the installed Java project facet.