spring的AOP配置之XML方式

29 篇文章 0 订阅

AOP概念

⚫ AOP(Aspect Oriented Programing)面向切面编程,一种编程范式,隶属于软工范畴,指导开发者如
何组织程序结构
⚫ AOP弥补了OOP的不足,基于OOP基础之上进行横向开发
◆ OOP规定程序开发以类为主体模型,一切围绕对象进行,完成某个任务先构建模型
◆ AOP程序开发主要关注基于OOP开发中的共性功能,一切围绕共性功能进行,完成某个任务先
构建可能遇到的所有共性功能(当所有功能都开发出来也就没有共性与非共性之分)

AOP动态代理的方式(spring的AOP默认是JDK Proxy)

<!--    配置AOP
	proxy-target-class="false"配置为false就是使用的JDK Proxy
	由源码得:
			<xsd:attribute name="proxy-target-class" type="xsd:boolean" default="false">
				<xsd:annotation>
					<xsd:documentation><![CDATA[
					是否要创建基于类(CGLIB)的代理?默认情况下,标准创建基于Java接口的代理。
	Are class-based (CGLIB) proxies to be created? By default, standard
	Java interface-based proxies are created.
					]]></xsd:documentation>
				</xsd:annotation>
			</xsd:attribute>		
-->
    <aop:config proxy-target-class="false">
    </aop:config>

JDK的动态代理,需要有实现接口
动态代理——JDK Proxy
⚫ JDKProxy动态代理是针对对象做代理,要求原始对象具有接口实现,并对接口方法进行增强
在aop动态代理的时候发现这个类是实现接口的类,就选择JDK的动态代理,从ioc中获取这个动态代理的实现类就需要按照接口.class去获取
CGLIB动态代理方式,继承方式
动态代理——CGLIB
⚫ CGLIB(Code Generation Library),Code生成类库
⚫ CGLIB动态代理不限定是否具有接口,可以对任意操作进行增强
⚫ CGLIB动态代理无需要原始被代理对象,动态创建出新的代理对象
需要将配置文件中这个设置为true才开启CGLIB方式动态代理

<aop:config proxy-target-class="true">

CGLIB动态代理方式,继承方式,就直接用这个类.class去获取
在这里插入图片描述

AOP作用

⚫ 伴随着AOP时代的降临,可以从各个行业的标准化、规范化开始入手,一步一步将所有共性功能逐一开
发完毕,最终以功能组合来完成个别业务模块乃至整体业务系统的开发
⚫ 目标:将软件开发由手工制作走向半自动化/全自动化阶段,实现“插拔式组件体系结构”搭建

AOP概念图解

在这里插入图片描述
在这里插入图片描述

AOP

⚫ Joinpoint(连接点):就是方法
⚫ Pointcut(切入点):就是挖掉共性功能的方法
⚫ Advice(通知):就是共性功能,最终以一个方法的形式呈现
⚫ Aspect(切面):就是共性功能与挖的位置的对应关系
⚫ Target(目标对象):就是挖掉功能的方法对应的类产生的对象,这种对象是无法直接完成最终工作的
⚫ Weaving(织入):就是将挖掉的功能回填的动态过程
⚫ Proxy(代理):目标对象无法直接完成工作,需要对其进行功能回填,通过创建原始对象的代理对象实现
⚫ Introduction(引入/引介) :就是对原始对象无中生有的添加成员变量或成员方法

AOP配置之XML方式

AOP开发过程

⚫ 开发阶段(开发者完成)
◆ 正常的制作程序
◆ 将非共性功能开发到对应的目标对象类中,并制作成切入点方法
◆ 将共性功能独立开发出来,制作成通知
◆ 在配置文件中,声明切入点
◆ 在配置文件中,声明切入点与通知间的关系(含通知类型),即切面
⚫ 运行阶段(AOP完成)
◆ Spring容器加载配置文件,监控所有配置的切入点方法的执行
◆ 当监控到切入点方法被运行,使用代理机制,动态创建目标对象的代理对象,根据通知类别,在代理对象的对应
位置将通知对应的功能织入,完成完整的代码逻辑并运行

