Spring AOP - way to use annotations introduced (long article Comments)

Foreword

Prior to parse the source code section, I explain the source code of the core part of the Spring IOC. If you are familiar with the use of Spring AOP, then, after the Spring IOC understanding of the core source code, source code to learn Spring AOP, it should be said to be a matter of course, we will not have any difficulties.

But just start talking about Spring AOP source, I also felt a little awkward, so there will be some in this chapter. Getting started using Spring AOP introduction: including some conceptual overview of the use and configuration of Spring AOP.

First posted here about the mind map.

Spring AOP.png

What is AOP

AOP: Aspect Oriented Programming (Aspect Oriented Programming)

Aspect is a new modular mechanism to be described in the dispersed objects, classes, or crosscutting concerns (crosscutting concern) function. The core concept of separating crosscutting concerns is aspect-oriented programming from the attention point. Separation of concerns makes the code to solve a specific problem areas independent from the business logic, business logic code no longer contains the calling code for a specific problem areas, business logic with a specific problem areas to encapsulate by section, to maintain , so the original changes scattered throughout the application can manage very well.

Li Zhihui recently read the "large-scale Web Site Technology Framework," a book, the author mentions the development of low coupling system is one of the ultimate goal of software design. This AOP Aspect Oriented Programming in a way a manifestation of this concept. The number of repeat, and the primary business logic code is not related functionality (logging, security management, etc.) cut out of the modularly encapsulated pulled through, to achieve separation of concerns, the decoupling module, such that the system management easier to maintain .

Such divide and rule design, so I felt a sense of beauty.

AOP is to be achieved on the basis of our original write code on certain packages, such as the method of execution before, after the method returns, the method throws an exception and other places after a certain interception or call processing enhancement processing.

AOP implementations not because Java provides no magic hook, several life-cycle approach can tell us, but we want to achieve a proxy instance is actually running is actually an example of the generated proxy class .

Terms and concepts

As mentioned earlier, Spring AOP AspectJ extension of the concept of using a jar package annotations provided in AspectJ. That is, inside the Spring AOP concepts and terminology, Spring is not unique, but AOP and relevant.

The concept can be seen hastily, looked after chapter after back to see would be a deeper understanding of the concept.

the term concept
Aspect It is cut Pointcutand Adviceset, typically as a separate class. PointcutAnd Advicetogether define the entire contents on the cut surface, it is what, when and where to completion.
Joinpoint This means that your application can insert a little AOP aspect. It can be said that this is the application using Spring AOP framework to take action actual location.
Advice This is the actual action taken before or after execution method. This is the actual code fragment called during execution of the program Spring AOP framework.
Pointcut This is a set of one or more entry points, it should be performed at the point of tangency Advice. You can use an expression or pattern designated entry points, examples will be mentioned later.
Introduction Reference allows us to add a new method or property to an existing class
Weaving Create a process to be enhanced object. This can be done at compile time (e.g. using AspectJ compiler), it may be done at runtime. Spring and other pure Java AOP frameworks, performs weaving at runtime.

PS: There is a question finishing time concept, why so many online articles to advice translated into Chinese "notice" mean? ? ? Conceptually sense? ? ? I prefer to translate into "enhanced" (concurrent Chinese network ifeve.com also translated into enhanced)

There are some notes indicating the type of Advice of, or enhanced opportunity will be more clearly seen after example after.

the term concept
Before Before the method is called to perform enhanced
After After the method is called to perform enhanced
After-returning After the successful execution method enhanced
After-throwing After the implementation of enhanced method throws an exception specified
Around Before and after the implementation of the method call custom enhancements behavior (most flexible way)

Use

After the Spring 2.0, Spring AOP has two configurations.

  1. -based Schema : After the Spring 2.0 uses XML way to configure, use namespaces<aop />

  2. @AspectJ configuration : annotation mode after Spring 2.0 provides. Here though it is called @AspectJ, but nothing to this fact and AspectJ.

PS: personally love @AspectJ this way, use is down in most aspects. It may be because I think the way XML configuration Spring Bean is very simple, it does not look good to write, so a little rejection of it. 23333 ~

This article notes the way for talks, and gives the corresponding DEMO; after parsing the source code will be annotated in this way as an example to explain the Spring AOP source (read the entire source code parsing, by analogy would be otherwise, because the principle is the same)

If you are interested in other configurations students can google other learning materials.


To a dividing line, the official start

1. Open the @AspectJNotes configuration

Open @AspectJannotation configuration, there are two ways

  1. In XML configuration:

    <aop:aspectj-autoproxy/>
    复制代码
  2. Use @EnableAspectJAutoProxyannotations

    @Configuration
    @EnableAspectJAutoProxy
    public class Config {
    
    }
    复制代码

After the above-described configuration is turned on, all in a container , the @AspectJannotated bean will be arranged Spring AOP as a class, referred to as an Aspect.

NOTE: There is a place to note, @ AspectJ annotation can only act on the Spring Bean above, so you use @Aspect modified class with either @Component comment modification, either through configuration in XML.

For example, the following wording,

// 有效的AOP配置类
@Aspect
@Component
public class MyAspect {
 	//....   
}

// 如果没有在XML配置过,那这个就是无效的AOP配置类
@Aspect
public class MyAspect {
 	//....   
}
复制代码

2. Configure Pointcut (enhanced entry point)

Pointcut been translated into point cut in most places, which is used to define the method needs to be enhanced or need to be blocked.

In Spring, we can think Pointcut be used to match the Spring bean container, all methods that meet the specified criteria.

For example, the following wording,

    // 指定的方法
    @Pointcut("execution(* testExecution(..))")
    public void anyTestMethod() {}
复制代码

Here's the full list what Pointcut matching mode:

  1. Execution : matching method signature

    The easiest way to the above examples, "execution(* testExecution(..))"is called a matching testExecutionmethod *represent any return value, (..)zero or more of any parameters.

  2. ** within: ** where the specified class or package where the following method (Spring AOP unique)

        // service 层
        // ".." 代表包及其子包
        @Pointcut("within(ric.study.demo.aop.svc..*)")
        public void inSvcLayer() {}
    复制代码
  3. @annotation : have a specific comment on the method

        // 指定注解
        @Pointcut("@annotation(ric.study.demo.aop.HaveAop)")
        public void withAnnotation() {}
    复制代码
  4. bean (idOrNameOfBean): match the name of the bean (Spring AOP exclusive)

        // controller 层
        @Pointcut("bean(testController)")
        public void inControllerLayer() {}
    复制代码

The above is routine in several common configuration uses

There are finer matching requirements, refer to this article: www.baeldung.com/spring-aop-...

About Pointcut configuration, Spring official recommendation has this to say:

When working with enterprise applications, you often want to refer to modules of the application and particular sets of operations from within several aspects. We recommend defining a "SystemArchitecture" aspect that captures common pointcut expressions for this purpose. A typical such aspect would look as follows:

It means that, if you are working with enterprise applications, Spring suggest that you use SystemArchitecturethis configuration section, some of the upcoming public PointCut configured to write all this inside a class maintenance. Examples of documents to the official website like this (it is used in the XML configuration file, it did not add @Component comment)

package com.xyz.someapp;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class SystemArchitecture {

  /**
   * A join point is in the web layer if the method is defined
   * in a type in the com.xyz.someapp.web package or any sub-package
   * under that.
   */
  @Pointcut("within(com.xyz.someapp.web..*)")
  public void inWebLayer() {}

  /**
   * A join point is in the service layer if the method is defined
   * in a type in the com.xyz.someapp.service package or any sub-package
   * under that.
   */
  @Pointcut("within(com.xyz.someapp.service..*)")
  public void inServiceLayer() {}

  /**
   * A join point is in the data access layer if the method is defined
   * in a type in the com.xyz.someapp.dao package or any sub-package
   * under that.
   */
  @Pointcut("within(com.xyz.someapp.dao..*)")
  public void inDataAccessLayer() {}

  /**
   * A business service is the execution of any method defined on a service
   * interface. This definition assumes that interfaces are placed in the
   * "service" package, and that implementation types are in sub-packages.
   * 
   * If you group service interfaces by functional area (for example, 
   * in packages com.xyz.someapp.abc.service and com.xyz.def.service) then
   * the pointcut expression "execution(* com.xyz.someapp..service.*.*(..))"
   * could be used instead.
   */
  @Pointcut("execution(* com.xyz.someapp.service.*.*(..))")
  public void businessService() {}
  
  /**
   * A data access operation is the execution of any method defined on a 
   * dao interface. This definition assumes that interfaces are placed in the
   * "dao" package, and that implementation types are in sub-packages.
   */
  @Pointcut("execution(* com.xyz.someapp.dao.*.*(..))")
  public void dataAccessOperation() {}

}
复制代码

