当前位置:网站首页 > 技术博客 > 正文

@aspect注解与@pointcut



@AspectJ相关文章

《》

《》

《》

与 AspectJ 相同的是,Spring AOP 同样需要对目标类进行增强,也就是生成新的 AOP 代理类;与 AspectJ 不同的是,Spring AOP 无需使用任何特殊命令对 Java 源代码进行编译,它采用运行时动态地、在内存中临时生成“代理类”的方式来生成 AOP 代理。

Spring 允许使用 AspectJ Annotation 用于定义方面(Aspect)、切入点(Pointcut)和增强处理(Advice),Spring 框架则可识别并根据这些 Annotation 来生成 AOP 代理。Spring 只是使用了和 AspectJ 5 一样的注解,但并没有使用 AspectJ 的编译器或者织入器(Weaver),底层依然使用的是 Spring AOP,依然是在运行时动态生成 AOP 代理,并不依赖于 AspectJ 的编译器或者织入器。

简单地说,Spring 依然采用运行时生成动态代理的方式来增强目标对象,所以它不需要增加额外的编译,也不需要 AspectJ 的织入器支持;而 AspectJ 在采用编译时增强,所以 AspectJ 需要使用自己的编译器来编译 Java 文件,还需要织入器。

为了启用 Spring 对 @AspectJ 方面配置的支持,并保证 Spring 容器中的目标 Bean 被一个或多个方面自动增强,必须在 Spring 配置文件中配置如下片段,

2、守护者类(声明为Aspect):

3、XML配置文件:

4、测试类:

5、控制台输出:

解说:

1、通过 Spring 的 XML Schema 配置方式:

当然,如果我们希望完全启动 Spring 的“零配置”功能,则还需要启用 Spring 的“零配置”支持,让 Spring 自动搜索指定路径下 Bean 类。

所谓自动增强,指的是 Spring 会判断一个或多个方面是否需要对指定 Bean 进行增强,并据此自动生成相应的代理,从而使得增强处理在合适的时候被调用。

如果不打算使用 Spring 的 XML Schema 配置方式,则应该在 Spring 配置文件中增加如下片段来启用 @AspectJ 支持。