XML标签

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

切入点表达式

在这里插入图片描述
在这里插入图片描述

通知类型

⚫ AOP的通知类型共5种
◆ 前置通知:原始方法执行前执行,如果通知中抛出异常,阻止原始方法运行
应用:数据校验
◆ 后置通知:原始方法执行后执行,无论原始方法中是否出现异常,都将执行通知
应用:现场清理
◆ 返回后通知:原始方法正常执行完毕并返回结果后执行,如果原始方法中抛出异常,无法执行
应用:返回值相关数据处理
◆ 抛出异常后通知:原始方法抛出异常后执行,如果原始方法没有抛出异常,无法执行
应用:对原始方法中出现的异常信息进行处理
◆ 环绕通知:在原始方法执行前后均有对应执行执行,还可以阻止原始方法的执行
应用:十分强大,可以做任何事情

通知类型XML

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

一 在pom文件中导入相关坐标

AspectJ

⚫ Aspect(切面)用于描述切入点与通知间的关系,是AOP编程中的一个概念
⚫ AspectJ是基于java语言对Aspect的实现

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.9.RELEASE</version>
        </dependency>
<!--        aop切面包-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.5</version>
        </dependency>
<!--        junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

二 将需要对切入点(方法)进行添加的功能制作成一个切面类,并存放在ioc容器中

切面类
package com.fs.aop;

import org.aspectj.lang.ProceedingJoinPoint;

/*
这个类是AOP的切面类
    里面编辑一些织入的方法
 */
public class AOPDemoAdvice {

    public void proxyAOPBefore(){
        System.out.println("给切入点(方法)添加了前置通知~~~");
    }
    public void proxyAOPAfter(){
        /*
        这个后置通知是无论代码是否出现异常,都会执行这个通知
         */
        System.out.println("给切入点(方法)添加了后置通知~~~");
    }


    public void proxyAOPBeforeReturning() {
        /*
        BeforeReturning
            表示的是代码运行成功无任何异常,会执行的通知
         */
        System.out.println("给切入点(方法)添加了代码运行成功后的后置通知~~~");
    }

    public void proxyAOPBeforeThrowing() {

        System.out.println("给切入点(方法)添加了代码运行异常后的后置通知~~~");
    }

    /*
    环绕通知
        环绕通知可以将上面的通知方法全部实现
        ProceedingJoinPoint
            这类就代表切入点,可以给这个切入点执行配置通知
     */
    public Object proxyAOPAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {

        Object proceed = null;
        try {
            //proceedingJoinPoint切入点执行前配置前置通知
            System.out.println("环绕通知的前置通知执行的代码");
            //切入点(被动态代理的方法)执行
            proceed = proceedingJoinPoint.proceed();
            //proceedingJoinPoint切入点执行成功无报错后配置前置通知
            System.out.println("环绕通知的-成功运行-后执行的代码");
        } catch (Throwable throwable) {
            //proceedingJoinPoint切入点执行前配置异常通知
            System.out.println("环绕通知的切入点执行-异常后-执行的代码");
            throwable.printStackTrace();
        } finally {
            //proceedingJoinPoint切入点执行前后通知,就是代码无论是异常,还成功运行,都会执行的增强代码
            System.out.println("环绕通知的后置通知执行的代码");
        }
        return proceed;
    }
}

目标对象(这里模拟三层架构的service,对service中的某些方法进行aop)
AopService接口
package com.fs.service;

public interface AopService {
    void findAll();
    void add();
    void findById();
    void del();
    void update();
}

AopServiceImpl实现类
package com.fs.service.impl;

import com.fs.service.AopService;