The above SystemArchitecture well understood, the Aspect defines Pointcut pile, and then can be directly referenced anywhere in need of Pointcut.

Configuration cut-off point, which represents some of the ways we want to intercept, but the program requires a method how to intercept enhanced, is to configure Advice later be introduced.

3. Configure Advice

Note that among the actual development process, Aspect single class should abide by the principles of responsibility, do not put all of the Advice to configure all written in a class Aspect inside.

This is for the convenience of presentation, so write together.

To direct the sample code, which contains several configurations Advice (noun above mentioned concept section).

/**
 * 注:实际开发过程当中,Advice应遵循单一职责,不应混在一起
 *
 * @author Richard_yyf
 * @version 1.0 2019/10/28
 */
@Aspect
@Component
public class GlobalAopAdvice {

    @Before("ric.study.demo.aop.SystemArchitecture.dataAccessOperation()")
    public void doAccessCheck() {
        // ... 实现代码
    }

    // 实际使用过程当中 可以像这样把Advice 和 Pointcut 合在一起,直接在Advice上面定义切入点
    @Before("execution(* ric.study.demo.dao.*.*(..))")
    public void doAccessCheck() {
        // ... 实现代码
    }

    // 在方法
    @AfterReturning("ric.study.demo.aop.SystemArchitecture.dataAccessOperation()")
    public void doAccessCheck() {
        // ... 实现代码
    }

    // returnVal 就是相应方法的返回值
    @AfterReturning(
        pointcut="ric.study.demo.aop.SystemArchitecture.dataAccessOperation()",
        returning="returnVal")
    public void doAccessCheck(Object returnVal) {
        //  ... 实现代码
    }

    // 异常返回的时候
    @AfterThrowing("ric.study.demo.aop.SystemArchitecture.dataAccessOperation()")
    public void doRecoveryActions() {
        // ... 实现代码
    }

    // 注意理解它和 @AfterReturning 之间的区别,这里会拦截正常返回和异常的情况
    @After("ric.study.demo.aop.SystemArchitecture.dataAccessOperation()")
    public void doReleaseLock() {
        // 通常就像 finally 块一样使用,用来释放资源。
        // 无论正常返回还是异常退出,都会被拦截到
    }

    // 这种最灵活,既能做 @Before 的事情,也可以做 @AfterReturning 的事情
    @Around("ric.study.demo.aop.SystemArchitecture.businessService()")
    public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
       	//  target 方法执行前... 实现代码
        Object retVal = pjp.proceed();
        //  target 方法执行后... 实现代码
        return retVal;
    }
}
复制代码

In some scenarios, when we think of @Before, to get into the reference method, such as recording some of the log , we can org.aspectj.lang.JoinPointbe realized. The above ProceedingJoinPointis its subclasses.

@Before("...")
public void logArgs(JoinPoint joinPoint) {
    System.out.println("方法执行前,打印入参:" + Arrays.toString(joinPoint.getArgs()));
}
复制代码

As another corresponding thereto, the method returns a reference print:

@AfterReturning( pointcut="...", returning="returnVal")
public void logReturnVal(Object returnVal) {
    System.out.println("方法执行后,打印返参:" + returnVal));
}
复制代码

Quick Demo

