精华内容
下载资源
问答
  • 通过springboot的Aop面向切面实现彩色日志使用的场景 Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员...

    通过springboot的Aop面向切面实现彩色日志使用的场景

    Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,Spring Boot致力于在蓬勃发展的快速应用开发领域(rapid application development)成为领导者。
    在项目中我们脱离不开保留用户访问的相关信息,那么下文我们来一起实现springboot通过Aop面向切面实现彩色日志。

    • 我们在项目的resources文件夹下新建一个日志的配置文件命名为logback.xml

      logback.xml彩色日志是每天保留不同等级日志以及会记录实时日志内容,同时会将保存的内容打印在控制台,日志保留的有效期是15天,可自行配置,超过设置的天数会自动删除16天前的日志文件,其次保存的位置也可以自行配置

      	<?xml version="1.0" encoding="UTF-8"?>
      	<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
      	<!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true -->
      	<!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
      	<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false-->
      	<configuration  scan="true" scanPeriod="10 seconds">
      	
      	    <!--<include resource="org/springframework/boot/logging/logback/base.xml" />-->
      	
      	    <contextName>logback</contextName>
      	    <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
      	    <property name="log.path" value="D:/mylogs/logs" /><!--D:/mylogs/logs-->
      	
      	    <!-- 彩色日志 -->
      	    <!-- 彩色日志依赖的渲染类 -->
      	    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
      	    <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
      	    <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
      	    <!-- 彩色日志格式 -->
      	    <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
      	
      	
      	    <!--输出到控制台-->
      	    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
      	        <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
      	        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
      	            <level>info</level>
      	        </filter>
      	        <encoder>
      	            <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
      	            <!-- 设置字符集 -->
      	            <charset>UTF-8</charset>
      	        </encoder>
      	    </appender>
      	
      	
      	    <!--输出到文件-->
      	
      	    <!-- 时间滚动输出 level为 DEBUG 日志 -->
      	    <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
      	        <!-- 正在记录的日志文件的路径及文件名 -->
      	        <file>${log.path}/log_debug.log</file>
      	        <!--日志文件输出格式-->
      	        <encoder>
      	            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
      	            <charset>UTF-8</charset> <!-- 设置字符集 -->
      	        </encoder>
      	        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
      	        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      	            <!-- 日志归档 -->
      	            <fileNamePattern>${log.path}/debug/log-debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
      	            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
      	                <maxFileSize>100MB</maxFileSize>
      	            </timeBasedFileNamingAndTriggeringPolicy>
      	            <!--日志文件保留天数-->
      	            <maxHistory>15</maxHistory>
      	        </rollingPolicy>
      	        <!-- 此日志文件只记录debug级别的 -->
      	        <filter class="ch.qos.logback.classic.filter.LevelFilter">
      	            <level>debug</level>
      	            <onMatch>ACCEPT</onMatch>
      	            <onMismatch>DENY</onMismatch>
      	        </filter>
      	    </appender>
      	
      	    <!-- 时间滚动输出 level为 INFO 日志 -->
      	    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
      	        <!-- 正在记录的日志文件的路径及文件名 -->
      	        <file>${log.path}/log_info.log</file>
      	        <!--日志文件输出格式-->
      	        <encoder>
      	            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
      	            <charset>UTF-8</charset>
      	        </encoder>
      	        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
      	        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      	            <!-- 每天日志归档路径以及格式 -->
      	            <fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
      	            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
      	                <maxFileSize>100MB</maxFileSize>
      	            </timeBasedFileNamingAndTriggeringPolicy>
      	            <!--日志文件保留天数-->
      	            <maxHistory>15</maxHistory>
      	        </rollingPolicy>
      	        <!-- 此日志文件只记录info级别的 -->
      	        <filter class="ch.qos.logback.classic.filter.LevelFilter">
      	            <level>info</level>
      	            <onMatch>ACCEPT</onMatch>
      	            <onMismatch>DENY</onMismatch>
      	        </filter>
      	    </appender>
      	
      	    <!-- 时间滚动输出 level为 WARN 日志 -->
      	    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
      	        <!-- 正在记录的日志文件的路径及文件名 -->
      	        <file>${log.path}/log_warn.log</file>
      	        <!--日志文件输出格式-->
      	        <encoder>
      	            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
      	            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
      	        </encoder>
      	        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
      	        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      	            <fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
      	            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
      	                <maxFileSize>100MB</maxFileSize>
      	            </timeBasedFileNamingAndTriggeringPolicy>
      	            <!--日志文件保留天数-->
      	            <maxHistory>15</maxHistory>
      	        </rollingPolicy>
      	        <!-- 此日志文件只记录warn级别的 -->
      	        <filter class="ch.qos.logback.classic.filter.LevelFilter">
      	            <level>warn</level>
      	            <onMatch>ACCEPT</onMatch>
      	            <onMismatch>DENY</onMismatch>
      	        </filter>
      	    </appender>
      	
      	
      	    <!-- 时间滚动输出 level为 ERROR 日志 -->
      	    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
      	        <!-- 正在记录的日志文件的路径及文件名 -->
      	        <file>${log.path}/log_error.log</file>
      	        <!--日志文件输出格式-->
      	        <encoder>
      	            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
      	            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
      	        </encoder>
      	        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
      	        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      	            <fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
      	            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
      	                <maxFileSize>100MB</maxFileSize>
      	            </timeBasedFileNamingAndTriggeringPolicy>
      	            <!--日志文件保留天数-->
      	            <maxHistory>15</maxHistory>
      	        </rollingPolicy>
      	        <!-- 此日志文件只记录ERROR级别的 -->
      	        <filter class="ch.qos.logback.classic.filter.LevelFilter">
      	            <level>ERROR</level>
      	            <onMatch>ACCEPT</onMatch>
      	            <onMismatch>DENY</onMismatch>
      	        </filter>
      	    </appender>
      	
      	    <!--
      	        <logger>用来设置某一个包或者具体的某一个类的日志打印级别、
      	        以及指定<appender><logger>仅有一个name属性,
      	        一个可选的level和一个可选的addtivity属性。
      	        name:用来指定受此logger约束的某一个包或者具体的某一个类。
      	        level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
      	              还有一个特俗值INHERITED或者同义词NULL,代表强制执行上级的级别。
      	              如果未设置此属性,那么当前logger将会继承上级的级别。
      	        addtivity:是否向上级logger传递打印信息。默认是true-->
      	    <!--<logger name="org.springframework.web" level="info"/>-->
      	    <!--<logger name="org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor" level="INFO"/>-->
      	    <!--
      	        使用mybatis的时候,sql语句是debug下才会打印,而这里我们只配置了info,所以想要查看sql语句的话,有以下两种操作:
      	        第一种把<root level="info">改成<root level="DEBUG">这样就会打印sql,不过这样日志那边会出现很多其他消息
      	        第二种就是单独给dao下目录配置debug模式,代码如下,这样配置sql语句会打印,其他还是正常info级别:
      	     -->
      	
      	
      	    <!--
      	        root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
      	        level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
      	        不能设置为INHERITED或者同义词NULL。默认是DEBUG
      	        可以包含零个或多个元素,标识这个appender将会添加到这个logger。
      	    -->
      	
      	    <!--开发环境:打印控制台-->
      	    <springProfile name="dev">
      	        <logger name="com.nmys.view" level="debug"/>
      	    </springProfile>
      	
      	    <root level="info">
      	        <appender-ref ref="CONSOLE" />
      	        <appender-ref ref="DEBUG_FILE" />
      	        <appender-ref ref="INFO_FILE" />
      	        <appender-ref ref="WARN_FILE" />
      	        <appender-ref ref="ERROR_FILE" />
      	    </root>
      	
      	    <!--生产环境:输出到文件-->
      	    <!--<springProfile name="pro">-->
      	    <!--<root level="info">-->
      	    <!--<appender-ref ref="CONSOLE" />-->
      	    <!--<appender-ref ref="DEBUG_FILE" />-->
      	    <!--<appender-ref ref="INFO_FILE" />-->
      	    <!--<appender-ref ref="ERROR_FILE" />-->
      	    <!--<appender-ref ref="WARN_FILE" />-->
      	    <!--</root>-->
      	    <!--</springProfile>-->
      	
      	</configuration>
      	```
      
      
    • 创建一个Aop切面类

      @Target({ElementType.PARAMETER, ElementType.METHOD})
      @Retention(RetentionPolicy.RUNTIME)
      @Inherited
      @Documented
      public @interface Operation {
          String name();
      }
      
      @Aspect // FOR AOP
      @Order(-99) // 控制多个Aspect的执行顺序,越小越先执行
      @Component
      public class LogAspect {
          private Logger logger = LoggerFactory.getLogger(getClass());
      
          @Pointcut("@annotation(xxx.xxxxx.Operation)")//上述Operation类的路径地址
          public void method(){
          }
      
          /**
           * doAround:(环绕方法,统一日志处理). <br/>
           * @author fenglanglang
           * @param joinPoint
           * @return
           * @throws Throwable
           */
          @Around("method()")
          public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
              long beginTime = System.currentTimeMillis();//1、开始时间
              Date date=new Date();
              ServletRequestAttributes requestAttr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
              String uri = requestAttr.getRequest().getRequestURI();
              String method=requestAttr.getRequest().getMethod();//请求方式
              String contentType=requestAttr.getRequest().getContentType();//请求类型
              String url="" + requestAttr.getRequest().getServerName() //服务器地址
                      + ":"
                      + requestAttr.getRequest().getServerPort()           //端口号
                      + requestAttr.getRequest().getRequestURI();//接口名称00
              String queryurl="";
              Enumeration queryurls=requestAttr.getRequest().getParameterNames();
              ArrayList<String> arrayList=Collections.list(queryurls);
              String[] arrStr = arrayList.toArray(new String[0]);
              for (int asd=0;asd<arrStr.length;asd++){
                  String value=requestAttr.getRequest().getParameter(arrStr[asd]);
                  queryurl+=arrStr[asd]+"="+(value)+",";//获取url地址和参数
      //            System.out.println(arrStr[asd]+"="+(value));
              }
              String qstitile=afterReturning(joinPoint);
              //访问目标方法的参数 可动态改变参数值
              Object[] args = joinPoint.getArgs();
              //方法名获取
              String methodName = joinPoint.getSignature().getDeclaringTypeName()+"."+joinPoint.getSignature().getName();
              //可能在反向代理请求进来时,获取的IP存在不正确行 这里直接摘抄一段来自网上获取ip的代码
              //调用实际方法
              Object object = joinPoint.proceed();
              long endTime = System.currentTimeMillis()-beginTime;
              String ip=getIpAddr(requestAttr.getRequest());
              String content=
                      "\n"+qstitile+
                       "\n    请求用户:"+"可根据自己需求获取返回"+
                       ",\n    请求URL:"+url+
                       ",\n    请求方式:"+method+
                       ",\n    请求时间:"+date+
                       ",\n    请求参数: {"+queryurl+"}"+
                       ",\n    请求类型:"+contentType+
                       ",\n    请求ip:"+ip+
                       ",\n    返回状态:"+"可根据自己需求获取返回"+
                       ",\n    返回说明:"+"可根据自己需求获取返回"+
                       ",\n    结束总耗时:"+endTime+"毫秒"+
                       ",\n    返回的结果:"+object.toString()+
                       "\n----------------------\n";
              logger.info(content);
              return object;
          }
      
      
      
          /**
           *
           * getIpAddr:(获取ip)
           * @author fenglanglang
           * @param request
           * @return
           */
          public static String getIpAddr(HttpServletRequest request) {
              String ipAddress = null;
              try {
                  ipAddress = request.getHeader("x-forwarded-for");
                  if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                      ipAddress = request.getHeader("Proxy-Client-IP");
                  }
                  if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                      ipAddress = request.getHeader("WL-Proxy-Client-IP");
                  }
                  if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                      ipAddress = request.getRemoteAddr();
                      if (ipAddress.equals("127.0.0.1")) {
                          // 根据网卡取本机配置的IP
                          InetAddress inet = null;
                          try {
                              inet = InetAddress.getLocalHost();
                          } catch (UnknownHostException e) {
                              System.out.println("获取ip异常:{}" + Throwables.getStackTraceAsString(e));
                          }
                          ipAddress = inet.getHostAddress();
                      }
                  }
                  // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
                  if (ipAddress != null && ipAddress.length() > 15) { // "***.***.***.***".length()
                      if (ipAddress.indexOf(",") > 0) {
                          ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
                      }
                  }
              } catch (Exception e) {
                  ipAddress = "";
              }
              return ipAddress;
          }
      
      
          /**
           * 获取类名
           * @param joinPoint
           * @return
           */
          public String afterReturning(JoinPoint joinPoint){
              Class<? extends Object> clazz =  joinPoint.getTarget().getClass();
              String controllerOperation = clazz.getName();
              if(clazz.isAnnotationPresent(Operation.class)){
                  // 当前controller操作的名称
                  controllerOperation = clazz.getAnnotation(Operation.class).name();
              }
              // 获取当前方法
              MethodSignature signature = (MethodSignature) joinPoint.getSignature();
              Method method = signature.getMethod();
              // clazz类下的所有方法
              Method[] methods = clazz.getDeclaredMethods();
              String methodOperation = "";
              for (Method m : methods) {
                  if(m.equals(method)){
                      methodOperation = m.getName();
                      if(m.isAnnotationPresent(Operation.class)){
                          methodOperation = m.getAnnotation(Operation.class).name();
                      }
                  }
              }
              controllerOperation=controllerOperation.substring(controllerOperation.lastIndexOf(".")+1,controllerOperation.length());
              return "---------执行了"+controllerOperation+"下的"+methodOperation+"操作:---------";
          }
      }
      
      
    • 通过切面日志的应用

      在方法的类注解中直接引入切面@Operation(name = “读取文档内容”)即可

      	/**
      	     * 读取信息文本文档
      	     * @return
      	     * @throws Exception
      	     */
      	    @Operation(name = "读取文档内容")
      	    @RequestMapping(value = {"/filetext"})
      	    public ModelAndView filetext(String name, ReturnVo returnVo) throws Exception{
      	        return new ModelAndView("before/public/filetext","list",a) ;
      	    }
      	```
      
      
    展开全文
  • Spring之注解实现aop(面向切面编程) 面试题思考:什么是基于注解的切面实现?(AOP是Aspect Oriented Program的首字母缩写) Spring AOP就是这么简单啦 Spring面向切面编程(AOP)的基本用法:基于注解的实现 ...
    展开全文
  • Spring AOP切面实现:示例

    引入jar包:

    aspectjrt-1.7.4.jar

    aspectjweaver.1.7.1.jar

    aopalliance-1.0.jar

    下载地址:

    http://mvnrepository.com/artifact/org.aspectj/aspectjrt

    http://mvnrepository.com/artifact/org.aspectj/aspectjweaver

    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:context="http://www.springframework.org/schema/context"
    	xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx"
    	xmlns:task="http://www.springframework.org/schema/task"
    	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.0.xsd
    		http://www.springframework.org/schema/context 
    		http://www.springframework.org/schema/context/spring-context-3.0.xsd
    		http://www.springframework.org/schema/mvc 
    		http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
    		http://www.springframework.org/schema/task
    		http://www.springframework.org/schema/task/spring-task-3.0.xsd
    		http://www.springframework.org/schema/aop  
            http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
    
    	<context:annotation-config />
    	<!-- spring扫描注解的配置 -->
    	<context:component-scan base-package="com.learn" />
    	
    	<aop:aspectj-autoproxy/>
    
    	<bean id="Learn" class="com.learn.spring.Learn" />
    </beans>
    

    注意添加:

    xmlns:aop="http://www.springframework.org/schema/aop"
    http://www.springframework.org/schema/aop  
    http://www.springframework.org/schema/aop/spring-aop-2.0.xsd

    切面类:

    package com.learn.aspect;
    
    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.stereotype.Component;
    
    @Aspect
    @Component
    public class LearnAspect {
    	
    	@Pointcut("execution(public * com.learn.spring..*.*(..))")
    	public void pointcut()
    	{
    	}
    	
    	@Around("pointcut()")
    	public Object around(ProceedingJoinPoint jp) throws Throwable
    	{
    		System.out.println("around");
    		return jp.proceed();
    	}
    	
    	@Before("pointcut()")
    	public void before()
    	{
    		System.out.println("before");
    	}
    	
    }
    
    java类:

    package com.learn.spring;
    
    public class Learn {
    	public void show()
    	{
    		System.out.println("Now is ShowTime");
    	}
    	
    }
    
    测试类:

    package com.learn.aspect;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    import com.learn.spring.Learn;
    
    public class Test {
    	public static void main(String[] args) {
    		ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    		Learn l = (Learn)context.getBean("Learn");
    		l.show();
    	}
    }
    输出结果:

    around
    before
    Now is ShowTime

    问题:

    1、报错:java.lang.ClassNotFoundException: org.aopalliance.intercept.MethodInterceptor

    解决:缺少aopalliance-1.0.jar包

    2、报错:java.lang.IllegalArgumentException: error at ::0 can't find referenced pointcut addHander

    原因:JDK不匹配。如:用JDK1.7,导入aspectjrt.1.6和apectjweaver.1.6 jar包,就会报错。

    解决:更换jar包



    展开全文
  • SpringAop切面实现日志记录代码实现:https://www.cnblogs.com/wenjunwei/p/9639909.html 问题记录 1.signature.getMethod().getAnnotation()无法获取注解对象 原因:Spring在处理中,可能是因为我的项目有事务,...

    SpringAop切面实现日志记录
    代码实现:https://www.cnblogs.com/wenjunwei/p/9639909.html

    问题记录

    1.signature.getMethod().getAnnotation()无法获取注解对象

    原因:Spring在处理中,可能是因为我的项目有事务,serviceImpl的方法被代理后直接得不到了。换一个思路:先得到自己的父类,然后通过父类得到真实的自己
    解决方法:
    https://www.cnblogs.com/wangshen31/p/9498731.html

     

     1 /**
     2      * 这个方法帮忙拿出注解中的operation属性
     3      * 因为有拦截serviceImpl的方法,而这些方法又加了事务管理,也就是这里也有aop,这些已经是代理类,用之前的写法获得的是代理类的方法,而这些
     4      * 方法是特么不会把父类中的方法的注解加上去的!!!
     5      * @param proceedingJoinPoint
     6      */
     7     private String getOperationOfTheAnnotation(ProceedingJoinPoint proceedingJoinPoint) throws Exception {
     8         
     9         Signature signature =  proceedingJoinPoint.getSignature();//方法签名
    10         Method method = ( (MethodSignature)signature ).getMethod();
    11         
    12         //这个方法才是目标对象上有注解的方法
    13         Method realMethod = proceedingJoinPoint.getTarget().getClass().getDeclaredMethod(signature.getName(), method.getParameterTypes());
    14         
    15                 
    16         AuthorizationNeed authorizationNeed = realMethod.getAnnotation(AuthorizationNeed.class);
    17         
    18         return authorizationNeed.operation();
    19                 
    20 
    21     }

     

    2.signature.getParameterNames() 获取不到值

    原因:如果您的bean实现了接口,那么JDK代理将在spring之前创建,并且在这种代理中,MethodSignature.getParameterNames()为null。
    如果您的bean没有实现接口,则会创建CGLIB代理,并在其中填充MethodSignature.getParameterNames()。
    解决方案:
    http://www.it1352.com/990863.html
    使用CGLIB代理,spring.aop.proxy-target-class: true (设置为true)

    1 server:
    2   port:8087
    3 spring:
    4   aop:
    5     auto: true #启动aop配置
    6     proxy-target-class: true

     

     

     

    展开全文
  • 切面实现事务   在实现事务的时候也是在xml中编写代码来实现,因为要用到切面,所以我们要引入aop schema,引入的方法实在beans标签上写为:  xmlns:aop=http://www.springframework.org/schema/aop  和  ...
  • 使用aop切面实现系统操作日志管理

    千次阅读 2019-08-01 14:29:39
    使用aop切面实现系统操作日志管理 一、思路: 新增表SYS_OPERATE_LOG(表结构在下面),在需要的地方加上@MyLog(value = "**"),value为表字段OPERATION的值. 表示发生了什么操作.比如:加@MyLog(value = "**")注解的...
  • 切面实现对controller层进行统一日志记录切面通用父类自定义注解需要的一些工具类业务模块使用 本文章项目开源地址 切面通用父类 这里实现通用父类,里面写好了对请求的信息(url、方法、请求头信息、参数)等信息,...
  • 使用自定义注解+Spring切面实现日志记录 转载于:https://www.cnblogs.com/liuys635/p/10585487.html
  • 自定义注解结合切面实现参数值的自动注入 一.自定义注解 /** * 创建时间的注解 **/ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface CreateDateTime { } /** * 创建人名,...
  • 前言:在实际开发中,我们可能会遇到需要对某个接口...一、切面实现请求接口频率限制 1.pom.xml引入 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-
  • 一,AOP切面实现 首先在pom里依赖aop,版本号:2.1.0.RELEASE 这里用Aop主要实现日志及异常处理,首先我们在接口层(lyn-web)创建一个Aop的切面类,如下: 定义好切面,然后写前置通知,后置通知,环绕通知...
  • 自定义注解及AOP切面实现针对字段的特殊字符的校验 1、 aspect 切面依赖包导入 <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <...
  • 使用Aspect切面实现系统日志并存入数据库1.pom.xml中:加入Maven依赖&lt;dependency&gt; &lt;groupId&gt;org.springframework&lt;/groupId&gt; &lt;artifactId&gt;spring-aspects&...
  • 利用自定义注解加spring切面实现redis service层缓存。 功能:通过在service层上设置缓存可以将服务层的处理结果保存到redis上,这样的话第二次查询的时候可以直接从redis上取,加快查取速度。 优点:对于重复查取...
  • spring mvc统一处理接口返回值filter过滤器实现HttpServletResponse的包装类过滤器具体实现特殊说明:Aop切面实现添加pom.xml修改配置文件spring-servlet.xmlaop类实现最后简单说一下拦截器以上代码如有侵权,请与我...
  • 切面做日志网上有太多教程,但基于注解的比较少,能做到比我功能更全的可能就更少了,当然,功能全,意味着一定复杂度,欢迎鲜花~(如果觉得我写的不够明白,可以催催我,ps: 我可不是不勤快哦~)
  • 从上述AOP实现原理中可知AOP中没有规定不同切面的执行顺序,都是把切面打乱放进了List中,但从放入List中的顺序追溯, 可知对应的是Spring加载类后注册BeanDefinition的顺序,即Spring注册BeanDefinition的顺序。...
  • 是一种面向切面编程的,利用预编译方式和运行期动态代理实现程序功能统一的一种技术。它也是Spring很重要的一部分,和IOC一样重要。利用AOP可以很好的对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的...
  • Java 利用AOP切面实现自定义注解示例

    千次阅读 2019-07-22 16:30:21
    * AOP为Aspect Oriented Programming的缩写,意为:面向切面编程 * AOP是一种编程范式,隶属于软工范畴,指导开发者如何组织程序结构 * AOP最早由AOP联盟的组织提出的,制定了一套规范.Spring将AOP思想引入到...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 15,019
精华内容 6,007
关键字:

切面实现