网上关于Spring AOP的文章不少,但大都千篇一律,复制粘贴一把梭。对着源码夸夸其谈,但是一些基础的概念却没怎么解释。很多概念、关系描述不清,含糊其辞。可谓以其昏昏,使人昭昭。
本文旨在梳理Spring AOP相关或由Spring AOP延伸出的概念,参考Spring官方文档,对概念进行解释。
文档地址:AOP Concepts
AOP即Aspect-oriented Programming,面向切面编程。和OOP相比,是一个全新的编程方式。类比与OOP的概念,OOP核心的概念是Class类,AOP中核心的概念是Aspect切面。AOP可以将跨类型跨对象的关注点模块化。
简单的说就是,AOP可以在不同类、不同对象的指定位置,在不破坏原程序代码的情况下,完成想要完成的事。
需要注意:AOP并不是Spring发明的,也不是Spring中独有的。 AOP中常见的概念如下:
横切关注点的一个模块化
@Aspect
annotation (the @AspectJ style).切面在连接点要做的具体行为
程序运行中的一个节点,在spring中通常是一个方法的执行
注意,切点是 a predicate,切点是对连接点的判断的描述,不是什么具体的东西
给目标类增加一个新的方法的途径,这个可能接触比较少
IsModified
interface, to simplify caching. (An introduction is known as an inter-type declaration in the AspectJ community.)被切面横切的对象
AOP框架生成的代理对象实现切面功能。Spring中的AOP代理对象通常是JDK动态代理或CGLIB代理生成。
将切面与程序连接产生代理对象的过程。Spring通常是运行时织入。注意,不仅仅是在运行时织入,也可在编译时、编译后等时机织入,如AspectJ
大多数人接触到AOP,应该都是从Spring AOP开始的。但其实Spring AOP并不是完整的面向切面编程的框架,它的文档中也写了:与其他大多数AOP框架不同,Spring AOP的目标不是提供一个完整的AOP实现,而是提供一定的AOP实现,使得能与Spring的IoC容器紧密结合。
AspectJ是一个独立的、完整的AOP框架,属于Eclipse基金会。AspectJ拥有自己的语法、编译器。它的功能比Spring AOP框架更加完整也更加强大。它支持编译时、编译后、加载时织入。
Spring AOP中是使用了AspectJ框架的一部分内容。它把AspectJ中的注解拿过来,用来方便自己通过注解进行配置。
为什么讲到Spring AOP就会提到动态代理?因为Spring的AOP框架是通过动态代理的方式来产生AOP proxy的。注意,这不是AOP proxy产生的唯一方式。AspectJ可以在编译织入以静态代理的方式产生AOP proxy。
这里顺便提到一个AOP Alliance(AOP联盟)项目,它是一群对Java和AOP感兴趣的软件工程师维护的,它提供了一个依赖包aopalliance-1.0.jar,包含AOP相关概念的接口定义。
在有的文章中会提到要导入aopalliance-1.0.jar。但其实Spring AOP完全不需要引入这个包。我们可以发现spring-aop包中是完全覆盖了这个aopalliance-1.0.jar中的类,甚至对一部分进行了重写。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.dingyufan</groupId>
<artifactId>spring-aop-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<spring.version>5.2.12.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
</project>
复制代码
package cn.dingyufan.springaopdemo.aspect;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LogAspect {
@Pointcut(value = "execution(* cn.dingyufan.springaopdemo.repository..*(..))")
public void repoPointcut(){}
@Pointcut(value = "execution(* cn.dingyufan.springaopdemo.service..*(..))")
public void servicePointcut() {}
@Pointcut(value = "servicePointcut() && args(String)")
public void serviceStringPointcut(){}
@Before(value = "repoPointcut()")
public void logRepoBefore() {
System.out.println("---before repository method---");
}
@Before(value = "servicePointcut()")
public void logServiceBefore() {
System.out.println("---before service method---");
}
@Before(value = "serviceStringPointcut()")
public void logServiceStringBefore() {
System.out.println("---before service method,String---");
}
}
复制代码
package cn.dingyufan.springaopdemo.repository;
import org.springframework.stereotype.Repository;
@Repository
public class MyRepository {
public void print(String str) {
String className = this.getClass().getSimpleName();
System.out.println(className + " string is " + str);
}
}
复制代码
package cn.dingyufan.springaopdemo.service;
public interface MyService {
void print(String str);
void print(Integer num);
}
复制代码
package cn.dingyufan.springaopdemo.service;
import org.springframework.stereotype.Service;
@Service
public class MyServiceImpl implements MyService {
@Override
public void print(String str) {
String className = this.getClass().getSimpleName();
System.out.println(className + " string is " + str);
}
@Override
public void print(Integer num) {
String className = this.getClass().getSimpleName();
System.out.println(className + " number is " + num);
}
}
复制代码
package cn.dingyufan.springaopdemo;
import cn.dingyufan.springaopdemo.repository.MyRepository;
import cn.dingyufan.springaopdemo.service.MyService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import java.time.LocalDateTime;
@Configuration
@EnableAspectJAutoProxy
@ComponentScan
public class SpringAopDemoApplication {
public static void main(String[] args) {
var applicationContext = new AnnotationConfigApplicationContext(SpringAopDemoApplication.class);
int day = LocalDateTime.now().getDayOfMonth();
var myRepository = applicationContext.getBean(MyRepository.class);
myRepository.print(String.valueOf(day));
System.out.println();
var myService = applicationContext.getBean(MyService.class);
myService.print(String.valueOf(day));
System.out.println();
myService.print(day);
System.out.println();
}
}
复制代码
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。