Spring5——AOP

本文详细介绍了Spring5中的AOP概念,包括面向切面编程的定义、底层原理,如JDK动态代理和CGLIB动态代理。接着讨论了AOP的关键术语,如连接点、切入点和通知,并提供了准备工作和实际操作的步骤,包括基于AspectJ的XML配置和注解方式实现AOP。还探讨了如何配置通知类型、切入点表达式、增强类优先级以及完全注解开发的方法。
摘要由CSDN通过智能技术生成

AOP(概念)

1、什么是 AOP

(1)面向切面编程(方面),利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

(2)通俗描述:不通过修改源代码方式,在主干功能里面添加新功能。

(3)使用登录例子说明 AOP
在这里插入图片描述

AOP(底层原理)

1、AOP 底层使用动态代理
(1)有两种情况动态代理

第一种 有接口情况,使用 JDK 动态代理
⚫ 创建接口实现类代理对象,增强类的方法
在这里插入图片描述

第二种 没有接口情况,使用 CGLIB 动态代理
⚫ 创建子类的代理对象,增强类的方法
在这里插入图片描述

AOP(JDK 动态代理)

1、使用 JDK 动态代理,使用 Proxy 类里面的方法创建代理对象

(1)调用 newProxyInstance 方法

方法有三个参数:

第一参数,类加载器;
第二参数,增强方法所在的类,这个类实现的接口,支持多个接口;
第三参数,实现这个接口 InvocationHandler,创建代理对象,写增强的部分。

2、编写 JDK 动态代理代码

(1)创建接口,定义方法

public interface UserDao {
	 public int add(int a,int b);
	 public String update(String id);
}

(2)创建接口实现类,实现方法

public class UserDaoImpl implements UserDao {
	 @Override
	 public int add(int a, int b) {
	 	return a+b;
	 }
	 @Override
	 public String update(String id) {
	 	return id;
 } 
}

(3)使用 Proxy 类创建接口代理对象

public class JDKProxy {
	 public static void main(String[] args) {
		 //创建接口实现类代理对象
		 Class[] interfaces = {UserDao.class};

		 UserDaoImpl userDao = new UserDaoImpl();
		 UserDao dao = (UserDao)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
		 int result = dao.add(1, 2);
		 System.out.println("result:"+result);
	 } 
}
//创建代理对象代码
class UserDaoProxy implements InvocationHandler {
	 //1 把创建的是谁的代理对象,把谁传递过来
	 //有参数构造传递
	 private Object obj;
	 public UserDaoProxy(Object obj) {
	 	this.obj = obj;
	 }
	 //增强的逻辑
	 @Override
	 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		 //方法之前
		 System.out.println("方法之前执行...."+method.getName()+" :传递的参数..."+ Arrays.toString(args));
		 //被增强的方法执行
		 Object res = method.invoke(obj, args);
		 //方法之后
		 System.out.println("方法之后执行...."+obj);
		 return res;
	 } 
}

AOP(术语)

1、连接点
类里面哪些方法可以被增强,这些方法称为连接点。

2、切入点
实际被增强的方法,称为切入点。

3、通知(增强)
(1)实际增强的逻辑部分称为通知。
(2)通知有多种类型:
在这里插入图片描述

4、切面

是动作

把通知应用到切入点过程。

AOP 操作(准备工作)

1、Spring 框架一般都是基于 AspectJ 实现 AOP 操作
(1)AspectJ 不是 Spring 组成部分,独立 AOP 框架,一般把 AspectJ 和 Spirng 框架一起使用,进行 AOP 操作。

2、基于 AspectJ 实现 AOP 操作
(1)基于 xml 配置文件实现
(2)基于注解方式实现(使用)

3、在项目工程里面引入 AOP 相关依赖
在这里插入图片描述

4、切入点表达式
(1)切入点表达式作用:知道对哪个类里面的哪个方法进行增强
(2)语法结构:execution([权限修饰符] [返回类型] [类全路径] [方法名称]([参数列表])

举例 1:对 com.atguigu.dao.BookDao 类里面的 add 进行增强
execution(* com.atguigu.dao.BookDao.add(…))

举例 2:对 com.atguigu.dao.BookDao 类里面的所有的方法进行增强
execution(* com.atguigu.dao.BookDao.* (…))

举例 3:对 com.atguigu.dao 包里面所有类,类里面所有方法进行增强
execution(* com.atguigu.dao.. (…))

AOP 操作(AspectJ 注解)

1、创建类,在类里面定义方法

1、创建类,在类里面定义方法
public class User {
	 public void add() {
	 	System.out.println("add.......");
	 } 
}

2、创建增强类(编写增强逻辑)

(1)在增强类里面,创建方法,让不同方法代表不同通知类型

/增强的类
public class UserProxy {
	 public void before() {//前置通知
	 	System.out.println("before......");
	 } 
}

3、进行通知的配置
(1)在 spring 配置文件中,开启注解扫描

<?xml version="1.0" encoding="UTF-8"?>
<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/beans 
	 http://www.springframework.org/schema/beans/spring-beans.xsd 
	 http://www.springframework.org/schema/context 
	 http://www.springframework.org/schema/context/spring-context.xsd 
	 http://www.springframework.org/schema/aop 
	 http://www.springframework.org/schema/aop/spring-aop.xsd">
 <!-- 开启注解扫描 -->
 <context:component-scan basepackage="com.spring5.aopanno"></context:component-scan>

(2)使用注解创建 User 和 UserProxy 对象

//被增强的类
@Compnent
public class User {}
//增强的类
@Compnent
public class UserProxy {}

(3)在增强类上面添加注解 @Aspect

//增强的类
@Component
@Aspect //生成代理对象
public class UserProxy {}

(4)在 spring 配置文件中开启生成代理对象

<!-- 开启 Aspect 生成代理对象--> 
<aop:aspectj-autoproxy></aop:aspectj-autoproxy> 

4、配置不同类型的通知
(1)在增强类的里面,在作为通知方法上面添加通知类型注解,使用切入点表达式配置

//增强的类
@Component
@Aspect //生成代理对象
public class UserProxy {
	 //前置通知
	 //@Before 注解表示作为前置通知
	 @Before(value = "execution(* com.spring5.aopanno.User.add(..))")
	 public void before() {
	 	System.out.println("before.........");
	 }
	 //后置通知(返回通知)
	 @AfterReturning(value = "execution(* com.spring5.aopanno.User.add(..))")
	 public void afterReturning() {
	 	System.out.println("afterReturning.........");
	 }
	 //最终通知
	 @After(value = "execution(* com.spring5.aopanno.User.add(..))")
	 public void after() {
	 	System.out.println("after.........");
	 }
	 //异常通知
	 @AfterThrowing(value = "execution(* com.spring5.aopanno.User.add(..))")
	 public void afterThrowing() {
	 	System.out.println("afterThrowing.........");
	 }
	 //环绕通知
	 @Around(value = "execution(* com.spring5.aopanno.User.add(..))")
	 public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
	 	 System.out.println("环绕之前.........");
		 //被增强的方法执行
		 proceedingJoinPoint.proceed();
		 System.out.println("环绕之后.........");
	 } 
}

