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