The full code is here

What is AOP?

The full name of AOP is Aspect Oriented Program

As I understand it, the idea of AOP is, in plain English, to divide the functionality of a program into two categories: core functionality and auxiliary functionality.

In non-faceted programming, the core functions and auxiliary functions are always coupled together, such as the code that logs the behavior of the database operations (I don’t know about other people, but I do). In this way, the code for the core function (database operations) is coupled with the code for the secondary function (logging).

With AOP, the code for core and helper functions is completely separate, and they can be modified independently without interfering with each other, essentially applying the proxy pattern of the Java design pattern (review it for another day).

How does Spring apply AOP?

1. What are the preparations

  • Which packages to add?

    The full Maven configuration file is as follows:

    <?xml version="1.0" encoding="UTF-8"? >
    <project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>SpringLearn</groupId>
        <artifactId>SpringDemo</artifactId>
        <version>1.0 the SNAPSHOT</version>
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-aop</artifactId>
                <version>4.3.11. RELEASE</version>
            </dependency>
            <dependency>
                <groupId>aopalliance</groupId>
                <artifactId>aopalliance</artifactId>
                <version>1.0</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-beans</artifactId>
                <version>4.3.11. RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-core</artifactId>
                <version>4.3.11. RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>4.3.11. RELEASE</version>
            </dependency>
            <! -- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjrt</artifactId>
                <version>1.9.1</version>
            </dependency>
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.6.8</version>
            </dependency>
            <dependency>
                <groupId>commons-logging</groupId>
                <artifactId>commons-logging</artifactId>
                <version>1.2</version>
            </dependency>
        </dependencies>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-eclipse-plugin</artifactId>
                    <version>2.8</version>
                    <configuration>
                        <downloadSources>true</downloadSources>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </project>
    Copy the code
  • Which classes do YOU want to add?

    LoggerAspect

    ProductService

    Category

    Product

The directory structure is as follows:

The full code is here

2. How are core functions and auxiliary functions separated?

Create a core functionality class ProductService

package com.learn.service;

import org.springframework.stereotype.Component;

@Component("ps")
public class ProductService {

    public void doSomeService(a) {
        System.out.println("Pretend this is some core business code!"); }}Copy the code

Create a helper LoggerAspect class

package com.learn.aspect;

import org.springframework.stereotype.Component;
import org.aspectj.lang.ProceedingJoinPoint;

@Component("la")
public class LoggerAspect {
    public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("start log:" + joinPoint.getSignature().getName());
        Object object = joinPoint.proceed();
        System.out.println("end log:" + joinPoint.getSignature().getName());
        returnobject; }}Copy the code

You can see that the code for the core functions and the code for the auxiliary functions are completely separate, so how do you tie them together?

To do this, you need to configure the Spring configuration file as follows:

<?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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
   
    <! - scan bean -- -- >
    <context:component-scan base-package="com.learn.service com.learn.springBasic com.learn.aspect"/>
    
    <! - the configuration of AOP -- -- >
    <aop:config>
        <! -- Config pointcut -->
        <aop:pointcut id="loggerCutpoint" expression="execution(* com.learn.service.ProductService.*(..)) "/>
        <! -- Configure the woven object -->
        <aop:aspect id="logAspect" ref="la">
            <aop:around pointcut-ref="loggerCutpoint" method="log"/>
        </aop:aspect>
    </aop:config>

</beans>
Copy the code

The < AOP :config> tag needs to be added to the configuration file.

The < AOP: Pointcut > tag configures the core class, which specifies which object to weave into.

execution(* com.learn.service.ProductService.*(..) )Copy the code

The above expression indicates that all methods under ProductService will be woven into helper functions, which will be called when the method is executed. < AOP :aspect> is configured with helper classes

<aop:around pointcut-ref="loggerCutpoint" method="log"/>
Copy the code

The pointcut-ref in the tag above is clearly the core class ID to weave in, and method is the method to weave in.

Running results:

start log:doSomeService pretends that this is some core business code! endlog:doSomeService
Copy the code

The result looks like this because the log method in the helper class says:

System.out.println("start log:" + joinPoint.getSignature().getName());
Object object = joinPoint.proceed();
System.out.println("end log:" + joinPoint.getSignature().getName());
Copy the code

The log method ultimately returns an Object. In this case, it actually returns the ProductService Object, which is implemented in the proxy mode.

Configure AOP with annotations

Annotation configuration of AOP is also simple, much like annotation configuration of beans.

First, remove all < AOP :config> tags from the Spring configuration file and replace them with < AOP: Aspectj-AutoProxy /> tags to enable automatic proxy.

<?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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <! - scan bean -- -- >
    <context:component-scan base-package="com.learn.service com.learn.springBasic com.learn.aspect"/>
    <! Configure automatic proxy AOP
    <aop:aspectj-autoproxy/>

</beans>
Copy the code

Some changes will also be made to the LoggerAspect class, with @aspect and @around annotations.

package com.learn.aspect;

import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.aspectj.lang.ProceedingJoinPoint;

@Aspect
@Component("la")
public class LoggerAspect {

    @Around(value = "execution(* com.learn.service.ProductService.*(..) )")
    public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("start log:" + joinPoint.getSignature().getName());
        Object object = joinPoint.proceed();
        System.out.println("end log:" + joinPoint.getSignature().getName());
        returnobject; }}Copy the code

Running results:

start log:doSomeService pretends that this is some core business code! endlog:doSomeService
Copy the code

Annotation mode AOP complete code here