5、相同的切入点抽取

//相同切入点抽取
@Pointcut(value = "execution(* com.spring5.aopanno.User.add(..))")
public void pointdemo() {
}
//前置通知
//@Before 注解表示作为前置通知
@Before(value = "pointdemo()")
public void before() {
 	System.out.println("before.........");
}

6、有多个增强类多同一个方法进行增强,设置增强类优先级
(1)在增强类上面添加注解 @Order(数字类型值),数字类型值越小优先级越高

@Component
@Aspect
@Order(1)
public class PersonProxy{}

7、完全使用注解开发
(1)创建配置类,不需要创建 xml 配置文件

@Configuration
@ComponentScan(basePackages = {"com"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class ConfigAop {
}

AOP 操作(AspectJ 配置文件)

1、创建两个类,增强类和被增强类,创建方法

2、在 spring 配置文件中创建两个类对象

<!--创建对象--> 
<bean id="book" class="com.spring5.aopxml.Book"></bean> 
<bean id="bookProxy" class="com.spring5.aopxml.BookProxy"></bean> 

3、在 spring 配置文件中配置切入点

<!--配置 aop 增强--> 
<aop:config>
	 <!--切入点-->
	 <aop:pointcut id="p" expression="execution(* com.spring5.aopxml.Book.buy(..))"/>
	 <!--配置切面-->
	 <aop:aspect ref="bookProxy">
		 <!--增强作用在具体的方法上-->
		 <aop:before method="before" pointcut-ref="p"/>
	 </aop:aspect>
</aop:config>
Spring AOPSpring框架中的一个重要模块,它提供了面向切面编程(AOP)的支持。AOP是一种编程思想,它可以在不改变原有代码的情况下,通过在程序运行时动态地将代码“织入”到现有代码中,从而实现对原有代码的增强。 Spring AOP提供了基于注解的AOP实现,使得开发者可以通过注解的方式来定义切面、切点和通知等相关内容,从而简化了AOP的使用。 下面是一个基于注解的AOP实现的例子: 1. 定义切面类 ```java @Aspect @Component public class LogAspect { @Pointcut("@annotation(Log)") public void logPointcut() {} @Before("logPointcut()") public void beforeLog(JoinPoint joinPoint) { // 前置通知 System.out.println("执行方法:" + joinPoint.getSignature().getName()); } @AfterReturning("logPointcut()") public void afterLog(JoinPoint joinPoint) { // 后置通知 System.out.println("方法执行完成:" + joinPoint.getSignature().getName()); } @AfterThrowing(pointcut = "logPointcut()", throwing = "ex") public void afterThrowingLog(JoinPoint joinPoint, Exception ex) { // 异常通知 System.out.println("方法执行异常:" + joinPoint.getSignature().getName() + ",异常信息:" + ex.getMessage()); } } ``` 2. 定义业务逻辑类 ```java @Service public class UserService { @Log public void addUser(User user) { // 添加用户 System.out.println("添加用户:" + user.getName()); } @Log public void deleteUser(String userId) { // 删除用户 System.out.println("删除用户:" + userId); throw new RuntimeException("删除用户异常"); } } ``` 3. 在配置文件中开启AOP ```xml <aop:aspectj-autoproxy/> <context:component-scan base-package="com.example"/> ``` 在这个例子中,我们定义了一个切面类LogAspect,其中通过@Aspect注解定义了一个切面,通过@Pointcut注解定义了一个切点,通过@Before、@AfterReturning和@AfterThrowing注解分别定义了前置通知、后置通知和异常通知。 在业务逻辑类中,我们通过@Log注解标注了需要增强的方法。 最后,在配置文件中,我们通过<aop:aspectj-autoproxy/>开启了AOP功能,并通过<context:component-scan>扫描了指定包下的所有组件。 这样,当我们调用UserService中的方法时,就会触发LogAspect中定义的通知,从而实现对原有代码的增强。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值