Java常用的AOP框架有AspectJ、Spring AOP、Javassist、Guice、Byte Buddy等;本文主要介绍AspectJ的功能示例,Spring AOP的主要功能、代码示例、以及自动代理的配置和实现。并简要介绍了Spring AOP和AspectJ的关系,以及Spring AOP在Spring Boot自动配置时不同版本的差异。
AspectJ是一个基于Java语言的强大的面向切面编程(AOP)框架。它扩展了Java语言,提供了更丰富的AOP功能,并且与Java语言紧密集成。
AspectJ提供了一种在编译时或运行时织入切面逻辑的方式,以实现横切关注点的处理。它支持在方法调用、方法执行、字段访问和异常处理等连接点上应用切面逻辑。
以下是AspectJ的一些主要特点和功能:
丰富的切入点表达式:AspectJ提供了灵活且强大的切入点表达式语言,可以精确地选择要应用切面的连接点。
多种类型的通知:AspectJ支持多种类型的通知,包括前置通知、后置通知、返回通知、异常通知和环绕通知。这些通知可以在切点的不同阶段执行切面逻辑。
切面继承和优先级:AspectJ支持切面之间的继承关系和优先级设置,可以灵活地组织和管理切面。
静态织入和动态织入:AspectJ支持在编译时进行静态织入,以及在运行时通过字节码增强进行动态织入。这使得切面逻辑可以在不同的阶段应用到目标代码中。
强大的切面编程能力:AspectJ提供了丰富的切面编程能力,包括引入新的成员变量和方法到目标类中,修改现有的类和方法,以及对切点进行动态绑定等。
与Spring集成:AspectJ与Spring框架紧密集成,可以与Spring AOP无缝协作,提供更强大的AOP功能。
总体而言,AspectJ是一个功能强大且灵活的AOP框架,可以帮助开发人员更好地实现横切关注点的处理。它提供了丰富的特性和语法,使得切面编程变得更加简单和直观。无论是在JavaEE应用程序还是在Spring应用程序中,AspectJ都是一个非常有用的工具。
下面是一个逐步指南,介绍如何使用AspectJ进行切面编程:
添加AspectJ依赖:在项目的构建文件(如Maven的pom.xml或Gradle的build.gradle)中添加AspectJ的依赖项。
定义切面类:创建一个Java类,用于定义切面逻辑。可以使用@Aspect
注解来标识该类为切面类。
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class MyAspect {
// 切面逻辑代码
}
@Pointcut
注解定义切点,即指定在哪些方法或类上应用切面逻辑。import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class MyAspect {
@Pointcut("execution(* com.example.MyClass.myMethod(..))")
public void myPointcut() {
}
}
@Before
、@After
、@Around
等注解来标识通知类型。import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class MyAspect {
@Before("myPointcut()")
public void beforeAdvice() {
// 在切点方法执行前执行的逻辑
}
}
静态织入:使用AspectJ编译器,在编译期间将切面织入到目标代码中。可以使用AspectJ编译器命令行工具或IDE插件来进行编译。
动态织入:在运行时使用AspectJ织入器,通过Java命令行参数或配置文件指定织入器。
以上是使用AspectJ进行切面编程的基本步骤。根据具体的需求和场景,可以进一步扩展和配置切面逻辑,使用AspectJ提供的更多特性和语法。
Spring AOP(Aspect-Oriented Programming)是Spring框架提供的一种轻量级的AOP框架。它通过在运行时动态地将切面逻辑织入到应用程序中,实现了横切关注点的处理。
以下是Spring AOP的一些主要特点和功能:
基于代理的AOP:Spring AOP使用代理模式来实现AOP。它通过创建目标对象的代理对象,并将切面逻辑织入到代理对象中,从而实现对目标对象方法的增强。
切点和通知:Spring AOP支持使用切点(Pointcut)来定义需要应用切面逻辑的连接点,例如方法调用或字段访问等。它提供了多种类型的通知(Advice),包括前置通知(@Before)、后置通知(@After)、返回通知(@AfterReturning)、异常通知(@AfterThrowing)和环绕通知(@Around),以实现在切点处执行的切面逻辑。
自动代理:Spring AOP支持自动代理,可以根据配置自动创建代理对象,并将切面逻辑织入到目标对象中。通过使用@EnableAspectJAutoProxy
注解或配置文件中的
元素,可以启用自动代理功能。
切面的模块化:Spring AOP支持将切面逻辑模块化,可以将切面逻辑定义为一个独立的切面类,以实现切面逻辑的重用和解耦。
与Spring框架集成:Spring AOP与Spring框架无缝集成,可以与其他Spring特性(如依赖注入)一起使用,提供更强大的功能和灵活性。
不支持跨类的切面织入:Spring AOP基于代理模式实现,只能对方法级别的连接点进行切面织入,不支持跨类的切面织入。
总的来说,Spring AOP是一个简单而强大的AOP框架,可以帮助开发人员实现横切关注点的处理。它提供了基于代理的AOP机制、切点和通知的灵活组合、自动代理的支持以及与Spring框架的无缝集成。通过使用Spring AOP,开发人员可以更轻松地实现日志记录、事务管理、性能监控等横切关注点的功能。
下面是一个使用注解的示例,演示如何使用Spring AOP来记录方法执行时间:
引入依赖:确保项目中包含Spring AOP的相关依赖。
定义切面:创建一个切面类,并使用@Aspect
注解进行标记。
@Aspect
@Component
public class LoggingAspect {
// 定义切点,匹配所有的public方法
@Pointcut("execution(public * com.example.MyService.*(..))")
public void publicMethods() {}
// 编写通知,在方法执行前和执行后记录执行时间
@Around("publicMethods()")
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
Object result = joinPoint.proceed();
long endTime = System.currentTimeMillis();
long executionTime = endTime - startTime;
System.out.println(joinPoint.getSignature() + " 执行时间:" + executionTime + "ms");
return result;
}
}
@EnableAspectJAutoProxy
注解启用自动代理。@SpringBootApplication
@EnableAspectJAutoProxy
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
// ...
MyService myService = context.getBean(MyService.class);
myService.doSomething();
// ...
}
}
在上述示例中,我们创建了一个切面类LoggingAspect
,并在其中定义了一个切点publicMethods()
,它匹配com.example.MyService
类中的所有public方法。然后,我们使用@Around
注解编写了一个通知,用于在方法执行前和执行后记录执行时间。
通过在应用程序的主类上添加@EnableAspectJAutoProxy
注解,我们启用了自动代理,使得Spring能够自动创建代理对象并织入切面逻辑。
当运行应用程序时,每次调用MyService
类中的方法时,切面逻辑将记录方法的执行时间,并输出到控制台。
这个示例演示了如何使用注解来定义切面和通知,以及如何配置和启用自动代理。通过使用注解,我们可以更简洁地定义切面逻辑,并将其与特定方法或类关联起来。
在Spring AOP中,默认情况下,自动代理使用基于Java动态代理(Java Dynamic Proxy)实现。
Java动态代理是Java语言提供的一种代理机制,通过在运行时动态生成代理类和代理对象来实现代理功能。它基于接口(Interface)来创建代理对象,对目标对象的方法进行代理,并在代理对象的方法中调用目标对象的方法。
Java动态代理有一个限制,即只能代理实现了接口的类。因此,如果目标对象没有实现接口,Spring AOP将无法使用Java动态代理进行自动代理。
当目标对象实现了接口时,Spring AOP将使用Java动态代理来创建代理对象,并将切面逻辑织入到代理对象中。
如果目标对象没有实现接口,Spring AOP将尝试使用CGLib(Code Generation Library)来创建代理对象。CGLib是一个强大的代码生成库,它通过继承目标类来创建代理对象,并使用字节码增强技术来实现代理功能。
总之,当目标对象实现了接口时,Spring AOP默认使用Java动态代理来创建代理对象。当目标对象没有实现接口时,Spring AOP将使用CGLib来创建代理对象。可以通过配置来指定使用哪种代理方式。
在Spring中,可以通过配置来指定使用哪种代理方式(Java动态代理或CGLib)。以下是两种常用的配置方式:
元素配置:<aop:aspectj-autoproxy proxy-target-class="true"/>
在Spring的配置文件中,可以使用
元素来启用自动代理,并通过proxy-target-class
属性来指定是否使用CGLib代理。将proxy-target-class
属性设置为true
表示使用CGLib代理,设置为false
或省略该属性表示使用Java动态代理。
@EnableAspectJAutoProxy
注解配置:@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AppConfig {
// 配置其他Bean和AOP切面
}
在Spring的Java配置类中,可以使用@EnableAspectJAutoProxy
注解来启用自动代理,并通过proxyTargetClass
属性来指定是否使用CGLib代理。将proxyTargetClass
属性设置为true
表示使用CGLib代理,设置为false
表示使用Java动态代理。
通过以上配置方式,可以灵活地指定使用哪种代理方式。根据具体的需求和场景,选择合适的代理方式来实现AOP功能。
Spring AOP与AspectJ之间存在一定的关联。Spring AOP可以与AspectJ进行集成,利用AspectJ的注解或XML配置来定义切面,并通过Spring AOP将切面织入到目标对象中。这样,Spring AOP可以结合AspectJ的强大功能和语法,实现更灵活和强大的AOP编程。
Spring AOP是通过动态代理实现AOP的,它并不直接借助AspectJ的编译器和织入工具。虽然Spring AOP的实现受到了AspectJ的影响,并且与AspectJ有很好的集成,但Spring AOP并不使用AspectJ的编译器来修改字节码或进行静态织入。
在Spring AOP中,切面逻辑是通过动态代理来织入到目标对象中的。Spring AOP使用JDK动态代理或CGLIB动态代理来创建代理对象,并在代理对象的方法调用前后织入切面逻辑。这种动态织入的方式使得Spring AOP更加灵活和轻量级,但相对于AspectJ而言,它在切面编程的能力上可能略有限制。
Spring 中的 AOP,有接口就用 JDK 动态代理,没有接口就用 Cglib 动态代理。
Spring Boot 中的 AOP,2.0 之前和 Spring 一样;2.0 之后首选 Cglib 动态代理,如果用户想要使用 JDK 动态代理,需要自己手动配置。
AspectJ提供了两种方式来配置织入方式:静态织入和动态织入。
使用AspectJ编译器命令行工具:可以使用ajc
命令来编译包含AspectJ切面的代码。在命令行中指定目标代码和切面代码的路径,AspectJ编译器会将切面逻辑织入到目标代码中生成织入后的字节码文件。
使用IDE插件:常见的Java开发工具(如Eclipse、IntelliJ IDEA)提供了AspectJ插件,可以在IDE中配置AspectJ切面,并通过插件进行编译和织入。可以通过插件的配置界面或注解来指定切面逻辑的织入方式。
Java命令行参数:在运行Java程序时,可以使用-javaagent
参数指定AspectJ织入器,织入器会在程序启动时加载并根据配置文件将切面逻辑织入到目标代码中。
配置文件:可以创建一个AspectJ配置文件(通常是XML格式),在配置文件中指定要织入的切面和切点,以及织入方式。然后,在运行Java程序时指定该配置文件,AspectJ织入器会根据配置文件将切面逻辑织入到目标代码中。
无论是静态织入还是动态织入,配置织入方式都需要指定切面的位置和目标代码的位置,并选择合适的织入时机。具体的配置方式和细节可以根据使用的工具和需求而有所不同。
通过上述介绍,希望大家能够明白AspectJ和Spring AOP框架的原理及实现方式,以及了解Spring AOP采用了AspectJ的注解但没有采用其织入方式,而是通过动态代理的方式(JDK动态代理和CGLIB动态代理)生成代理类和代理对象。Spring AOP支持自动代理,如果目标对象实现了接口,则会采用JDK动态代理,如果没有实现接口则采用CGLIB动态代理。可以通过配置改变使用哪种动态代理,Spring Boot2.0前后的默认配置不同等。
JDK动态代理和CGLib动态代理的对比
Spring Boot 中的 AOP,到底是 JDK 动态代理还是 Cglib 动态代理?