The IoC Container 5. Aspect Oriented Programming with Spring

Spring AOP各种材料讲解的非常多,本章用来总结个人对Spring AOP的一点浅显理解以及用来Spring AOP快速入门。

AOP意思是面向切面编程。切面编程可以想象在某个类中砍开一个口子,这个口子是这个类中的一个方法,然后在这个口子(方法)前后植入一些逻辑,从而控制这些方法的访问。

Spring AOP实现原理是设计模式中的代理模式,更准确的说是动态代理,动态代理的意义在于控制被代理对象的访问,植入相应的逻辑,该逻辑可以在被代理对象方法的前后等地方。典型的比如Spring的事务机制就是这样实现的,在需要事务的方法上植入相应逻辑,在被代理对象方法正常执行完后执行commit,假设执行过程中发生异常,则执行rollback,这套通用的事务逻辑就是Spring AOP中Advice,Advice可以植入到任何需要该Advice的方法前后。

从设计模式的角度来讲,AOP中的Advice就是通用不变的逻辑(可复用),而Joint Point就是变的逻辑(业务逻辑,难以复用)。AOP的过程就是解耦的过程(解耦就是分离变与不变的过程)。

Spring AOP中的概念就不再叙述,大家可以在下面的示例代码中自行体会或者查看官方文档。本节不再给出xml版本的定义方式,仅给出基于注解的方式。需要的术语如下:

  • Aspect
  • Join point
  • Advice
  • Pointcut
  • Introduction
  • Target object
  • AOP proxy
  • Weaving

Spring AOP支持使用AspectJ语法定义相关面向切面编程的信息,Spring AOP仅支持AspectJ语法的子集,不过也支持继承完整的AspectJ。(Spring AOP仅使用AspectJ的语法,底层仍然是Spring自己的动态代理实现:jdk proxy或者cglib,而AspectJ本身包含自己的编译方式。如果想在Spring中使用完整的AspectJ,官方文档有相关示例,本章不讲解Full AspectJ,因为一般来说Spring AOP已经够用)。

下面给出示例和讲解:

@EnableAspectJAutoProxy开启AspectJ的Spring支持
proxyTargetClass默认为false,使用jdk proxy,不过jdk proxy有个缺陷,被代理对象必须继承自接口;proxyTargetClass设置为true,使用cglib,原理是继承方式生成子类来实现动态代理,所以需要保证类和相关切点方法不是final的才可以。

@Configuration
@ComponentScan(basePackages = "examples")
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AppConfig {
}

定义@Aspect和@PointCut
@Aspect注解在类上,表明此类用于定义切面编程的相关信息,切点定义使用@PointCut。Advice等也必须定义在@Aspect注解的类中。

package examples;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class SystemArchitecture {

    @Pointcut("execution(public * *(..))")
    public void anyPublicOperation() {}
}

@Pointcut后面的表达式用于过滤出符合该表达式条件的切点集合。@Pointcut("execution(public * *(..))")表示所有类中的所有公共方法作为切点。
Advice定义
Advice包含好几种,代码示例中是@Before Advice,这个Advice定义为@Before("examples.SystemArchitecture.anyPublicOperation()"),这里引用的是SystemArchitecture的anyPublicOperation定义所过滤的切点集合,意味着在这些切点前,都会执行doAccessCheck方法。

@Component
@Aspect
public class BeforeExample {

    @Before("examples.SystemArchitecture.anyPublicOperation()")
    public void doAccessCheck() {
        System.out.println("before advice.");
    }

}

在上面的代码示例中实现了Advice的植入,所有类的公共方法(Joint Point 切点)执行之前,都会率先执行doAccessCheck方法。Advice一般是权限检查等不变的通用逻辑,通过AOP我们实现了这些通用逻辑的复用,这些逻辑可以切入到用户代码前后执行。Spring AOP使用动态代理实现了AOP功能,默认使用jdk proxy。

最后再总结下,@PointCut和Advice必须定义在@AspectJ注解的类中。@PointCut表达式用于过滤出前后需要植入控制逻辑的方法(切点),Advice(比如@Before)定义通用的控制逻辑用于植入。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容