2、通过<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/>启动@AspectJ(此时schema中不需要相关的AOP配置

上面配置文件中的 AnnotationAwareAspectJAutoProxyCreator 是一个 Bean 后处理器(BeanPostProcessor),该 Bean 后处理器将会为容器中 Bean 生成 AOP 代理,当启动了 @AspectJ 支持后,只要我们在 Spring 容器中配置一个带 @Aspect 注释的 Bean,Spring 将会自动识别该 Bean,并将该 Bean 作为方面 Bean 处理

在 Spring 容器中配置方面 Bean(即带 @Aspect 注释的 Bean),与配置普通 Bean 没有任何区别,一样使用 <bean.https://www.cnblogs.com/duanxz/> 元素进行配置,一样支持使用依赖注入来配置属性值;如果我们启动了 Spring 的“零配置”特性,一样可以让 Spring 自动搜索,并装载指定路径下的方面 Bean。

不用xml配置文件的情况下,通过@Configuration来装配Spring bean,@EnableAspectJAutoProxy来启动spring AOP功能。见《》

使用 @Aspect 标注一个 Java 类,该 Java 类将会作为方面 Bean,如下面代码片段所示:

方面类(用 @Aspect 修饰的类)和其他类一样可以有方法、属性定义,还可能包括切入点、增强处理定义。

当我们使用 @Aspect 来修饰一个 Java 类之后,Spring 将不会把该 Bean 当成组件 Bean 处理,因此负责自动增强的后处理 Bean 将会略过该 Bean,不会对该 Bean 进行任何增强处理。

开发时无须担心使用 @Aspect 定义的方面类被增强处理,当 Spring 容器检测到某个 Bean 类使用了 @Aspect 标注之后,Spring 容器不会对该 Bean 类进行增强。

下面将会考虑采用 Spring AOP 来改写前面介绍的例子:

下面例子使用一个简单的 Chinese 类来模拟业务逻辑组件:

Chinese.java

提供了上面 Chinese 类之后,接下来假设同样需要为上面 Chinese 类的每个方法增加事务控制、日志记录,此时可以考虑使用 Around、AfterReturning 两种增强处理。

先看 AfterReturning 增强处理代码。

AfterReturningAdviceTest.java

上面 Aspect 类使用了 @Aspect 修饰,这样 Spring 会将它当成一个方面 Bean 进行处理。其中程序中粗体字代码指定将会在调用 org.crazyit.app.service.impl 包下的所有类的所有方法之后织入 log(Object rvt) 方法。

再看 Around 增强处理代码:

与前面的 AfterReturning 增强处理类似的,此处同样使用了 @Aspect 来修饰前面 Bean,其中粗体字代码指定在调用com.dxz.aop.demo6 包下的所有类的所有方法的“前后(Around)” 织入 processTx(ProceedingJoinPoint jp) 方法需要指出的是,虽然此处只介绍了 Spring AOP 的 AfterReturning、Around 两种增强处理,但实际上 Spring 还支持 Before、After、AfterThrowing 等增强处理,关于 Spring AOP 编程更多、更细致的编程细节,可以参考《轻量级 Java EE 企业应用实战》一书。

本示例采用了 Spring 的零配置来开启 Spring AOP,因此上面 Chinese 类使用了 @Component 修饰,而方面 Bean 则使用了 @Aspect 修饰,方面 Bean 中的 Advice 则分别使用了 @AfterReturning、@Around 修饰。接下来只要为 Spring 提供如下配置文件即可:

applicationContext-aop6.xml

接下来按传统方式来获取 Spring 容器中 chinese Bean、并调用该 Bean 的两个方法,程序代码如下:

BeanTest.java

从上面开发过程可以看出,对于 Spring AOP 而言,开发者提供的业务组件、方面 Bean 并没有任何特别的地方。只是方面 Bean 需要使用 @Aspect 修饰即可。程序不需要使用特别的编译器、织入器进行处理

运行上面程序,将可以看到如下执行结果:

虽然程序是在调用 Chinese 对象的 sayHello、eat 两个方法,但从上面运行结果不难看出:实际执行的绝对不是 Chinese 对象的方法,而是 AOP 代理的方法。也就是说,Spring AOP 同样为 Chinese 类生成了 AOP 代理类。这一点可通过在程序中增加如下代码看出:

上面代码可以输出 p 变量所引用对象的实现类,再次执行程序将可以看到上面代码产生class com.dxz.aop.demo6.Chinese$$EnhancerBySpringCGLIB$$7d0b6d20的输出,这才是 p 变量所引用的对象的实现类,这个类也就是 Spring AOP 动态生成的 AOP 代理类。从 AOP 代理类的类名可以看出,AOP 代理类是由 CGLIB 来生成的。

如果将上面程序程序稍作修改:只要让上面业务逻辑类 Chinese 类实现一个任意接口——这种做法更符合 Spring 所倡导的“面向接口编程”的原则。假设程序为 Chinese 类提供如下 Person 接口,并让 Chinese 类实现该接口:

Person.java

Chinese修改实现Person接口:

接下来让 BeanTest 类面向 Person 接口、而不是 Chinese 类编程。即将 BeanTest 类改为如下形式:

BeanTest.java

原来的程序是将面向 Chinese 类编程,现在将该程序改为面向 Person 接口编程,再次运行该程序,程序运行结果没有发生改变。只是 System.out.println(p.getClass()); 将会输出 class com.sun.proxy.$Proxy10,这说明此时的 AOP 代理并不是由 CGLIB 生成的,而是由 JDK 动态代理生成的

Spring AOP 框架对 AOP 代理类的处理原则是:如果目标对象的实现类实现了接口,Spring AOP 将会采用 JDK 动态代理来生成 AOP 代理类;如果目标对象的实现类没有实现接口,Spring AOP 将会采用 CGLIB 来生成 AOP 代理类——不过这个选择过程对开发者完全透明、开发者也无需关心。

Spring AOP 会动态选择使用 JDK 动态代理、CGLIB 来生成 AOP 代理,如果目标类实现了接口,Spring AOP 则无需 CGLIB 的支持,直接使用 JDK 提供的 Proxy 和 InvocationHandler 来生成 AOP 代理即可。关于如何 Proxy 和 InvocationHandler 来生成动态代理不在本文介绍范围之内,如果读者对 Proxy 和 InvocationHandler 的用法感兴趣则可自行参考 Java API 文档或《疯狂 Java 讲义》。

版权声明


相关文章:

  • 方舟生存进化神器大全_神器位置_攻略-4399方舟生存进2025-07-16 17:01:01
  • 滑动验证代码2025-07-16 17:01:01
  • 对称密码算法和非对称密码算法2025-07-16 17:01:01
  • strace命令详解2025-07-16 17:01:01
  • 我的世界java版本大全2025-07-16 17:01:01
  • pthread_cond_wait2025-07-16 17:01:01
  • 弹性盒子布局实例2025-07-16 17:01:01
  • 正品蓝导航网站多少2025-07-16 17:01:01
  • 移位运算求值2025-07-16 17:01:01
  • 逻辑回归模型的公式2025-07-16 17:01:01