1. 什么是SpringAOP
AOP 为 Aspect Oriented Programming 的缩写,意思为面向切面编程,是通过 预编译方式 和 运行期动态代理
实现程序功能的统一维护的一种技术。AOP 是 OOP 的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。
利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
------ 来自百度
简单的说:就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们的已有方法进行增强。
2. SpringAOP的作用和优势
作用:在程序运行期间,在不修改源码的情况下对方法进行功能增强;
优势:减少重复代码,提高开发效率,并且便于维护;
AOP的作用和优势就是动态代理的作用和优势,AOP的底层就是动态代理;
动态代理特点:字节码随用随创建,随用随加载,不修改源码的基础上对方法增强(在程序运行过程中创建代理对象)
3. SpringAOP底层实现
AOP的底层是通过Spring提供的动态代理技术实现的
在运行期间,Spring通过动态代理技术动态的生成代理对象,代理对象方法执行时进行增强功能的接入,再去调用目标对象的方法,从而完成功能的增强。
AOP有两种常用的代理技术:
1. JDK代理:基于接口的动态代理技术
Jdk实现的动态代理,只能给有接口的类做代理(被代理类最少实现一个接口,如果没有则不能使用)
简单的说:就是在运行时,给需要增强的类生成了一个同父异母的兄弟类,这个类不仅有他兄弟的所有功能,而且有的功能比原来的类功能更强大。
动态代理:在内存中形成代理类;
基于JDK的动态代理技术有三个角色:
- 抽象角色: — 接口
- 真实角色: — 要增强的对象
- 代理角色: — 动态代理生成的
实现步骤
1.代理对象和真实对象实现相同的接口
2.代理对象 = Proxy.newProxyInstance(); --将增强的代码,写在involve方法内!
3.使用代理对象调用方法。
4.增强方法(invoke) 代理对象中使用method.invoke 才是真正调用真实对象的方法!(先执行到代理对象,再执行真实对象)
代码的执行流程:
通过代理对象调用方法时,先执行invoke,再执行真实的方法;
结论: Jdk实现的动态代理,只能给有接口的类做代理
JDK需要让代理对象和真实对象产生联系(实现同样的接口),有共同的方法;
Proxy.newProxyInstance(),返回一个代理对象;
调用代理对象的任何方法,InvocationHandler中的invoke()都会执行
public class ProxyTest {
public static void main(String[] args) {
//目标对象
final Target target = new Target();
//增强对象
final Advice advice = new Advice();
//返回值 就是动态生成的代理对象
TargetInterface proxy = (TargetInterface) Proxy.newProxyInstance(
target.getClass().getClassLoader(), //目标对象类加载器
target.getClass().getInterfaces(), //目标对象相同的接口字节码对象数组
new InvocationHandler() {
//调用代理对象的任何方法 实质执行的都是invoke方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//前置增强
advice.before();
//执行目标方法
Object invoke = method.invoke(target, args);
//后置增强
advice.afterReturning();
return invoke;
}
}
);
//调用代理对象的方法
proxy.save();
}
}
2. cglib代理:基于子类的动态代理技术
基于cglib的动态代理 和 JDK动态代理的区别 和 联系:
区别:
-
JDK: 基于接口的动态代理, 要求代理对象和真实对象,必须实现同一个接口
-
Cglib: 基于子类的动态代理, 要求真实类不能被final修饰;(继承目标对象,然后对方法进行增强)
代理对象产生方式:
-
Jdk: Proxy.newProxyInstance
-
Cglib: Enhancer.creat
需要重写的增强不同:
-
JDK:重写involve方法;
-
Cglib: 重写intercept方法;
创建代理对象的几个参数也不一样,但是基本格式都是固定是的(增强的代码都是写在重写方法中的)
联系:
所需要增强的代码,都是写在重写的 invoke或者intercept方法的,增强代码几乎一致;
执行的顺序也一样,都是在代理对象调用方法时: 先执行增强的方法,再执行真实的方法!
结论:
何选用代理方式? — 看是否有接口!是否被final修饰!
动态代理时的关注点应该在哪里? ---- 应该放在核心的增强方法中的代码上
public class ProxyTest {
public static void main(String[] args) {
//目标对象
final Target target = new Target();
//增强对象
final Advice advice = new Advice();
//返回值 就是动态生成的代理对象 基于cglib
//1、创建增强器
Enhancer enhancer = new Enhancer();
//2、设置父类(目标)
enhancer.setSuperclass(Target.class);
//3、设置回调
enhancer.setCallback(new MethodInterceptor() {
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
advice.before(); //执行前置
Object invoke = method.invoke(target, args);//执行目标
advice.afterReturning(); //执行后置
return invoke;
}
});
//4、创建代理对象
Target proxy = (Target) enhancer.create();
proxy.save();
}
}
4.Spring AOP的概念
Spring 的 AOP 实现底层就是对上面的动态代理的代码进行了封装,封装后只需要对需要关注的部分进行代码编写,并通过配置的方式完成指定目标的方法增强。
常用的定义:
-
Target( 目标对象): 代理的目标对象. (被代理的真实对象)
-
Proxy (代理):一个类被 AOP 织入增强后,就产生一个结果代理类
-
Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点
-
Pointcut(切入点):所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义
-
Advice(通知/ 增强):所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知
-
Aspect(切面):是切入点和通知的结合
-
Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。spring采用动态代理织入。
5. Spring AOP 技术实现的内容
Spring 框架监控切入点方法的执行。
一旦监控到切入点方法被运行,使用代理机制,动态创建目标对象的代理对象,根据通知类别,在代理对象的对应位置,将通知对应的功能织入,完成完整的代码逻辑运行。
Spring 中,框架会根据目标类是否实现了接口来决定采用哪种动态代理的方式(JDK动态代理,CgLib动态代理)
6.基于 XML 的 AOP 开发
Ⅰ. Maven工程导入Spring工程的相关坐标
<!--导入spring的context坐标,context依赖aop-->
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.4</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<!--单元测试依赖-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
Ⅱ.创建目标接口和目标类
public interface TargetInterface {
public void method();
}
public class Target implements TargetInterface {
@Override
public void method() {
System.out.println("Target running....");
}
}
Ⅲ.创建切面类
public class MyAspect {
public void before(){
System.out.println("前置增强..........");
}
public void afterReturning(){
System.out.println("后置增强..........");
}
}
Ⅳ.将目标类和切面类的对象创建权交给Spring框架并配置织入 (配置到applicationContext.xml配置文件中)
<!--目标对象-->
<bean id="target" class="top.cloud.aop.Target"></bean>
<!--切面对象-->
<bean id="myAspect" class="top.cloud.aop.MyAspect"></bean>
<!--配置织入:告诉spring框架 哪些方法(切点)需要进行哪些增强(前置、后置...)-->
<aop:config>
<!--声明切面-->
<aop:aspect ref="myAspect">
<!--切面:切点+通知-->
<aop:before method="before" pointcut="execution(public void top.cloud.aop.Target.save())"/>
</aop:aspect>
</aop:config>
Ⅴ.测试代码
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
@Autowired
private TargetInterface target;
@Test
public void test1(){
target.save();
}
}
Ⅵ.结果
前置增强.......
Target running......
实现了,在不修改源码的基础上,对已有方法进行增强.
本文深入解析Spring AOP(面向切面编程)的概念、作用及优势,介绍其底层实现原理,包括JDK代理和Cglib代理技术。同时,提供基于XML的AOP开发示例,帮助读者理解如何在Spring框架中运用AOP进行代码增强。
1157

被折叠的 条评论
为什么被折叠?



