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
方法执行结束...

原文地址:https://www.cnblogs.com/hongmoshui/p/10694535.html