springboot of AOP

  • AOP share, springboot in aop

    • springboot introduced aop

      <!--aop-->
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-aop</artifactId>
      </dependency>
      复制代码

    on

    spring:
      aop:
        auto: true #启动aop配置
    复制代码

    And @EnableAspectJAutoProxy.

    The two configurations are starting aop, but in fact springboot in aop has been enabled by default, so no need to write these two configurations

Use the default proxy cglib in springboot in the spring and dynamic agency jdk used, if so how do you want to use dynamic proxies jdk in springboot in it? In this case can be configured spring.aop.proxy-target-class = false in the configuration file, but, as a class @EnableAspectJAutoProxy annotation proxy can not change the pattern of the springboot, such as dynamic annotation proxy itself enable the jdk However, they did not work.

  • Glossary

    • Notice (in some places called Enhanced) (Advice): needs to be done is called a notice that you need to write business logic in such matters, logs, first defined, then need a place to go with

    • Connection point (Join point): the spring is allowed to use local notification, each method may be substantially longitudinal connecting point Throws

    • Cut-off point (Poincut): in fact screened connection points, all methods of a class are connection points, but not all needs will filter out some as a connection point as the tangent point. If the notification section defines the action or execution timing, then cut-off point defines the place of execution

    • Section (Aspect): in fact, notify the point of tangency and the combination of notification and the point of tangency together define the entire contents of the section, it is doing, where and when to perform

    • Introducing (Introduction): in without changing an existing class code, add properties and methods for the class, without modifying the conventional can type in the premise that they would have a new behavior and state. In fact, the section: use the target class (that is, the new notification method attribute defined) to go

    • Target (target): the object to be notified. That is, objects need to add extra code, which is the real business logic is woven into the tissue section.

    • Weaving (Weaving): The procedure program code section is added. Is woven in a specified section of the connection point to the target object, a plurality of points can be woven into the life cycle of the target object:

      Compile: section is woven in the target class compile time, this approach requires special compiler

      Loading of class: in the target section is woven when the class loader to the JVM, this approach requires special class loader, which can be applied before the target class bytecode enhancement is introduced in the target class

      Runtime: section is woven into applications running at a certain time, under normal circumstances, when the weaving section, AOP container will dynamically create a proxy object as the target object, Spring AOP is in this way woven into facets.

  • Create a section

    @Aspect in springboot in a class labeled aspect classes, but only use @Aspect does not directly use, also need to use this class to inject @Component comment

  • Cut-off point

    • Writing

      1. Notes can be written on each notification

        @Before(value = "@annotation(TestAnnotation)")
        复制代码
      2. You can create a method using @Pointcut marker position on the tangent point method

        @Pointcut("@annotation(TestAnnotation)")
        public void pointCut(){
        }
        复制代码
    • Entry point indicator

      1. exeution

        execution(modifier-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
        复制代码
        • modifier-pattern: the method specified modifier, support wildcards, the portion may be omitted

        • ret-type-pattern: Specifies the return type, support wildcards, you can use the "*" wildcard to return all value types

        • declaring-type-pattern: the specified method belongs to class, to support wildcard, the portion may be omitted

        • name-pattern: the method name to be matched, support wildcards, you can use the "*" wildcard to all method names

        • param-pattern: shape parameter list specified method, two support wildcard, " " and "..", where " " represents a type of any parameter, while the ".." represents zero or more parameters of any type.

        • throw-pattern: Specifies the method declaration thrown exception, support wildcards, the portion may be omitted

          example:

          execution (public * * (..)) // match all public methods

          execution (* set * (..)) // start with set matching method

          execution (* com.abc.service.AdviceManager. * (..)) // matching method of any AdviceManager

          Execution (* com.abc.service. . (..)) // packet matches any of the methods of any class com.abc.servcie

      2. within

        All methods in the class can only match

        // com.zejian.dao matching packet and its subpackages all methods in all classes within (com.zejian.dao .. *)

        // matching method implements all subclasses DaoUser interface

        within (com.zejian.dao.DaoUser +)

        In addition there @within within its use within the comment is

      3. Annotations way

        @Pointcut("@annotation(TestAnnotation)")

      4. args和@args

        args parameter configuration are all methods, and matching @args are all methods of this class annotated parameters

      5. other

        In addition to the above also this indicator, bean, and other target points to this target class, the target just the proxy class, bean bean refers to match by

  • Notice

    • Notification type and its parameters

      1. Around advice: ProceedingJoinPoint

      2. Before advice: JoinPoint

      3. After returning advice: JoinPoint

      4. Back to News: JoinPoint, returning

        returning: defining a target only after the method returns to perform the corresponding parameter type value and a return notification notifying method set, or not performed, the notification method for returning parameter corresponding to match any type of Object to return the target value

      5. Exception notification: JoinPoint, throwing

        throwing: defining a goal post abnormality notification only exception thrown to execute the notification method and the corresponding parameters exception type, or not performed, for throwing the notification method corresponding to the parameter type Throwable will match any exception.

    • Notification of the execution order

      ①不自定义情况下,无异常的aop执行流程:环绕前置==》前置==》程序执行==》环绕后置==》后置==》返回
      ②不自定义情况下,有异常的aop执行流程:环绕前置==》前置==》程序执行==》环绕后置==》后置==》异常返回
      复制代码
    • JoinPoint 和ProceedingJoinPoint

    • public interface JoinPoint {  
         String toString();         //连接点所在位置的相关信息  
         
         String toShortString();     //连接点所在位置的简短相关信息 
         
         String toLongString();     //连接点所在位置的全部相关信息  
         
         Object getThis();         //返回AOP代理对象,也就是com.sun.proxy.$Proxy18
         
         Object getTarget();       //返回目标对象或者是接口(也就是定义方法的接口或类,为什么会是接口呢?这主要是在目标对象本身是动态代理的情况下,例如Mapper。所以返回的是定义方法的对象如aoptest.daoimpl.GoodDaoImpl或com.b.base.BaseMapper<T, E, PK>)
         
         Object[] getArgs();       //返回被通知方法参数列表  
         
         Signature getSignature();  //返回当前连接点签名  其getName()方法返回方法的FQN,如void aoptest.dao.GoodDao.delete()或com.b.base.BaseMapper.insert(T)(需要注意的是,很多时候我们定义了子类继承父类的时候,我们希望拿到基于子类的FQN,这直接可拿不到,要依赖于AopUtils.getTargetClass(point.getTarget())
         
         SourceLocation getSourceLocation();//返回连接点方法所在类文件中的位置  
         
         String getKind();        //连接点类型  
         
         StaticPart getStaticPart(); //返回连接点静态部分  
        }  
      复制代码

      ProceedingJoinPoint inherited JoinPoint, in addition to adding proceed, proceed (Object [] args) Method two

    • Alternatively pre-notification with a notification surround, return notification, abnormality notification, the notification post

      @Around(value ="pointCut()")
      public Object aroundCut(ProceedingJoinPoint proceedingJoinPoint) {
          logger.info("前置通知");
          Object proceed = null;
          try {
              proceed = proceedingJoinPoint.proceed();
              System.out.print(proceed);
              logger.info("后置通知");
          } catch (Throwable throwable) {
              throwable.printStackTrace();
              logger.info("异常通知");
          }finally {
              logger.info("返回通知");
          }
          return proceed;
      }
      复制代码
    • Pre-notification and return parameters and return values ​​change notifications

         //前置通知,在改变参数的时候,不能改变基本类型的参数,如果想要改变基本类型的参数,需要创     建一个封装类
         @Before("pointCut()")
          public void beforeCut(JoinPoint joinPoint){
              Object[] args = joinPoint.getArgs();
              for (Object o: args){
                  System.out.println(o);
                  if (o instanceof Person){
                      Person person = (Person) o;
                      person.setName("zhangsan");
                      System.out.println(person);
                  }
                  logger.info(o.toString());
              }
          }
          //后置通知
          @AfterReturning(value = "pointCut()",returning = "keys")
          public void returningCut(JoinPoint joinPoint,Object keys){
                if (keys instanceof RetKit){
                    RetKit retKit = (RetKit) keys;
                    retKit.data(222);
                }
      
          }
      复制代码
    • Changing the parameters and return values ​​in the surrounding notification

         @Around(value ="pointCut()")
          public Object aroundCut(ProceedingJoinPoint proceedingJoinPoint)  {
              logger.info("前置通知");
              Object[] args = proceedingJoinPoint.getArgs();
              int i =0;
              for (Object arg:args){
                  if (arg instanceof Integer){
                      args[i]=2;
                  }
                  i++;
              }
              Object proceed = null;
              try {
                  proceed = proceedingJoinPoint.proceed(args);
                  logger.info("后置通知");
              } catch (Throwable throwable) {
                  throwable.printStackTrace();
                  logger.info("异常通知");
              }finally {
                  RetKit retKit = (RetKit) proceed;
                  retKit.setData("修改结果");
                  logger.info(proceed.toString());
                  logger.info("返回通知");
              }
              return proceed;
          }
      复制代码
    • You can use request and response in the notice

      @Before("pointCut()")
      public void beforeCut(JoinPoint joinPoint){
          ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
          HttpServletRequest request = attributes.getRequest();
          HttpServletResponse response = attributes.getResponse();
          //url
          logger.info("url={}",request.getRequestURI());
          //method
          logger.info("method={}", request.getMethod());
          //ip
          logger.info("ip={}", request.getRemoteAddr());
          //类方法
          logger.info("classMethod={}", joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
          //参数
          Enumeration<String> paramter = request.getParameterNames();
          while (paramter.hasMoreElements()) {
              String str = (String) paramter.nextElement();
              logger.info(str + "={}", request.getParameter(str));
          }
           //重定向或者转发
          try {
              response.sendRedirect("/person/error");
            request.getRequestDispatcher("/person/error").forward(request,response);
          } catch (IOException e) {
              e.printStackTrace();
          }catch (ServletException e) {
              e.printStackTrace();
          }
      }
      复制代码
    • Exception notification and extension

      While the AOP AfterThrowing process can handle an abnormal state of the target method, but this deal directly with the capture different catch, catch catch means fully handle the exception, if there is no catch block re-throws a new exception, the method may normal end; and although AfterThrowing processing handled the exception, but it can not fully handle the exception, the exception will still be spread to the previous caller, that JVM.

      • Handling abnormal
        1. java way of handling exceptions

          1. try-catch
          2. throws
        2. spring exception handling in a manner

          1. Use @ExceptionHandler
          2. 使用@ControllerAdvice+@ExceptionHandler
          3. Achieve HandlerExceptionResolver Interface
            @Slf4j
            @Component
            public class GlobalExpetion implements HandlerExceptionResolver {
                @Override
                public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
               log.info("系统发生异常");
                // 统一处理异常
                ModelAndView modelAndView = new ModelAndView();
                modelAndView.addObject("message", "系统发生异常,请稍后重试");
                modelAndView.setViewName("/500");
                return modelAndView;
            }
            }
          复制代码
  • Section of the scope, priorities and principles of nesting

    • The scope of section

      public, protected, default scope methods can be intercepted

    • priority

      You can use @order assign priorities facets. value is the default value @order int, i.e. the maximum power of 31 -12 transaction section Priority: The default priority is the lowest

    • Nested principle

      a. method does not meet the call blocking rules, this class in other ways to meet the conditions to intercept calls, this time will not start the intercept method b aop Call method does not meet the blocking rules, call other class methods to intercept the conditions are met, this time the method starts aop intercept method c. a method of intercepting calls meet satisfy recall intercepted B (within the class into the class and outside) the sequence would start outside of class aop interception, intercept method is to enter a after the post-notification method then proceeds to b is set, and then into a post-process after the notification b completed notification method, and then completed a notification method, if it is called within this class only once aop

      • Principle factors nested form

        Because aop intercept the target class but not really inject proxy class ioc container, but in java if the calling method is to use this.method () to call this form, then this points to is not the proxy class but the class itself. So this time aop not intercept method.

      • Solution

        1. Injected into their own

          @Component
          public class TestAopService {
              @Resource
              private TestAopService testAopService;
              public TestAopService() {
              }
              @TestAnnotation
              public void say1(){
                  testAopService.say2();
                  System.out.println("1");
              }
              @TestAnnotation
              public void say2(){
                  System.out.println("1");
              }
          }
          复制代码
        2. 使用AopContext.currentProxy()

          @Component
          public class TestAopService {
              public TestAopService() {
              }
          
              @TestAnnotation
              public void say1(){
                  ((TestAopService)AopContext.currentProxy()).say2();
                  System.out.println("1");
              }
              @TestAnnotation
              public void say2(){
                  System.out.println("1");
              }
          }
          复制代码

          However, to note is AopContext.currentProxy () must be annotated with @EnableAspectJAutoProxy (exposeProxy = true) use, because AopContext bean scanning function is off by default and must be manually set to true before they can

        3. Find using ApplicationContext bean

          @Component
          public class TestAopService {
              @Autowired
              private ApplicationContext applicationContext;
              public TestAopService() {
              }
          
              @TestAnnotation
              public void say1(){
                  TestAopService bean = applicationContext.getBean(TestAopService.class);
                  bean.say2();
                  System.out.println("1");
              }
              @TestAnnotation
              public void say2(){
                  System.out.println("1");
              }
          }
          复制代码

Guess you like

Origin juejin.im/post/5dd73de6e51d45236665e696