AOP切面详解
一、spring-aop.xml文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:task="http://www.springframework.org/schema/task" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd "> <!-- 启动@AspectJ支持 --> <aop:aspectj-autoproxy proxy-target-class="true"/> <context:component-scan base-package="hongmoshui.com.cnblogs.www.base.aop" /> </beans>
二、spring-mybatis.xml文件和spring-mvc.xml文件中,分别导入spring-aop.xml的配置
spring-mybatis.xml【service和dao层的注解有效】:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"> <!--读取jdbc资源文件 --> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <!-- 允许JVM参数覆盖 --> <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" /> <!-- 忽略没有找到的资源文件 --> <property name="ignoreResourceNotFound" value="true" /> <!-- 配置资源文件 --> <property name="locations"> <list> <value>classpath:properties/jdbc.properties</value> </list> </property> </bean> <!-- 配置数据源 --> <bean id="dataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close"> <!-- 数据库驱动 --> <property name="driverClass" value="${master.jdbc.driver}" /> <!-- 相应驱动的jdbcUrl --> <property name="jdbcUrl" value="${master.jdbc.url}" /> <!-- 数据库的用户名 --> <property name="username" value="${master.jdbc.username}" /> <!-- 数据库的密码 --> <property name="password" value="${master.jdbc.password}" /> <!-- 检查数据库连接池中空闲连接的间隔时间,单位是分,默认值:240,如果要取消则设置为0 --> <property name="idleConnectionTestPeriod" value="60" /> <!-- 连接池中未使用的链接最大存活时间,单位是分,默认值:60,如果要永远存活设置为0 --> <property name="idleMaxAge" value="30" /> <!-- 每个分区最大的连接数 --> <!-- 判断依据:请求并发数 --> <property name="maxConnectionsPerPartition" value="100" /> <!-- 每个分区最小的连接数 --> <property name="minConnectionsPerPartition" value="5" /> </bean> <!-- 扫描包 --> <context:component-scan base-package="hongmoshui.com.cnblogs.www.*.service.impl,hongmoshui.com.cnblogs.www.*.dao.impl" /> <!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <!-- 自动扫描mapping.xml文件 --> <property name="mapperLocations" value="classpath:mappers*/*Mapper.xml"></property> </bean> <!-- DAO接口所在包名,Spring会自动查找其下的类 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="hongmoshui.com.cnblogs.www.base.dao.impl,hongmoshui.com.cnblogs.www.work.dao" /> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property> </bean> <!-- 定义事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 导入aop配置 --> <import resource="classpath*:/spring/spring-aop.xml" /> </beans>
spring-mvc.xml【controller层的注解有效】:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd "> <!-- 配置注解驱动 --> <mvc:annotation-driven/> <!-- 扫描controller包 --> <context:component-scan base-package="hongmoshui.com.cnblogs.www.*.controller"/> <!-- 配置视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/"/> <property name="suffix" value=".jsp"/> </bean> <!-- 对静态资源文件的访问 ,不支持访问WEB-INF目录 --> <!-- <mvc:default-servlet-handler/> --> <!-- 对静态资源文件的访问 ,可以访问任何目录,包括访问WEB-INF目录 --> <mvc:resources mapping="/resources/**" location="/resources/" /> <!-- 导入aop配置 --> <import resource="classpath*:/spring/spring-aop.xml" /> </beans>
三、自定义注解类【连接点】
package hongmoshui.com.cnblogs.www.work.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited public @interface Log { /** * 方法名 * @author 洪墨水 */ public String name() default ""; /** * 描述 * @author 洪墨水 */ public String description() default "no description"; }
参数定义:
@Target 注解
功能:指明了修饰的这个注解的使用范围,即被描述的注解可以用在哪里。
ElementType的取值包含以下几种:
-
TYPE:类,接口或者枚举
-
FIELD:域,包含枚举常量
-
METHOD:方法
-
PARAMETER:参数
-
CONSTRUCTOR:构造方法
-
LOCAL_VARIABLE:局部变量
-
ANNOTATION_TYPE:注解类型
-
PACKAGE:包
@Retention 注解
功能:指明修饰的注解的生存周期,即会保留到哪个阶段。
RetentionPolicy的取值包含以下三种:
-
SOURCE:源码级别保留,编译后即丢弃。
-
CLASS:编译级别保留,编译后的class文件中存在,在jvm运行时丢弃,这是默认值。
-
RUNTIME: 运行级别保留,编译后的class文件中存在,在jvm运行时保留,可以被反射调用。
@Documented 注解
功能:指明修饰的注解,可以被例如javadoc此类的工具文档化,只负责标记,没有成员取值。
@Inherited注解
功能:允许子类继承父类中的注解。
四、自定义切面类
package hongmoshui.com.cnblogs.www.base.aop; import java.io.IOException; import java.lang.reflect.Method; import java.util.Calendar; import org.apache.log4j.Logger; 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.Pointcut; import org.springframework.stereotype.Component; import com.alibaba.fastjson.JSON; import hongmoshui.com.cnblogs.www.base.utils.TimeUtil; import hongmoshui.com.cnblogs.www.work.annotation.Log; /** * 日志注解的切面类 * @author 洪墨水 */ @Aspect @Component public class LogAspect { /** * 日志记录log */ public transient Logger log = Logger.getLogger(getClass()); @Around(value = "@annotation(l)", argNames = "l") public Object aroundBase(ProceedingJoinPoint point, Log l) { RecordMessage recordMessage = new RecordMessage(); Long startTime = System.currentTimeMillis(); Object object = null; try { /* 记录下当前时间 作为请求起始时间 */ recordMessage.setRequestTime(TimeUtil.getLongDateString(Calendar.getInstance().getTime())); /* 获取请求的信息 */ getRequestParams(point, recordMessage); /* 执行请求的方法 */ object = point.proceed(); /* 记录下当前时间 作为响应时间 */ recordMessage.setResponseTime(TimeUtil.getLongDateString(Calendar.getInstance().getTime())); /* 记录响应参数 */ recordMessage.setResponseParames(object == null ? "" : JSON.toJSONString(object)); } catch (Throwable e) { log.warn("proceed GW Interface throwable, ", e); } finally { Long endTime = System.currentTimeMillis(); recordMessage.setCostTime(endTime - startTime); /* 记录接口日志 */ log.info(recordMessage.toString()); } return object; } /** * 从切点中解析出该切点对应的方法 * @param point point * @throws ClassNotFoundException * @throws IOException * @author 洪墨水 */ private void getRequestParams(ProceedingJoinPoint point, RecordMessage recordMessage) throws ClassNotFoundException, IOException { /* 类名 */ String targetObject = point.getTarget().getClass().getName(); /* 方法名 */ String methodName = point.getSignature().getName(); recordMessage.setTargetObject(targetObject); recordMessage.setMethod(methodName); Object[] args = point.getArgs(); Class<?> targetClass = Class.forName(targetObject); Method[] methods = targetClass.getMethods(); StringBuilder requestBuilder = new StringBuilder(0); /** * 遍历方法 获取能与方法名相同且请求参数个数也相同的方法 */ for (Method method : methods) { if (!method.getName().equals(methodName)) { continue; } Class<?>[] classes = method.getParameterTypes(); if (classes.length != args.length) { continue; } for (int index = 0; index < classes.length; index++) { requestBuilder.append(args[index] == null ? "" : JSON.toJSONString(args[index])); } recordMessage.setRequestParames(requestBuilder.toString()); } return; } @Pointcut(value = "execution(* hongmoshui.com.cnblogs.www.work.service.impl.*.*(..))") public void getValuePointCut() { } @After(value = "getValuePointCut()") public void after() { System.out.println("方法执行结束..."); } } /** * 日志记录对象 * @author 洪墨水 */ class RecordMessage { /** * 请求的方法 */ private String method; /** * 请求方法所在的对象 */ private String targetObject; /** * 请求参数 */ private String requestParames; /** * 请求时间 */ private String requestTime; /** * 响应时间 */ private String responseTime; /** * 响应参数 */ private String responseParames; /** * 请求的来源IP */ private String requestIp; /** * 方法执行的耗时,毫秒 */ private long costTime; /** * 请求的方法 */ public String getMethod() { return method; } /** * 请求的方法 */ public void setMethod(String method) { this.method = method; } /** * 请求方法所在的对象 */ public String getTargetObject() { return targetObject; } /** * 请求方法所在的对象 */ public void setTargetObject(String targetObject) { this.targetObject = targetObject; } /** * 请求参数 */ public String getRequestParames() { return requestParames; } /** * 请求参数 */ public void setRequestParames(String requestParames) { this.requestParames = requestParames; } /** * 请求时间 */ public String getRequestTime() { return requestTime; } /** * 请求时间 */ public void setRequestTime(String requestTime) { this.requestTime = requestTime; } /** * 响应时间 */ public String getResponseTime() { return responseTime; } /** * 响应时间 */ public void setResponseTime(String responseTime) { this.responseTime = responseTime; } /** * 响应参数 */ public String getResponseParames() { return responseParames; } /** * 响应参数 */ public void setResponseParames(String responseParames) { this.responseParames = responseParames; } /** * 请求的来源IP */ public String getRequestIp() { return requestIp; } /** * 请求的来源IP */ public void setRequestIp(String requestIp) { this.requestIp = requestIp; } /** * 方法执行的耗时,毫秒 */ public long getCostTime() { return costTime; } /** * 方法执行的耗时,毫秒 */ public void setCostTime(long costTime) { this.costTime = costTime; } /** * toString * @return String String * @author 洪墨水 */ @Override public String toString() { StringBuilder sBuilder = new StringBuilder(0); sBuilder.append("method=").append(method); sBuilder.append(", targetObject=").append(targetObject); sBuilder.append(", requestParames=").append(requestParames); sBuilder.append(", requestTime=").append(requestTime); sBuilder.append(", responseTime=").append(responseTime); sBuilder.append(", responseParames=").append(responseParames); sBuilder.append(", requestIp=").append(requestIp); sBuilder.append(", costTime=").append(costTime); return sBuilder.toString(); } }
时间工具类:
package hongmoshui.com.cnblogs.www.base.utils; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.TimeZone; import org.apache.commons.lang3.StringUtils; /** * 时间工具类 * @author 洪墨水 */ public class TimeUtil { private static int i = 0; /** * 日期转换成 yyyy-MM-dd HH:mm:ss+时区形式 如:2019-04-24 19:18:03+0800 * @param date 日期 * @return 按格式返回日期 * @author 洪墨水 */ public static String getDateString(Date date) { if (date == null) { return null; } SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssZ"); return dateFormat.format(date); } /** * 日期转换成 yyyy-MM-dd HH:mm:ss 形式 如:2019-04-24 19:18:03 * @param date 日期 * @return 按格式返回日期 * @author 洪墨水 */ public static String dateToString() { Calendar now = Calendar.getInstance(); now.set(Calendar.SECOND, now.get(Calendar.SECOND) + i); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); i++; if (i > 1) { i = 0; } return dateFormat.format(now.getTime()); } /** * 日期转换成 yyyy-MM-dd HH:mm:ss+时区形式 如:2019-04-24 19:18:03+0800 * @param date 日期 * @return 按格式返回日期 * @author 洪墨水 */ public static String getDateString(String date) { if (date == null) { return null; } return TimeUtil.getDateString(toDate(date, "yyyy-MM-dd HH:mm:ss")); } /** * * String转 Date * @param date 日期 * @param format 格式 * @return 转换后日期 * @author 洪墨水 */ public static Date toDate(String date, String format) { if (StringUtils.isEmpty(format)) { format = "yyyy-MM-dd HH:mm:ss"; } SimpleDateFormat df = new SimpleDateFormat(format); try { return df.parse(date); } catch (ParseException e) { return new Date(); } } /** * * String转 Date * @param date 日期 * @param format 格式 * @return 转换后日期 * @author 洪墨水 */ public static Date toDate(String date) { return toDate(date, null); } /** * 将带时区的时间字符串转换成系统所在时区的时间 如:2019-04-24 19:18:03+0700 转换到东八区的时间为:2019-04-24 * 20:18:03 * @param dateformat 日期格式 * @return 系统所在时区的时间 * @throws ParseException [参数说明] * @author 洪墨水 */ public static Date convertToLocalDate(String dateformat) throws ParseException { SimpleDateFormat dFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssZ"); Date date = dFormat.parse(dateformat); Calendar calendar = Calendar.getInstance(); calendar.setTime(date); calendar.setTimeZone(TimeZone.getDefault()); return calendar.getTime(); } /** * <获取当前时间N小时后的时间 > * @param n 小时 * @return 日期 * @author 洪墨水 */ public static Date getNextDate(int n) { Calendar now = Calendar.getInstance(); now.set(Calendar.HOUR_OF_DAY, now.get(Calendar.HOUR_OF_DAY) + n); return now.getTime(); } /** * <获取当前时间N天后的凌晨 > * @param n 天 * @return 日期 * @author 洪墨水 */ public static Date getMorningNextDate(int n) { Calendar now = Calendar.getInstance(); now.set(Calendar.DATE, now.get(Calendar.DATE) + n);// 设置时间向前进n天 now.set(Calendar.HOUR_OF_DAY, 0); now.set(Calendar.MINUTE, 0); now.set(Calendar.SECOND, 0); return now.getTime(); } /** * <获取当前时间N小时后的整点时间 > * @param n 小时 * @return 日期 * @author 洪墨水 */ public static Date getNextHour(int n) { Calendar now = Calendar.getInstance(); now.set(Calendar.DATE, now.get(Calendar.DATE)); now.set(Calendar.HOUR_OF_DAY, now.get(Calendar.HOUR_OF_DAY) + n);// 设置时间向前进n小时 return now.getTime(); } /** * <获取当前时间N天后的凌晨【精确到毫秒】 > * @param n 前进天数 * @return Date [日期] * @author 洪墨水 */ public static Date getMorningNextDateMillisecond(int n) { Calendar now = Calendar.getInstance(); now.set(Calendar.DATE, now.get(Calendar.DATE) + n);// 设置时间向前进n天 now.set(Calendar.HOUR_OF_DAY, 0); now.set(Calendar.MINUTE, 0); now.set(Calendar.SECOND, 0); now.set(Calendar.MILLISECOND, 0); return now.getTime(); } /** * 比较 * @param date 日期 * @return 是否是今天 * @author 洪墨水 */ public static boolean checkLastDate(Date date) { Date d = new Date(); Calendar current = Calendar.getInstance(); current.setTime(date); Calendar start = Calendar.getInstance(); Calendar end = Calendar.getInstance(); start.set(Calendar.YEAR, current.get(Calendar.YEAR)); start.set(Calendar.MONTH, current.get(Calendar.MONTH)); start.set(Calendar.DAY_OF_MONTH, current.get(Calendar.DAY_OF_MONTH)); start.set(Calendar.HOUR_OF_DAY, 0); start.set(Calendar.MINUTE, 0); start.set(Calendar.SECOND, 0); end.set(Calendar.YEAR, current.get(Calendar.YEAR)); end.set(Calendar.MONTH, current.get(Calendar.MONTH)); end.set(Calendar.DAY_OF_MONTH, current.get(Calendar.DAY_OF_MONTH)); end.set(Calendar.HOUR_OF_DAY, 23); end.set(Calendar.MINUTE, 59); end.set(Calendar.SECOND, 59); if (d.after(start.getTime()) && d.before(end.getTime())) { return true; } return false; } /** * 获取日期;格式:yyyy-MM-dd * @param date 日期 * @return String yyyy-MM-dd格式的日期字符串 * @author 洪墨水 */ public static String getDate(Date date) { SimpleDateFormat dFormat = new SimpleDateFormat("yyyy-MM-dd"); dFormat.setTimeZone(TimeZone.getDefault()); return dFormat.format(date); } /** * <获取年月> * @param date 时间 * @return String [获取年月] * @author 洪墨水 */ public static String getDateYearAndMonth(Date date) { SimpleDateFormat dFormat = new SimpleDateFormat("yyyy-MM"); dFormat.setTimeZone(TimeZone.getDefault()); return dFormat.format(date); } /** * 获取有效时间 * @return 有效时间 * @author 洪墨水 */ public static int getExpireTime() { Calendar cal = Calendar.getInstance(); cal.set(Calendar.HOUR_OF_DAY, 23); cal.set(Calendar.MINUTE, 59); cal.set(Calendar.SECOND, 59); return (int) ((cal.getTime().getTime() - new Date().getTime()) / 1000); } /** * <时间增加> * @param p 时间日期 * @param number 要增加数 * @param filed 域 * @return Date [增加后的时间] * @author 洪墨水 */ public static Date addDate(Date p, int number, int filed) { Calendar cal = Calendar.getInstance(); cal.setTime(p); cal.add(filed, number); return cal.getTime(); } /** * <时间戳转日期时间> * @param s 时间戳 * @return String [日期时间] * @author 洪墨水 */ public static String stampToDate(String s, String format) { if (StringUtils.isEmpty(format)) { format = "yyyy-MM-dd HH:mm:ss"; } String res; SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format); long lt = new Long(s); Date date = new Date(lt); res = simpleDateFormat.format(date); return res; } /** * 日期转换成 yyyy-MM-dd HH:mm:ss zzz+时区形式 如:2019-04-24 19:18:03 132+0800 * @param date 日期 * @return LongDate * @author 洪墨水 */ public static String getLongDateString(Date date) { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SZ"); return dateFormat.format(date); } }
aop切面类中的@Pointcut的用法:
格式:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)
括号中各个pattern分别表示:
- 修饰符匹配(modifier-pattern?)
- 返回值匹配(ret-type-pattern)可以为*表示任何返回值,全路径的类名等
- 类路径匹配(declaring-type-pattern?)
- 方法名匹配(name-pattern)可以指定方法名 或者 *代表所有, set* 代表以set开头的所有方法
- 参数匹配((param-pattern))可以指定具体的参数类型,多个参数间用“,”隔开,各个参数也可以用“*”来表示匹配任意类型的参数,如(String)表示匹配一个String参数的方法;(*,String) 表示匹配有两个参数的方法,第一个参数可以是任意类型,而第二个参数是String类型;可以用(..)表示零个或多个任意参数
- 异常类型匹配(throws-pattern?)
- 其中后面跟着“?”的是可选项
注:详细信息请看----切面AOP的切点@Pointcut用法
四、测试类
package hongmoshui.com.cnblogs.www.work.service.impl; import java.io.IOException; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.text.SimpleDateFormat; import java.util.Date; import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Logger; import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFCellStyle; import org.apache.poi.hssf.usermodel.HSSFFont; import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.util.CellRangeAddress; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import hongmoshui.com.cnblogs.www.base.dao.RedisClientDao; import hongmoshui.com.cnblogs.www.base.model.Result; import hongmoshui.com.cnblogs.www.work.annotation.Log; import hongmoshui.com.cnblogs.www.work.dao.TestDao; import hongmoshui.com.cnblogs.www.work.dao.TestQueryDao; import hongmoshui.com.cnblogs.www.work.model.UserInfo; import hongmoshui.com.cnblogs.www.work.service.TestService; @Service("testService") public class TestServiceImpl implements TestService { @Autowired private transient RedisClientDao redisClientDao;/** * 日志记录log */ public transient Logger log = Logger.getLogger(getClass()); @Log(name = "getValue") @Override public Result getValue(String key) { Result result = new Result(); Object obj = redisClientDao.get(key); if (obj != null) { result.setSuccess(true); result.setMessage("取出成功!"); result.put("value", obj); log.info("call redis get success! redis key:" + key + ",value:" + obj); } else { result.setSuccess(false); result.setMessage("取出失败!"); log.error("call redis get failed! redis key:" + key + ",value:" + obj); } return result; } }
测试结果:
2019-04-22 15:36:51 [hongmoshui.com.cnblogs.www.base.aop.LogAspect]-[INFO] method=getValue, targetObject=hongmoshui.com.cnblogs.www.work.service.impl.TestServiceImpl, requestParames="hongmoshui_01", requestTime=2019-04-22 15:36:51 134+0800, responseTime=2019-04-22 15:36:51 250+0800, responseParames={"message":"取出成功!","value":"我是01","success":true}, requestIp=null, costTime=119
方法执行结束...