• AOP sharing, AOP in SpringBoot

    • Aop is introduced in SpringBoot

      <! --aop--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>Copy the code

    about

    spring:
      aop:
        auto: true Start the AOP configuration
    Copy the code

    And @ EnableAspectJAutoProxy.

    Both of these configurations are aop enabled, but AOP is already enabled by default in SpringBoot, so there is no need to write either configuration

The default cglib proxy in SpringBoot is the JDK dynamic proxy in Spring. What if you want to use the JDK dynamic proxy in SpringBoot? Spring.aop.proxy-target-class =false can be configured in the configuration file, but annotations such as @enableAspectJAutoProxy do not change the springBoot proxy mode. Because such annotations are themselves dynamic proxies for the JDK enabled, they don’t work.

  • Noun explanation

    • Advice: The work that needs to be done is called Advice. This is when you write business logic that needs to be defined, such as transactions, logs, etc., and then use it where necessary

    • Join point: This is where notifications are allowed in Spring, and it can be a Join point for almost every method that throws exceptions before and after

    • Poincut: Select join points. All methods in a class are join points, but not all of them are required. Some of them are selected as join points. If the advice defines the action or timing of the cut, the cut point defines the place of execution

    • Aspect: A combination of advice and pointcuts, which together define all aspects of an Aspect, what it does, when and where it is executed

    • Introduction: Adding attributes and methods to an existing class without changing the code of the class gives them new behavior and states without modifying existing classes. This is to apply the aspect (defined by the new method property: notification) to the target class

    • Target: The notified object. That is, objects that need to be added extra code, where the real business logic is organized into facets.

    • Weaving: The process of adding aspects to program code. Facets are woven into the target object at the specified join point, and there are multiple points that can be woven into the target object during its lifetime:

      Compile-time: The aspect is woven in when the target class is compiled, which requires a special compiler

      Class loading time: The aspect is woven into the target class when it is loaded into the JVM. This approach requires a special class loader that enhances the bytecode of the target class before it is introduced into the application

      Runtime: The aspect is woven at some point during the application’s run. Typically, when weaving into the aspect, the AOP container dynamically creates a proxy object for the target object, which is how Spring AOP is woven into the aspect.

  • Create a plane

    In SpringBoot, you use @aspect to mark a class as a facet class, but @aspect alone cannot be used directly. You also need to inject the class with the @Component annotation

  • Point of tangency

    • writing

      1. You can write it on the notes of each notice

        @Before(value = "@annotation(TestAnnotation)")
        Copy the code
      2. You can create a method that marks the Pointcut position on the method with @pointcut

        @Pointcut("@annotation(TestAnnotation)")
        public void pointCut(){
        }
        Copy the code
    • Pointcut indicator

      1. exeution

        execution(modifier-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
        Copy the code
        • Modifier-pattern: specifies the modifiers of methods. Wildcards are supported and can be omitted

        • Ret-type-pattern: Specifies the return value type. Wildcard characters are supported. You can use asterisk (*) to wildcard all return value types

        • Literal -type-pattern: Indicates the class to which the method literal belongs. Wildcard character is supported. This part can be omitted

        • Name-pattern: specifies matched method names. Wildcards are supported. You can use asterisks (*) to match all method names

        • Param-pattern: Specifies the parameter list of a method. Two wildcards, “” and”.. “are supported. , where “” represents an arbitrary type of parameter, and”..” Represents zero or more parameters of any type.

        • Throw-pattern: Specifies the exception thrown by the method declaration. Wildcards are supported. This part can be omitted

          Example:

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

          execution(* set*(..) // Matches methods that start with set

          execution(* com.abc.service.AdviceManager.* (..) // Matches any method in AdviceManager

          execution(* com.abc.service.. (..) )// Matches any method of any class in the com.abc.servcie package

      2. within

        Only all methods within a class can be matched

        // Match all methods in all classes within the com.zejian.dao package and its subpackages. *)

        // match methods that implement all subclasses of the DaoUser interface

        within(com.zejian.dao.DaoUser+)

        In addition to within, there’s also the @within annotation which is how to use within

      3. Annotation way

        @Pointcut(“@annotation(TestAnnotation)”)

      4. The args and @ args

        Args is configured for all methods that have this parameter, while @args matches all methods that have this annotation on the class of the parameter

      5. other

        This refers to the target class, while target only refers to the proxy class, and bean refers to the bean that can match through

  • notice

    • The type of notification and its parameters

      1. Surround notification: ProceedingJoinPoint

      2. Pre-notification: JoinPoint

      3. Post notification: JoinPoint

      4. Return notification: JoinPoint, RETURNING

        Returning: Specifies that post-return notification can only be executed when returning values of target method and corresponding parameter types of notification method returning. Otherwise, post-return notification will match any target return value for notification method parameters of Object RETURNING

      5. Exception notification: JoinPoint and Throwing

        Throwing: Restricts post-exception notification to only exceptions thrown by the target method and the exception type of the corresponding notification method parameter. Otherwise, it is not executed. For Throwing, the notification method parameter is Throwable and will match any exception.

    • The order in which notifications are executed

      ① No custom case, no abnormal AOP execution process: surround == "surround ==" program execution == "surround ==" return ② No custom case, abnormal AOP execution process: surround == "program execution ==" surround == "return exceptionCopy the code
    • JoinPoint and ProceedingJoinPoint

    • public interface JoinPoint { String toString(); String toShortString(); String toLongString(); Object getThis(); // Returns an AOP proxy object, namely com.sun.proxy.$Proxy18Object getTarget(); // Return the target object or interface (i.e. the interface or class that defines the method). This is mainly in cases where the target object itself is a dynamic proxy, such as Mapper. So returns the definition method of Object such as aoptest. Daoimpl. GoodDaoImpl or com. B.b ase. BaseMapper < T, E, PK >) Object [] getArgs (); Signature getSignature(); / / returns the current connection point signature The getName () method returns the method FQN, such as void aoptest. Dao. GoodDao. Delete () or com. B.b ase. BaseMapper. Insert (T) (it is important to note that A lot of times when we define a subclass that inherits from a parent class, we want to get a subclass-based FQN, which we can't get, To rely on aoputils.gettarGetClass (point.gettarget ()) SourceLocation getSourceLocation(); // Return the position of the join point method in the class file String getKind(); // Connection point type StaticPart getStaticPart(); // Return static part of join point}Copy the code

      ProceedingJoinPoint extends JoinPoint and adds methods PROCEED and Proceed (Object[] args)

    • Replace pre-notification, return notification, exception notification, and post-notification with surround notification

      @Around(value ="pointCut()")
      public Object aroundCut(ProceedingJoinPoint proceedingJoinPoint) {
          logger.info("Advance notice");
          Object proceed = null;
          try {
              proceed = proceedingJoinPoint.proceed();
              System.out.print(proceed);
              logger.info("Post notification");
          } catch (Throwable throwable) {
              throwable.printStackTrace();
              logger.info("Exception notification");
          }finally {
              logger.info("Return notification");
          }
          return proceed;
      }
      Copy the code
    • Pre-notification and return notification change parameters and return values

      // Create an enclosing class @before (); // Create an enclosing class @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 = return"pointCut()",returning = "keys")
          public void returningCut(JoinPoint joinPoint,Object keys){
                if(keys instanceof RetKit){ RetKit retKit = (RetKit) keys; retKit.data(222); }}Copy the code
    • Change parameters and return values in the surround notification

         @Around(value ="pointCut()")
          public Object aroundCut(ProceedingJoinPoint proceedingJoinPoint)  {
              logger.info("Advance notice");
              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("Post notification");
              } catch (Throwable throwable) {
                  throwable.printStackTrace();
                  logger.info("Exception notification");
              }finally {
                  RetKit retKit = (RetKit) proceed;
                  retKit.setData("Modified result");
                  logger.info(proceed.toString());
                  logger.info("Return notification");
              }
              return proceed;
          }
      Copy the code
    • Request and Response can be used in notifications

      @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()); // Class method logger.info("classMethod={}", joinPoint.getSignature().getDeclaringTypeName() + "."+ joinPoint.getSignature().getName()); / / parameter Enumeration < String > paramter = request. GetParameterNames ();while (paramter.hasMoreElements()) {
              String str = (String) paramter.nextElement();
              logger.info(str + "= {}", request.getParameter(str)); } // redirect or forward try {response.sendredirect ("/person/error");
            request.getRequestDispatcher("/person/error").forward(request,response); } catch (IOException e) { e.printStackTrace(); }catch (ServletException e) { e.printStackTrace(); }}Copy the code
    • Exception notification and extension

      Although AOP’s AfterThrowing processing can handle the exception of the target method, it is different from the direct use of catch catching. Catch catching means that the exception is completely processed. If no new exception is thrown in the catch block, the method may end normally. The AfterThrowing processing does this, but it does not fully handle the exception, which is still propagated to the next caller, the JVM.

      • The way exceptions are handled
        1. How Java handles exceptions

          1. try-catch
          2. throws
        2. How exceptions are handled in Spring

          1. Using the @ ExceptionHandler
          2. Using the @ ControllerAdvice + @ ExceptionHandler
          3. Implement the HandlerExceptionResolver interface
            @Slf4j
            @Component
            public class GlobalExpetion implements HandlerExceptionResolver {
                @Override
                public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
               log.info("System exception"); ModelAndView = new ModelAndView(); modelAndView.addObject("message"."An exception occurred. Please try again later.");
                modelAndView.setViewName("/ 500");
                returnmodelAndView; }}Copy the code
  • Scope, priority, and nesting rules for facets

    • Scope of the section

      Methods in the public, protected, and default scopes can all be intercepted

    • priority

      You can specify the priority of the slice using @order. The value in @order defaults to the maximum value of int which is 2 to the 31st minus 1. Transaction aspect Priority: Defaults to the lowest priority

    • The principle of nested

      A. Aop intercepting method B will not be started if a method in the class that does not meet the interception rule is called. Aop intercepting method C is started when calling a method that does not meet the interception rules and calls a method from another class that does. Call meet intercept method calls again meet intercept method b (divided into in this class and outside class) outside the class would start aop interception, the order of the intercept method is first to enter a rear notice and then into the rear b method, walk the b method notice before entering a rear of the notice, and then through a method of notification, Aop will only be executed once if invoked within this class

      • The formation factor of the nesting principle

        Because AOP intercepts not the real target class but the proxy class injected into the IOC container, in Java methods are called in the form this.method (), which points to the class itself rather than the proxy class. So aop cannot intercept methods at this point.

      • The solution

        1. Inject yourself into yourself

          @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"); }}Copy the code
        2. Using 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"); }}Copy the code

          Note, however, that aopContext.currentProxy () must be used with the @enableAspectJAutoProxy (exposeProxy = true) annotation, because the AopContext scan bean is turned off by default, It must be set to true manually

        3. Use ApplicationContext to find beans

          @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"); }}Copy the code