public class AopServiceImpl implements AopService {
    @Override
    public void findAll() {
        System.out.println("业务层执行了findAll~~~");
    }

    @Override
    public void add() {
        System.out.println("业务层执行了add~~~");

    }

    @Override
    public void findById() {
        System.out.println("业务层执行了findById~~~");
        //制造异常来是异常通知生效
//        int i = 1/0;
    }

    @Override
    public void del() {
        System.out.println("业务层执行了del~~~");

    }

    @Override
    public void update() {
        System.out.println("业务层执行了update~~~");

    }
}

编写applicationContext.xml配置文件

<?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: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/aop https://www.springframework.org/schema/aop/spring-aop.xsd">

<!--    将业务层实现类存放在ioc容器中,因为需要对某个类中的方法进行aop需要这个类也在ioc容器中-->
    <bean id="aopService" class="com.fs.service.impl.AopServiceImpl"/>
<!--    将切面类也交给ioc管理-->
    <bean id="aopDemoAdvice" class="com.fs.aop.AOPDemoAdvice"/>

    <aop:config>
<!--        配置切入点(方法),那些方法需要增强
            execution(* com.fs.service.impl.*.find*(..))
            任意修饰符,任意返回值 com.fs.service.impl包下的任意类的find开头的方法(任意参数)-->
        <aop:pointcut id="pt" expression="execution(* com.fs.service.impl.*.find*(..))"/>
<!--        配置切面类(切入点与通知的关系指定),里面有增强的代码(共性代码)-->
        <aop:aspect ref="aopDemoAdvice">
<!--          给切入点(方法)执行的时候配置通知
              通俗点讲就是给上面配置的切入点(方法)动态的对方法进行增强,并且创建一个动态代理对象存放
              在ioc的容器中-->

<!--            配置前置通知-->
<!--            <aop:before method="proxyAOPBefore" pointcut-ref="pt"/>-->
<!--            配置后置通知-->
<!--            <aop:before method="proxyAOPAfter" pointcut-ref="pt"/>-->
<!--            配置运行成功通知-->
<!--            <aop:after-returning method="proxyAOPBeforeReturning" pointcut-ref="pt"/>-->
<!--            配置运行异常通知-->
<!--            <aop:after-throwing method="proxyAOPBeforeThrowing" pointcut-ref="pt"/>-->


<!--            配置环绕通知(可以实现上面的任意通知方式)-->
            <aop:around method="proxyAOPAround" pointcut-ref="pt"/>
        </aop:aspect>
    </aop:config>
</beans>

测试代码

    @Test
    public void method02() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationAop.xml");

        /*
        JDK的动态代理,需要有实现接口
        在aop动态代理的时候发现这个类是实现接口的类,就选择JDK的动态代理
		若aop动态代的时候发现这个类是普通类,就选择CGLIB动态代理方式,继承方式,就不会

        因为当前业务实现类被aop动态代理增强方法后生成了一个类,这个类的不是AopServiceImpl
            所以在ioc中获取使用AopServiceImpl.class是拿不到的,只能通过AopService接口去ioc中找
            因为aop动态代理生成的实现类还是实现了AopService,所以可以通过接口类型去ioc中找到
            这个aop动态代理的实现类
         */
//        AopServiceImpl aopService = applicationContext.getBean(AopServiceImpl.class);
        AopService aopService = applicationContext.getBean(AopService.class);
//        aopService.findAll();
        aopService.findById();
    }

测试效果

findById()方法正常运行

在这里插入图片描述

若在findById()方法中制作一个异常
    @Override
    public void findById() {
        System.out.println("业务层执行了findById~~~");
        //制造异常来是异常通知生效
        int i = 1/0;
    }

在这里插入图片描述

图解Aop

在这里插入图片描述

通知获取参数数据(了解)

若有多个参数,JoinPoint一定要在第一个参数的位子
在这里插入图片描述

通知获取返回值数据

在这里插入图片描述

通知获取异常数据

在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值