Spring支持AspectJ的注解式切面编程。

(1)使用@Aspect声明是一个切面。

(2)使用@After、@Before、@Around定义建言(advice),可直接将拦截规则(切点)作为参数。

(3)其中@After、@Before、@Around参数的拦截规则为切点(PointCut),为了使切点复用,可使用@PointCut专门定义拦截规则,然后在@After、@Before、@Around的参数中调用。

(4)其中符合条件的每一个被拦截处为连接点(JoinPoint)。

本节示例将演示基于注解拦截和基于方法规则拦截两种方式,演示一种模拟记录操作的日志系统的实现。其中注解式拦截能够很好地控制要拦截的粒度和获得更丰富的信息,Spring本身在事务处理(@Transcational)和数据缓存(@Cacheable等)上面都使用此种形式的拦截。

<dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.1.6.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>4.1.6.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>4.1.6.RELEASE</version>
        </dependency>
<!--        spring aop支持-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>4.1.6.RELEASE</version>
        </dependency>
<!--        aspectj支持-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.8.5</version>
        </dependency>
<!--        -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.5</version>
        </dependency>
    </dependencies>
package com.shrimpking.test1;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Created by IntelliJ IDEA.
 *
 * @Author : Shrimpking
 * @create 2024/1/5 21:45
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Action
{
    String name();

}

这里讲下注解,注解本身是没有功能的,就和xml一样。注解和xml都是一种元数据,元数据即解释数据的数据,这就是所谓配置。

package com.shrimpking.test1;

import org.springframework.stereotype.Service;

/**
 * Created by IntelliJ IDEA.
 *
 * @Author : Shrimpking
 * @create 2024/1/5 21:49
 */
@Service
public class AnnotationService
{
    @Action(name = "注解式拦截add操作")
    public void add(){

    }


}
package com.shrimpking.test1;

import org.springframework.stereotype.Service;

/**
 * Created by IntelliJ IDEA.
 *
 * @Author : Shrimpking
 * @create 2024/1/5 21:52
 */
@Service
public class MethodService
{
    public void add(){

    }
}
package com.shrimpking.test1;


import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * Created by IntelliJ IDEA.
 *
 * @Author : Shrimpking
 * @create 2024/1/5 21:53
 */
@Aspect
@Component
public class LogAspect
{
    @Pointcut("@annotation(com.shrimpking.test1.Action)")
    public void annotationPointCut(){

    }

    @After("annotationPointCut()")
    public void after(JoinPoint joinPoint){
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Action action = method.getAnnotation(Action.class);
        System.out.println("注解式拦截 " + action.name());
    }

    @Before("execution(* com.shrimpking.test1.MethodService.*(..))")
    public void before(JoinPoint joinPoint){
       MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        Method method = signature.getMethod();
        System.out.println("方法式的拦截 " + method.getName());
    }
}

①通过@Aspect注解声明一个切面。

②通过@Component让此切面成为Spring容器管理的Bean。

③通过@PointCut注解声明切点。

④通过@After注解声明一个建言,并使用@PointCut定义的切点。

⑤通过反射可获得注解上的属性,然后做日志记录相关的操作,下面的相同。

⑥通过@Before注解声明一个建言,此建言直接使用拦截规则作为参数。

package com.shrimpking.test1;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

/**
 * Created by IntelliJ IDEA.
 *
 * @Author : Shrimpking
 * @create 2024/1/5 22:08
 */
@Configuration
@ComponentScan("com.shrimpking")
@EnableAspectJAutoProxy
public class AopConfig
{
}

使用@EnableAspectJAutoProxy注解开启Spring对AspectJ代理的支持。

package com.shrimpking.test1;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * Created by IntelliJ IDEA.
 *
 * @Author : Shrimpking
 * @create 2024/1/5 22:09
 */
public class Main
{
    public static void main(String[] args)
    {
        AnnotationConfigApplicationContext context
                = new AnnotationConfigApplicationContext(AopConfig.class);
        AnnotationService annotationService = context.getBean(AnnotationService.class);
        MethodService methodService = context.getBean(MethodService.class);
        annotationService.add();
        methodService.add();
        context.close();
    }
}
"C:\Program Files\Java\jdk1.8.0_181\bin\java.exe" -javaagent:C:\ProgramX\ideaIU-2019.2.2.win\lib\idea_rt.jar=56091:C:\ProgramX\ideaIU-2019.2.2.win\bin -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_181\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar;E:\idea_code\springboot80\demo2\target\classes;E:\maven_store\repository\org\springframework\spring-context\4.1.6.RELEASE\spring-context-4.1.6.RELEASE.jar;E:\maven_store\repository\org\springframework\spring-expression\5.3.30\spring-expression-5.3.30.jar;E:\maven_store\repository\org\springframework\spring-beans\4.1.6.RELEASE\spring-beans-4.1.6.RELEASE.jar;E:\maven_store\repository\org\springframework\spring-core\4.1.6.RELEASE\spring-core-4.1.6.RELEASE.jar;E:\maven_store\repository\commons-logging\commons-logging\1.2\commons-logging-1.2.jar;E:\maven_store\repository\org\springframework\spring-aop\4.1.6.RELEASE\spring-aop-4.1.6.RELEASE.jar;E:\maven_store\repository\aopalliance\aopalliance\1.0\aopalliance-1.0.jar;E:\maven_store\repository\org\aspectj\aspectjrt\1.8.5\aspectjrt-1.8.5.jar;E:\maven_store\repository\org\aspectj\aspectjweaver\1.8.5\aspectjweaver-1.8.5.jar" com.shrimpking.test1.Main
一月 05, 2024 10:56:52 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@3f91beef: startup date [Fri Jan 05 22:56:52 CST 2024]; root of context hierarchy
注解式拦截 注解式拦截add操作
方法式的拦截 add
一月 05, 2024 10:56:52 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext doClose
信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@3f91beef: startup date [Fri Jan 05 22:56:52 CST 2024]; root of context hierarchy

Process finished with exit code 0