For more information, see: spring.hhui.top/

In the last post, a summary of AOP’s basic usage posture introduced a simple way to use AOP. At the end of the article, several problems were raised to be solved. This post will take a look at more instructions for using AOP to address these problems

I. Advanced skills

1. Annotation interception

In the previous article, the main introduction is based on the regular expression to intercept the corresponding method, the next demonstration how to use annotations to intercept the target method, implementation is relatively simple

First create annotations

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnoDot {
}
Copy the code

Then add annotations on the target method, here with the help of a blog post in front of the project, to create a new com. Git. Hui. Boot. Aop. Demo2. AnoDemoBean, pay attention to the package path is not blocked by above AnoAspect define Advice, The purpose of creating a new package path here is to minimize the number of interference items

@Component
public class AnoDemoBean {
    @AnoDot
    public String genUUID(long time) {
        try {
            System.out.println("in genUUID before process!");
            return UUID.randomUUID() + "|" + time;
        } finally {
            System.out.println("in genUUID finally!"); }}}Copy the code

Next, define the corresponding advice and add it directly to the previous AnoAspect.

@Aspect
@Component
public class AnoAspect {
    @Before("@annotation(AnoDot)")
    public void anoBefore(a) {
        System.out.println("AnoAspect "); }}Copy the code

The test code

@SpringBootApplication
public class Application {
    private AnoDemoBean anoDemoBean;

    public Application(AnoDemoBean anoDemoBean) {
        this.anoDemoBean = anoDemoBean;
        this.anoDemoBean();
    }

    private void anoDemoBean(a) {
        System.out.println("> > > > > > >" + anoDemoBean.genUUID(System.currentTimeMillis()));
    }
    
    public static void main(String[] args) { SpringApplication.run(Application.class); }}Copy the code

The output is as follows, where the logic in before Advice is executed before the target method is executed

AnoAspect 
in genUUID before process!
in genUUID finally!
>>>>>>>3a5d749d-d94c-4fc0-a7a3-12fd97f3e1fa|1551513443644
Copy the code

2. Multiple advice intercepts

If more than one advice satisfies the interception rule while a method is executing, will all of them fire? As you know from the previous blog post, different types of advice can be intercepted. What if there are multiple types of advice?

In front of a blog post on the basis of the operation, we extend the com. Git. Hui. Boot. Aop. Demo. DemoBean

@Component
public class DemoBean {
    @AnoDot
    public String genUUID(long time) {
        try {
            System.out.println("in genUUID before process!");
            return UUID.randomUUID() + "|" + time;
        } finally {
            System.out.println("in genUUID finally!"); }}}Copy the code

The corresponding test section content is as follows

@Aspect
@Component
public class AnoAspect {

    @Before("execution(public * com.git.hui.boot.aop.demo.*.*(*))")
    public void doBefore(JoinPoint joinPoint) {
        System.out.println("do in Aspect before method called! args: " + JSON.toJSONString(joinPoint.getArgs()));
    }

    @Pointcut("execution(public * com.git.hui.boot.aop.demo.*.*(*))")
    public void point(a) {}@After("point()")
    public void doAfter(JoinPoint joinPoint) {
        System.out.println("do in Aspect after method called! args: " + JSON.toJSONString(joinPoint.getArgs()));
    }

    /** * After executing, specify parameters through args; Specify results returned by RETURNING, requiring that the return value type matches * *@param time
     * @param result
     */
    @AfterReturning(value = "point() && args(time)", returning = "result")
    public void doAfterReturning(long time, String result) {
        System.out.println("do in Aspect after method return! args: " + time + " ans: " + result);
    }

    @Around("point()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("do in Aspect around ------ before");
        Object ans = joinPoint.proceed();
        System.out.println("do in Aspect around ------- over! ans: " + ans);
        return ans;
    }

    @Before("point()")
    public void sameBefore(a) {
        System.out.println("SameAspect");
    }

    @Before("@annotation(AnoDot)")
    public void anoBefore(a) {
        System.out.println("AnoAspect"); }}Copy the code

The test code is as follows

@SpringBootApplication
public class Application {
    private DemoBean demoBean;

    public Application(DemoBean demoBean) {
        this.demoBean = demoBean;
        this.demoBean();
    }

