Spring AOP介绍(一)之 Spring AOP 基础介绍
AOP是什么?
AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。与OOP对比,AOP面向切面,传统的OOP开发中,代码逻辑是自上而下的,在这些自上而下的过程中,会产生一些横切性的问题,这些横切性的问题和我们的主业务逻辑关系不大,会散落在代码的各个地方,造成难以维护,AOP的变成思想就是把业务逻辑和横切的问题进行分离,从而达到解耦的目的,提到代码的可重用性与开发效率。
可以看下这个图:
spring aop场景.pngAOP的应用场景有哪些?
如上图中显示的:
- 日志记录
- 权限验证
- 事务管理
- 等等
Spring对于AOP是怎样实现的呢?
- JDK动态代理(接口实现)
JDK原生动态代理是Java原生支持的,不需要任何外部依赖,但是它只能基于接口进行代理
- CGLIB代理(继承)
CGLIB(Code Generation Library)是一个基于ASM的字节码生成库,
它允许我们在运行时对字节码进行修改和动态生成。CGLIB通过继承方式实现代理。
编译时期的织入还是运行时期的织入?
两者都是在运行时期织入(后面有源码介绍)
初始化时期织入还是获取对象时期织入?
通过源码分析,可以知道是在初始化时期织入(后面有源码介绍)
Spring AOP和AspectJ的关系是什么?
对于Spring AOP来说,AOP是实现的目标,AspectJ是实现的手段,类似的还有IOC(Inversion of Control 控制反转)是目标,实现的手段是DI(Dependency Injection 依赖注入)。
Spring AOP提供两种编程风格
- @AspectJ support (利用aspectj的注解)
- Schema-based AOP support (xml aop:config 命名空间)
Spring AOP应用
让我们首先了解一些AOP概念和术语。
概念 | 描述 |
---|---|
Join point(连接点) | 目标对象中的方法,类似数据库表中的一条记录 |
PointCut(切点) | 表示连接点的集合,类似数据库中的表 |
Advice(通知) | 通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类 |
Aspect(切面) | 切点、连接点、通知等的载体,它们加起来就是一个切面 |
Target object(目标对象) | 包含连接点的对象,也被称作被通知或被代理对象 |
AOP proxy(AOP 代理对象) | AOP创建的对象,包含通知 |
Weaving(织入) | 把代理逻辑加入到目标对象的过程,叫做织入 |
Before advice(前置通知) | 前置通知 |
After returning advice(后置通知) | 后置通知 |
Around advice(环绕通知) | 前后都有,最常用的一种通知 |
简单代码演示
pom.xml
<?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>com.demo.spring</groupId>
<artifactId>spring-aop</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>spring-aop Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
com.demo.spring.dao.TestDao
package com.demo.spring.dao;
import org.springframework.stereotype.Component;
/**
* PACKAGE_NAME
*
* @author Zyy
* @date 2019/3/4 23:03
*/
@Component
public class TestDao {
public void query(){
System.out.println("dao-query ...");
}
}
com.demo.spring.config.AppConfig
package com.demo.spring.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
/**
* com.demo.spring.config
*
* @author Zyy
* @date 2019/3/4 23:05
*/
@Configuration
@EnableAspectJAutoProxy
@ComponentScan("com.demo.spring")
public class AppConfig {
}
com.demo.spring.config.AspectJTest
package com.demo.spring.config;
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.springframework.stereotype.Component;
/**
* com.demo.spring.config
*
* @author Zyy
* @date 2019/3/4 23:36
*/
@Aspect
@Component
public class AspectJTest {
@Pointcut("execution(* com.demo.spring.dao.*.*(..))")
public void pointCut(){
System.out.println("point cut");
}
@After("com.demo.spring.config.AspectJTest.pointCut()")
public void after(){
System.out.println("after advice");
}
@Before("com.demo.spring.config.AspectJTest.pointCut()")
public void before(){
System.out.println("before advice");
}
}
com.demo.spring.test.AopTest
package com.demo.spring.test;
import com.demo.spring.config.AppConfig;
import com.demo.spring.dao.TestDao;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* com.demo.spring.test
*
* @author Zyy
* @date 2019/3/4 23:07
*/
public class AopTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
TestDao dao = context.getBean(TestDao.class);
dao.query();
}
}
运行结果:
before advice
dao-query ...
after advice
欢迎留言进行讨论:)
网友评论