After introducing the above configuration, we use a quick Demo to actually demonstrate it again. Here the sequence change it;

1. Preparation of the target class

package ric.study.demo.aop.svc;

public interface TestSvc {

    void process();
}

@Service("testSvc")
public class TestSvcImpl implements TestSvc {
    @Override
    public void process() {
        System.out.println("test svc is working");
    }
}

public interface DateSvc {

    void printDate(Date date);
}

@Service("dateSvc")
public class DateSvcImpl implements DateSvc {

    @Override
    public void printDate(Date date) {
        System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date));
    }
}
复制代码

2. Configure Pointcut

@Aspect
@Component
public class PointCutConfig {
    @Pointcut("within(ric.study.demo.aop.svc..*)")
    public void inSvcLayer() {}   
}
复制代码

3. Configure Advice

/**
 * @author Richard_yyf
 * @version 1.0 2019/10/29
 */
@Component
@Aspect
public class ServiceLogAspect {

    // 拦截,打印日志,并且通过JoinPoint 获取方法参数
    @Before("ric.study.demo.aop.PointCutConfig.inSvcLayer()")
    public void logBeforeSvc(JoinPoint joinPoint) {
        System.out.println("在service 方法执行前 打印第 1 次日志");
        System.out.println("拦截的service 方法的方法签名: " + joinPoint.getSignature());
        System.out.println("拦截的service 方法的方法入参: " + Arrays.toString(joinPoint.getArgs()));
    }

    // 这里是Advice和Pointcut 合在一起配置的方式
    @Before("within(ric.study.demo.aop.svc..*)")
    public void logBeforeSvc2() {
        System.out.println("在service的方法执行前 打印第 2 次日志");
    }
}
复制代码

4. Turn @AspectJannotation configuration, and start

For convenience diagram, the configuration class and the class started writing together,

/**
 * @author Richard_yyf
 * @version 1.0 2019/10/28
 */
@Configuration
@EnableAspectJAutoProxy
@ComponentScan("ric.study.demo.aop")
public class Boostrap {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Boostrap.class);
        TestSvc svc = (TestSvc) context.getBean("testSvc");
        svc.process();
        System.out.println("==================");
        DateSvc dateSvc = (DateSvc) context.getBean("dateSvc");
        dateSvc.printDate(new Date());
    }
}
复制代码

5. Output

在service 方法执行前 打印第 1 次日志
拦截的service 方法的方法签名: void ric.study.demo.aop.svc.TestSvcImpl.process()
拦截的service 方法的方法入参: []
在service的方法执行前 打印第 2 次日志
test svc is working
==================
在service 方法执行前 打印第 1 次日志
拦截的service 方法的方法签名: void ric.study.demo.aop.svc.DateSvcImpl.printDate(Date)
拦截的service 方法的方法入参: [Mon Nov 04 18:11:34 CST 2019]
在service的方法执行前 打印第 2 次日志
2019-11-04 18:11:34
复制代码

JDK dynamic proxies and Cglib

Front mentioned, Spring AOP in the target class has time to implement the interface, use JDK dynamic proxy to generate proxy classes, we combine the above look at DEMO,

image.png

If we want to implement the interface regardless of whether there are ways to force the use of Cglib realized how to do?

Spring provides gives us the corresponding configuration, that is proxy-target-class.

注解方式:
//@EnableAspectJAutoProxy(proxyTargetClass = true) // 这样子就是默认使用CGLIB
XML方式:
<aop:config proxy-target-class="true">
复制代码

After the change,

image.png

summary

This paper describes the origin of the term and the concept of Spring AOP annotation-based use.

According to this article the author's writing habits, the source code is parsed pre-study chapters chapters. In the next chapter, we will annotate the entrance way, introduce Spring AOP source design, interpretation of related core source (read the entire source code parsing, by analogy would be otherwise, because the principle is the same).

Interested can turn [Introduction] section, look at what mind mapping.

If this article helpful to you, hoping to spot a praise, this is the biggest driving force for me.

Guess you like

Origin juejin.im/post/5dbffe37f265da4d17138615