    private void demoBean(a) {
        System.out.println("> > > > >" + demoBean.genUUID(System.currentTimeMillis()));
    }

    public static void main(String[] args) { SpringApplication.run(Application.class); }}Copy the code

The output is as follows: all facets are executed, that is, advice that meets the criteria is intercepted

do in Aspect around ------ before
AnoAspect
do in Aspect before method called! args: [1551520547268]
SameAspect
in genUUID before process!
in genUUID finally!
do in Aspect around ------- over! ans: 5f6a5616-f558-4ac9-ba4b-b4360d7dc238|1551520547268
do in Aspect after method called! args: [1551520547268]
do in Aspect after method return! args: 1551520547268 ans: 5f6a5616-f558-4ac9-ba4b-b4360d7dc238|1551520547268
>>>>> 5f6a5616-f558-4ac9-ba4b-b4360d7dc238|1551520547268
Copy the code

3. Nested interception

There are several ways of nesting cases, so let’s look at the first one

A. If the invoked method does not meet the interception rules, invoke other methods that meet the interception conditions

Here we continue the simulation with the bean from the first section, adding a method in the AnoDemoBean class

@Component
public class AnoDemoBean {

    public String randUUID(long time) {
        try {
            System.out.println("in randUUID start!");
            return genUUID(time);
        } finally {
            System.out.println("in randUUID finally!"); }}@AnoDot
    public String genUUID(long time) {
        try {
            System.out.println("in genUUID before process!");
            return UUID.randomUUID() + "|" + time;
        } finally {
            System.out.println("in genUUID finally!"); }}}Copy the code

The corresponding section is

@Aspect
@Component
public class NetAspect {

    @Around("@annotation(AnoDot)")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("In NetAspect doAround before!");
        Object ans = joinPoint.proceed();
        System.out.println("In NetAspect doAround over! ans: " + ans);
        returnans; }}Copy the code

Then the test case needs to be changed to call AnoDemoBean#randUUID directly to see if the genUUID of the call inside the method is intercepted by the cut

@SpringBootApplication
public class Application {
    private AnoDemoBean anoDemoBean;

    public Application(AnoDemoBean anoDemoBean) {
        this.anoDemoBean = anoDemoBean;
        this.anoDemoBean();
    }

    private void anoDemoBean(a) {
        System.out.println("> > > > > > >" + anoDemoBean.randUUID(System.currentTimeMillis()));
    }

    public static void main(String[] args) { SpringApplication.run(Application.class); }}Copy the code

The following output is displayed, indicating that logs are not intercepted in this scenario

in randUUID start!
in genUUID before process!
in genUUID finally!
in randUUID finally!
>>>>>>>0c6a5ccf-30c0-4ac0-97f2-3dc063580f3d|1551522176035
Copy the code

B. If the invocation method does not meet the interception rules, invoke methods that meet the interception conditions in other classes

We use the previous example again, but with a slight change to AnoDemoBean, calling the DemoBean method from section 2

The code for DemoBean is as follows

@AnoDot
public String genUUID(long time) {
    try {
        System.out.println("in DemoBean genUUID before process!");
        return UUID.randomUUID() + "|" + time;
    } finally {
        System.out.println("in DemoBean genUUID finally!"); }}Copy the code

Then the code for AnoDemoBean is as follows

@Component
public class AnoDemoBean {
    @Autowired
    private DemoBean demoBean;

    public String randUUID(long time) {
        try {
            System.out.println("in AnoDemoBean randUUID start!");
            return genUUID(time) + "< < < > > >" + demoBean.genUUID(time);
        } finally {
            System.out.println("in AnoDemoBean randUUID finally!"); }}@AnoDot
    public String genUUID(long time) {
        try {
            System.out.println("in AnoDemoBean genUUID before process!");
            return UUID.randomUUID() + "|" + time;
        } finally {
            System.out.println("in AnoDemoBean genUUID finally!"); }}}Copy the code

The test code is exactly the same as before, so let’s look at the output

in AnoDemoBean randUUID start!
in AnoDemoBean genUUID before process!
in AnoDemoBean genUUID finally!
# # # 3 above behavior anoDemoBean# randUUID method call anoDemoBean# genUUID method, the output, you can see no section of the log output
Below is a call to the demoBean#genUUID method to see the log of the aspect #doAround execution
In NetAspect doAround before!
in DemoBean genUUID before process!
in DemoBean genUUID finally!
In NetAspect doAround over! ans: f35b8878-fbd0-4840-8fbe-5fef8eda5e31|1551522532092
### And finally the close
in AnoDemoBean randUUID finally!
>>>>>>>e516a35f-b85a-4cbd-aae0-fa97cdecab47|1551522532092<<<>>>f35b8878-fbd0-4840-8fbe-5fef8eda5e31|1551522532092
Copy the code

From the above log analysis, it is clear that, by contrast, the method that satisfies the interception in this class will not follow the section logic; Calling a method in another class that satisfies the aspect interception will follow the aspect logic

C. Invoke methods that meet the section interception conditions, and invoke other methods that meet the section interception conditions

This is similar to the two cases, except that the method called directly also meets the condition of being intercepted by the section. Our main concern is whether the nested method will enter the section logic, so there is very little need to change, just add annotations to AnoDemoBean#randUUID and execute

@Component
public class AnoDemoBean {
    @Autowired
    private DemoBean demoBean;

    @AnoDot
    public String randUUID(long time) {
        try {
            System.out.println("in AnoDemoBean randUUID start!");
            return genUUID(time) + "< < < > > >" + demoBean.genUUID(time);
        } finally {
            System.out.println("in AnoDemoBean randUUID finally!"); }}@AnoDot
    public String genUUID(long time) {
        try {
            System.out.println("in AnoDemoBean genUUID before process!");
            return UUID.randomUUID() + "|" + time;
        } finally {
            System.out.println("in AnoDemoBean genUUID finally!"); }}}Copy the code

The output is as follows

The outermost section intercepts the execution of the AnoDemoBean#randUUID method
In NetAspect doAround before!
in AnoDemoBean randUUID start!
in AnoDemoBean genUUID before process!
in AnoDemoBean genUUID finally!
From the output of the three lines above, you can see that the internal AnoDemoBean#genUUID call does not pass the section logic again even if it meets the section blocking rules
The following 4 lines indicate that methods of other classes will enter the section logic if they meet the section blocking rules
In NetAspect doAround before!
in DemoBean genUUID before process!
in DemoBean genUUID finally!
In NetAspect doAround over! ans: d9df7388-2ef8-4b1a-acb5-6639c47f36ca|1551522969801

in AnoDemoBean randUUID finally!
In NetAspect doAround over! ans: cf350bc2-9a9a-4ef6-b496-c913d297c960|1551522969801<<<>>>d9df7388-2ef8-4b1a-acb5-6639c47f36ca|1551522969801
>>>>>>>cf350bc2-9a9a-4ef6-b496-c913d297c960|1551522969801<<<>>>d9df7388-2ef8-4b1a-acb5-6639c47f36ca|1551522969801
Copy the code

And one of the conclusions from the output is that

  • If the target method of execution calls A method of this class that satisfies the aspect rule, the aspect logic will not be triggered during the execution of method A
  • The target method of execution, if a method B of another class that satisfies the aspect rule is called, will fire aspect logic during the execution of method B

4. AOP intercepts method scope

The intercepted methods tested above are all public. Does that mean that only public methods can be intercepted?

As you can see from section 3, the private method was eliminated first. Why? Because private methods can normally only be called internally, and internal calls do not follow the aspect logic; So the next focus is on the default and protected scopes

@Component
public class ScopeDemoBean {

    @AnoDot
    String defaultRandUUID(long time) {
        try {
            System.out.println(" in ScopeDemoBean defaultRandUUID before!");
            return UUID.randomUUID() + " | default | " + time;
        } finally {
            System.out.println(" in ScopeDemoBean defaultRandUUID finally!"); }}@AnoDot
    protected String protectedRandUUID(long time) {
        try {
            System.out.println(" in ScopeDemoBean protectedRandUUID before!");
            return UUID.randomUUID() + " | protected | " + time;
        } finally {
            System.out.println(" in ScopeDemoBean protectedRandUUID finally!"); }}@AnoDot
    private String privateRandUUID(long time) {
        try {
            System.out.println(" in ScopeDemoBean privateRandUUID before!");
            return UUID.randomUUID() + " | private | " + time;
        } finally {
            System.out.println(" in ScopeDemoBean privateRandUUID finally!"); }}}Copy the code

