AOP(面向切面编程)
1.概述
AOP为AspectOrientedProgramming 的缩写,意为:面向切面编程,通过 预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。 AOP是OOP的延续,是软件开发中的一个热点,是java开发中的一个重要内 容。利用AOP可以对业务逻辑和非业务逻辑进行隔离,从而使得各部分之间的 耦合度降低,提高程序的可重用性,同时提高了开发的效率。
AOP、OOP在字面上虽然非常类似,但却是面向不同领域的两种设计思想。OOP (面向对象编程)针对业务处理过程的实体及其属性和行为进行抽象封装,以获 得更加清晰高效的逻辑单元划分。 而AOP则是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的 某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。这两种设 计思想在目标上有着本质的差异。
面向切面编程的好处就是: 减少重复,专注业务;
将业务代码和非业务代码分开
Reader reader = null;try {/*非业务代码*/reader = Resources.getResourceAsReader("mybatis.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);SqlSession sqlSession = sqlSessionFactory.openSession();/* 业务代码*/S_studentDao studentDao =sqlSession.getMapper(S_studentDao.class);System.out.println("班级id=2学生信息");ArrayList<S_student> sStudents = studentDao.getStudentsByClassId(2);for (S_student sStudent : sStudents) {System.out.println(sStudent);}/*非业务代码*/sqlSession.commit();sqlSession.close();} catch (IOException e) {throw new RuntimeException(e);}}
注意:面向切面编程只是面向对象编程的一种补充。
核心原理:
使用动态代理的方式在执行方法前后或者出现异常的时候做加入相关的逻辑.
使用案例:
事务处理:开启事务,关闭事务,出现异常后回滚事务
权限判断:在执行方法前,判断是否具有权限
日志:在执行前进行日志处理
这样我们就做到了 业务代码 与 非业务代码进行隔离,实现低耦合度
总结:面向切片编程,是一种将非业务代码与业务代码进行分离的一种思想,在实际开发中,往往许多重复操作,例如事务提交,权限验证,保存日志等功能
面向切片变成,就是将非业务代码进行抽取,然后在不修改原来代码的前提下,为我们的业务代码添加额外的功能
底层使用的是动态代理技术,让代理对象,帮助我们调用非业务代码
AOP思想不是spring特有的,是java中的动态代理模式,是spring框架中使用这一思想
2.概念
连接点(Joinpoint):类中可以被增强的方法(可以添加额外功能的方法),这个方法就被称为连接点
(增强:增加额外的方法)
切入点(pointcut):类中有很多方法可以被增强,但实际中只有add和update 被增强了,那么add和update方法就被称为切入点(实际实现的连接点)
通知(Advice): 通知是指一个切面在特定的连接点要做的事情(增强的功能)。通 知分为方法执行前通知,方法执行后通知,环绕通知等.
目标(Target): 代理的目标对象(连接点,切入点所在类)
代理(Proxy): 向目标对象应用通知时创建的代理对象(目前所使用的代理对象由Spring框架生成,不需要我们去关心)
3.springAOP 实现(AspectJ框架)
对于 AOP 这种编程思想,很多框架都进行了实现。Spring 就是其中之一,
可以完成面向切面编程。
AspectJ
是一个基于Java语言的AOP框架
,它提供了强大的AOP功能,且其实
现方式更为简捷,使用更为方便, 而且还支持注解式开发。所以,Spring 又
将 AspectJ 的对于 AOP 的实现也引入到了自己的框架中。
下载AOP相关jar
<dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.2.2.RELEASE</version>
</dependency>
AspectJ 中常用的通知有五种类型:
前置通知,后置通知,环绕通知,异常通知,返回通知.
-
@Before前置通知
:方法执行之前 -
@After后置通知
:方法执行之后,无论是否出现异常 -
@AfterReturnning返回通知
:方法成功执行之后通知,出现异常不执行 -
@AfterThrowing异常通知
:抛出异常之后通知 -
@Around环绕通知
:方法执行前后都有通知
基于注解方式的实现 启动AspectJ支持:
<aop:aspectj-autoproxy/>
@After 与 @AfterReturning 区别:After 无论方法是否正常执行都会执行,AfterReturning 只在方法正常执行后才执行。
配置案例具体分析
总体框架:
只需要配置spring.xml与pom.xml即可
spring.xml
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 开启注解扫描 对指定包下的注解进行扫描 ,检查添加spring类注解标签的类--><context:component-scan base-package="org.example"/><!-- 开启自动代理--><aop:aspectj-autoproxy/></beans>
pom.<?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>org.example</groupId><artifactId>spring2</artifactId><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies>
<!-- AOP实现依赖--><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.2.2.RELEASE</version></dependency><!--spring-context--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.2.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.2.RELEASE</version></dependency><!-- spring-jdbc--><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.2.2.RELEASE</version></dependency><!-- 阿里数据源--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.10</version></dependency><!-- mysql驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.16</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.4.2</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>1.3.1</version></dependency></dependencies></project>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>org.example</groupId><artifactId>spring2</artifactId><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies>
<!-- AOP实现依赖--><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.2.2.RELEASE</version></dependency><!--spring-context--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.2.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.2.RELEASE</version></dependency><!-- spring-jdbc--><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.2.2.RELEASE</version></dependency><!-- 阿里数据源--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.10</version></dependency><!-- mysql驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.16</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.4.2</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>1.3.1</version></dependency></dependencies></project>
AdminDao类
package org.example.dao;import org.example.comment.LogUtil;
import org.springframework.stereotype.Repository;@Repository
public class AdminDao {public void saveAdmin(){System.out.println("Admin saved successfully");
// new LogUtil().saveLogin();}public void deleteAdmin(){System.out.println("Admin deleted successfully");}public void updateAdmin(){System.out.println("Admin updated successfully");
// new LogUtil().commit();}}
LogUtil类
package org.example.comment;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;import java.util.Arrays;@Component //spring管理生成LogUtil对象
@Aspect //添加此标签类中的方法就是代理对象要调用的方法
public class LogUtil {
// @Before("execution(* org.example.dao.AdminDao.saveAdmin(..))")@Before("execution(* org.example.dao.AdminDao.*(..))")//AdminDao层所有方法都记录日志public void saveLogin() {System.out.println("this is Login saved log!!!");}@After("execution(* org.example.dao.AdminDao.*(..))")/*After 与 AfterReturning 区别:After 无论方法是否正常执行都会执行,而 AfterReturning 只在方法正常执行后才执行。*/public void commit() {System.out.println("Transaction committed");}// @AfterThrowing("execution(* org.example.dao.AdminDao.*(..))")
// public void exception1() {
// System.out.println("Exception occurred");
// }@AfterThrowing(value = "execution(* org.example.dao.AdminDao.*(..))",throwing = "e")public void exception2(Throwable e) {System.out.println("Exception occurred");}/** 环绕通知:* 环绕通知是指在方法调用前后以及异常调用的通知都要执行的通知,可以用来对方法进行拦截、修改或增强。* 环绕通知的定义格式为:* */@Around("execution(* org.example.dao.AdminDao.*(..))")public Object around(ProceedingJoinPoint joinPoint) {System.out.println("before around");Object result = null;try {System.out.println("保存日志");//前置通知Object[] args = joinPoint.getArgs();//获取方法参数System.out.println("参数:" + Arrays.toString(args));result = joinPoint.proceed();//调用我们自己的方法System.out.println("提交事务");//返回通知} catch (Throwable e) {e.printStackTrace();//异常通知}System.out.println("after around");//后置通知return result;}
}
AdminService
package org.example.service;import org.example.dao.AdminDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service("adminService")
public class AdminService {@AutowiredAdminDao adminDao;public void saveAdmin(){adminDao.saveAdmin();}public void deleteAdmin(){adminDao.deleteAdmin();}public void updateAdmin(){adminDao.updateAdmin();}
}
test类
package org.example.test;import org.example.service.AdminService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class test {public static void main(String[] args) {
// AdminService adminService = new AdminService();
// adminService.saveAdmin();
// adminService.updateAdmin();ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");AdminService adminService = (AdminService) context.getBean("adminService");adminService.saveAdmin();}
}
运行结果: