什么是SpringAOP?AOP底层?基于XML的AOP开发

本文深入解析Spring AOP(面向切面编程)的概念、作用及优势,介绍其底层实现原理,包括JDK代理和Cglib代理技术。同时,提供基于XML的AOP开发示例,帮助读者理解如何在Spring框架中运用AOP进行代码增强。

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. 真实角色: — 要增强的对象
  3. 代理角色: — 动态代理生成的

实现步骤

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......

实现了,在不修改源码的基础上,对已有方法进行增强.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值