Instead of using the methods in this class directly, using the AnoDemoBean above, we present the case for calling private methods by reflection

@Component
public class AnoDemoBean {
    @Autowired
    private ScopeDemoBean scopeDemoBean;

    public void scopeUUID(long time) {
        try {
            System.out.println("-------- default --------");
            String defaultAns = scopeDemoBean.defaultRandUUID(time);
            System.out.println("-------- default: " + defaultAns + " --------\n");


            System.out.println("-------- protected --------");
            String protectedAns = scopeDemoBean.protectedRandUUID(time);
            System.out.println("-------- protected: " + protectedAns + " --------\n");


            System.out.println("-------- private --------");
            Method method = ScopeDemoBean.class.getDeclaredMethod("privateRandUUID".long.class);
            method.setAccessible(true);
            String privateAns = (String) method.invoke(scopeDemoBean, time);
            System.out.println("-------- private: " + privateAns + " --------\n");
        } catch(Exception e) { e.printStackTrace(); }}}Copy the code

The test case

@SpringBootApplication
public class Application {
    private AnoDemoBean anoDemoBean;

    public Application(AnoDemoBean anoDemoBean) {
        this.anoDemoBean = anoDemoBean;
        this.anoDemoBean();
    }

    private void anoDemoBean(a) {
        anoDemoBean.scopeUUID(System.currentTimeMillis());
    }

    public static void main(String[] args) { SpringApplication.run(Application.class); }}Copy the code

The output is as follows. From the log print, the protected and default methods are cut

-------- default --------
In NetAspect doAround before!
 in ScopeDemoBean defaultRandUUID before!
 in ScopeDemoBean defaultRandUUID finally!
In NetAspect doAround over! ans: 2ad7e509-c62c-4f25-b68f-eb5e0b53196d | default | 1551524311537
-------- default: 2ad7e509-c62c-4f25-b68f-eb5e0b53196d | default | 1551524311537 --------

-------- protected --------
In NetAspect doAround before!
 in ScopeDemoBean protectedRandUUID before!
 in ScopeDemoBean protectedRandUUID finally!
In NetAspect doAround over! ans: 9eb339f8-9e71-4321-ab83-a8953d1b8ff8 | protected | 1551524311537
-------- protected: 9eb339f8-9e71-4321-ab83-a8953d1b8ff8 | protected | 1551524311537 --------

-------- private --------
 in ScopeDemoBean privateRandUUID before!
 in ScopeDemoBean privateRandUUID finally!
-------- private: 1826afac-6eca-4dc3-8edc-b4ca7146ce28 | private | 1551524311537 --------
Copy the code

5. Summary

The length of this blog post is quite long, mainly because the test code takes up a lot of space, so it is necessary to make a simple summary, a clear summary, convenient for those who do not want to see details, just want to get the final conclusion

Annotation interception:

  • First declare annotations
  • Add annotations to the target method
  • In the section, advice looks like this@Around("@annotation(AnoDot)")

Multiple advice situations:

  • When more than one advice satisfies an interception scenario, all are executed

Nested scene

  • If the target method of execution calls A method of this class that satisfies the aspect rule, the aspect logic will not be triggered during the execution of method A
  • The target method of execution, if a method B of another class that satisfies the aspect rule is called, will fire aspect logic during the execution of method B

scope

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

priority

Because this content is very much, so it is necessary to carry out separately, its main classification is as follows

  • Same aspect, different order of advice
  • Different aspects, order of execution of advice
  • Same aspect, same order of advice

II. The other

0. Project

  • Project: github.com/liuyueyi/sp…
  • Project: github.com/liuyueyi/sp…

1. An ashy Blog

  • A grey Blog Personal Blog blog.hhui.top
  • A Grey Blog-Spring feature Blog Spring.hhui.top

A gray personal blog, recording all the study and work in the blog, welcome everyone to go to stroll

2. Statement

As far as the letter is not as good, the above content is purely one’s opinion, due to the limited personal ability, it is inevitable that there are omissions and mistakes, if you find bugs or have better suggestions, welcome criticism and correction, don’t hesitate to appreciate

  • Micro Blog address: Small Gray Blog
  • QQ: a gray /3302797840

3. Scan attention

A gray blog

Knowledge of the planet