复习Spring第三课SpringAop

Aop
不修改代码得前提下,增加方法

一,为什么要用aop?

(1)代码混乱:越来越多得非业务需求(日志和验证等)加入后,原有得业务方法急剧膨胀,每个方法在处理核心逻辑得同时还必须兼顾其他多个关注点。
(2)代码冗余:以日志需求为例,直为了满足这个单易需求,就不得不在多个模块(方法)里重复相同得日志代码,如果日志需求发生变化,必须修改所有的模块。

二,Aop简介

(1)Aop(Aspect-Oriented Programming)面向切面编程:是一种新的方法论,是对传统OOP(Object-Oriented Programming,面向对象编辑)的补充。
(2)AOP的主要编程对象是切面(aspect),而且切面模块化横切关注点(横切关注点即具体需求)。
(3)在应用AOP编程时,仍需要定义公共功能。但可以明确的定义功能在哪里,以什么方式和应用,并且不必修改受影响的类。这样一来横切关注点就被模块化导特殊的对象(切面)里。
(4)AOP的好处:
每个事物逻辑位于一个位置,代码不分散,便于维护和升级业务模块更简洁,只包含核心业务代码。

三,图解AOP

在这里插入图片描述

四,Aop重要术语

(1)通知:切面必须要完成得工作,切面中得每一个方法都有被称为一个通知
                     前置通知@Befter
                     后置通知@After
                     返回通知@AfterRunning
                     异常通知@AfterThrowing
                     环绕通知@Around
(2)目标:被通知得对象,即原有的最基本得功能
(3)代理:切面+目标得整体
(4)连接点:程序执行得某个特定位置,由方法加方位构成,例如:add方法,执行之前
(5)切点:每个类都拥有多个连接点,Aop通过切点啊定位到特定得连接带你,切点和连接点不是一对一得关系,一个切点匹配多个连接点

五,Aop写法

1,配置文件


```java
<!--    配置aop自动代理处理方式 -->
    <aop:aspectj-autoproxy/>
<!--    给我们自定义的aop切面类创建出相应的bean,交给spring管理-->
    <bean id="aopAspect" class ="com.haina.spring.aop.AopAspect"/>
<!--    用来配置我们要给那个类的哪写方法增加aop切面-->
    <aop:config>
<!--        使用表达式来匹配我么需要增加切面方法,pointcut是一个切点,通用改切点使用得表达式可以找到匹配得方法-->
<!--                                                    给公共得方法增加-->
        <aop:pointcut id="cal" expression="execution(public* com.haina.spring.aop.CalculatorImpl.*(..))"/>
        <aop:aspect ref="aopAspect">
<!--            通过cal这个切点找到得方法,在执行前需要调用aopAspect对象中得before方法-->
<!--           pointcut-ref属性用来配置 需要使用得切点得bean method属性用来配置需要调用切面得那个方法-->
<!--            动态代理模式-->
            <aop:before method="before" pointcut-ref="cal"/>
<!--            在方法运行之后执行after方法,即使方法出现了异常,这个逻辑仍然会执行-->
            <aop:after method="after" pointcut-ref="cal"/>
<!--            after-returing 在运行成功之后才会执行,如果出现异常则不会执行,后面得也不会执行 ,result参数-->
            <aop:after-returning method="afterRet" pointcut-ref="cal" returning="result"/>
<!--        只有在方法出现异常得时候才会,触发这个通知,后面得不会执行-->
            <aop:after-throwing method="afterException" pointcut-ref="cal"/>
<!--            可以在方法执行前执行后分别加上-->
            <aop:around method="round" pointcut-ref="cal"/>
        </aop:aspect>
    </aop:config>

AopAspect 类

//aop类
public class AopAspect {
//    JoinPoint P一定要大写,p小写是另一个类
    public void before(JoinPoint joinPoint){
//        获取被代理得方法名
        String name = joinPoint.getSignature().getName();
//        用来获取被代理得方法参数值列表
        Object[] params = joinPoint.getArgs();

        for(Object o :params){
            Integer i = (Integer) o;
            if(i<0){
                throw new RuntimeException(name+"方法得参数不允许负数");
            }
        }
        System.out.println(name +"方法执行");
    }
    public void after(JoinPoint joinPoint){
        //        获取被代理得方法名
        String name = joinPoint.getSignature().getName();
        System.out.println(name+"方法执行完成!!!");
    }
    public void afterRet(JoinPoint joinPoint,int result){
//        获取被代理得方法名
        String name = joinPoint.getSignature().getName();

        System.out.println(name+"方法执行成功"+",方法执行结果:"+result);
    }
    public void afterException(JoinPoint joinPoint){
//        获取被代理得方法名
        String name = joinPoint.getSignature().getName();

        System.out.println(name+"方法抛出了异常");
    }

//    环绕通知,需要手动调用,环绕通知得方法根据被代理得方法来决定要不要加返回值
//    如果被代理得方法有返回值,则方法发必须也要加返回值
    public Object round(ProceedingJoinPoint proceedingJoinPoint)throws Throwable{
        System.out.println("环绕通知");
//调用被代理得方法
        Object result = proceedingJoinPoint.proceed();

        System.out.println("环绕通知结束,运行结果:"+result);
        return result;
    }
}


@Component //
public class CalculatorImpl implements Calculator {
    public int add(int a, int b) {
        return a+b;
    }
    public int sub(int a, int b) {
        return a-b;
    }
    public int mul(int a, int b) {
        return a*b;
    }
    public int div(int a, int b) {
        return a/b;
    }
}
public class AopTest {
    public static void main(String[] args) {
        //        创建spring全局对象,加载配置文件,用来初始化spring容器
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//       通过接口类型也可以获取到他实现类得对象
//        如果改接口有多个实现类,则不能这样写
        Calculator c = ctx.getBean(Calculator.class);

        int result = c.add(3,8);
        System.out.println(result);
        c.div(2,1);
        c.mul(3,5);
        c.sub(6,4);
    }
}

2,注解写法

//用注解写aop
@Aspect
@Component
public class AopAspect1 {

    @Pointcut("execution(public* com.haina.spring.aop.CalculatorImpl.*(..))")
    public void pointCut(){

    }

//    @Before("execution(public* com.haina.spring.aop.CalculatorImpl.*(..))")
//    这里可以符用表达式,注解里面得内容时带有@Pointcut注解得方法得方法名
    @Before("pointCut()")
    public void before(JoinPoint joinPoint){
        String name = joinPoint.getSignature().getName();
        System.out.println(name+"方法被执行------");
    }

//    @After("execution(public* com.haina.spring.aop.CalculatorImpl.*(..))")
    @After("pointCut()")
    public void after(JoinPoint joinPoint){
        String name = joinPoint.getSignature().getName();
        System.out.println(name+"方法执行完成------");
    }
}

六,执行顺序

1,不抛出异常时的顺序
在这里插入图片描述

2,抛出异常时的顺序
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值