学完AOP技术,真的不得不佩服发明AOP技术的人,真是个天才!!!
想要了解AOP,首先要了解什么叫代理。
1.代理
我们先来说说什么叫做代理:
假如我要买辆奥迪A7,我不会直接去长春一汽工厂去买,为啥?路途远,而且,如果以这样方式购买,一手交钱,一手交车,事先没人给我介绍车辆配置情况,发动机型号等等,买完之后的后续维修等等都是没有人给我介绍的。当然,这些都是基于假设情况,现实肯定不能这样。那我应该去哪买奥迪A7呢?4S店。车是长春一汽生产的,卖是4S店卖的,这就是代理。4S店会买前给我介绍车辆的详细情况,卖完给我提供售后保障。这就叫方法的增强。
1.1静态代理
静态代理,麻烦之处在于,我要创建多个代理对象,就好比,卖奥迪就开一个奥迪4S店,卖奔驰就开个奔驰4S店,那岂不是全国各地都开满了4S店?假设所有4S店服务也都是买车前介绍车辆详情,买后都是提供维修保障。这样就出现了代码冗余的情况。
1.2动态代理
动态代理,好处就在于我只需要创建一个代理对象,我只开一家4S店,我可以销售各种车辆,我卖奥迪,就买前介绍奥迪车辆详情,买后提供奥迪售后保障。我卖奔驰,就买前介绍奔驰车辆详情,买后提供奔驰售后保障。同样能起到方法增强的作用,但是大大减少了代码的冗余。
2.AOP简介
AOP的全称是Aspect Oriented Programming,即面向切面编程。是实现功能统一维护的一种技术,它将业务逻辑的各个部分进行隔离,使开发人员在编写业务逻辑时可以专心于核心业务,从而提高了开发效率。 作用:在不修改源码的基础上,对已有方法进行增强。
实现原理:动态代理技术。
优势:减少重复代码、提高开发效率、维护方便应用场景:事务处理、日志管理、权限控制、异常处理等方面。
3.AOP框架
AOP是一种思想,是一种面向切面编程的思想,AOP的主要作用就是,告诉我们可以通过动态代理的方式,织入一段代码到已经写到另一段代码中去。
SpringAop 和 AspectJ 是两个框架,它主要就是通过AOP的思想,来实现面向切面编程。
因为动态代理的方式,不止一种,所以也出现了两个框架,其实实现的作用都是一样的。
但还是有区别:
springAOP是动态织入、AspectJ是静态织入 (静态织入的意思就是:运行AspectJ的代码,将需要被面向切面编程的代码生成出来,变成class文件。)
他们的核心就是: 动态代理。
Spring整合AspectJ很麻烦,有很多配置,那是因为AspectJ先出来,后来spring想,让你来和我的spring整合多麻烦呀,我自己写一个AOP的实现,所以出现了SpringAop,最开始spring其实也实现了aop,不过实现的不好,后来看AspectJ这个代码写的不错,然后就借用了AspectJ的语法,又实现了一遍,所以springaop其实是依赖AspectJ的,只不过依赖之后,配置简化了。
4.AOP术语
以上这些术语中,我们要首先理解,什么叫目标对象,这个就好比一汽工厂,目标类里面能被拦截的方法都叫连接点,什么切入点呢?就是要被增强的方法。说到拦截,就要说到切点表达式了
切点表达式(重点)
切点表达式负责拦截连接点,这个什么意思呢?程序开启,方法一个个执行,我想在某个或者某些方法上进行增强,首先我得先拦截到这些方法(也就是找到符合条件的方法),然后进行织入。
5.通知类型
通知执行顺序
目标类
package com.icss.zrgj;
import org.springframework.stereotype.Repository;
@Repository("carFactory")
public class CarFactory {
// 这是目标方法Target
// 目标方法中的方法被称为连接点(jionpoint)
public void sellCar() {
System.out.println("长春一汽正在售卖一汽奥迪A7");
}
public int xinsuai() {
int a=1000;
int b=2536;
int c=a+b;
System.out.println("我返回一个C");
return c;
}
// 以下也是一个连接点
public void zhaoping() {
System.out.println("长春一汽正在招聘销售人员");
System.out.println(1/0);
}
}
切面类
package com.icss.zrgj;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
//这是一个切面类
public class MyAspect {
/*在切面类中可定义多个方法*/
// 这个JoinPoint jionpoint 是目标方法的对象,可以用来获取目标对象的信息
/*例如:目标方法所属于的类
* 目标方法的名字
* 目标方法的参数列表
* 目标方法访问修饰符等
* 目标方法的返回结果(不通用)
* 目标方法的异常信息(不通用)
* */
public void before(JoinPoint jionpoint){
// 目标方法还未执行,后两个不适用
System.out.println("这是前置通知");
}
// 这两个参数分别是 ↓目标方法对象 ↓目标方法返回值
// ↓关于切面类里面的方法返回值,我们只知道返回了,但是返回哪了不知道
public int afterreturn(JoinPoint jionpoint,int h){
System.out.println(h);
System.out.println("这是后置返回通知");
return 555;
}
public void after(){
System.out.println("这是最终通知");
}
public void exception(JoinPoint jionpoint,Exception e){
System.out.println(e);
}
/*
* 环绕通知比较特殊它的参数类型叫ProceedingJoinPoint其实感觉意义一样*/
public void arount(ProceedingJoinPoint jionpoint) throws Throwable {
System.out.println("环绕前");
jionpoint.proceed();
System.out.println("环绕后");
}
}
配置文件
<?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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 扫描此包下的注解-->
<context:component-scan base-package="com.icss.zrgj"/>
<!-- 扫描配置文件-->
<context:property-placeholder location="jdbc.properties"/>
<bean id="myaspect" class="com.icss.zrgj.MyAspect"/>
<aop:config>
<aop:pointcut id="is" expression="execution(public * com.icss.zrgj.CarFactory.* (..))"/>
<aop:aspect ref="myaspect">
<aop:before method="before" pointcut-ref="is"/>
<aop:after method="after" pointcut-ref="is"/>
<!-- 这个returning是绑定方法afterreturn的参数名字(它俩名字要一样),是目标方法的返回值(afterreturn方法的第二个参数是目标方法的返回值类型)-->
<aop:after-returning method="afterreturn" returning="h" pointcut-ref="is"/>
<aop:after-throwing method="exception" throwing="e" pointcut-ref="is"/>
<aop:around method="arount" pointcut-ref="is"/>
</aop:aspect>
</aop:config>
</beans>
6.AOP代码执行过程
首先要有目标类,这个目标类可以有接口,也可以没有接口。如果有接口,底层就用JDK动态代理,如果没有接口,就用CGLIB动态代理。
接着我们要创建切面类(代理类)。
在配置文件中,首先我们要创建切面类对象,接着配置切入点和切面类。前者告诉spring,我拦截到那些方法作为切入点,后者告诉spring哪个类是切面类和哪些方法是切入点,我要织入切面类里哪个方法。
代理类中的方法如果有返回值的话,返回哪里了,这个不知道
在测试类中,再次执行目标方法,这个方法已经不是单纯的原来的方法了
注意: 目标方法的返回值 和 代理类中方法的参数的关系(可以理解为,目标对象的返回值返回到代理类方法的参数里了)
标签:Spring,代理,详解,切面,AOP,println,方法,out From: https://blog.csdn.net/weixin_69053029/article/details/137548598