欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

复习Spring第三课SpringAop

程序员文章站 2024-03-14 10:13:52
...

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

一,为什么要用aop?

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

二,Aop简介

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

三,图解AOP

复习Spring第三课SpringAop

四,Aop重要术语

(1)通知:切面必须要完成得工作,切面中得每一个方法都有被称为一个通知
前置通知@Befter
后置通知@After
返回通知@AfterRunning
异常通知@AfterThrowing
环绕通知@Around
(2)目标:bei通知得对象,即院有得最基本得功能
(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,不抛出异常时的顺序
复习Spring第三课SpringAop

2,抛出异常时的顺序
复习Spring第三课SpringAop

相关标签: Spring spring