Spring-AOP

发布于:2024-04-27 ⋅ 阅读:(22) ⋅ 点赞:(0)

1.基本介绍

1.什么是AOP?

image-20240220103241229

2.示意图

image-20240220105205993

image-20240220105239393

3.五种通知

image-20240220110125266

image-20240220110136565

2.AOP快速入门

1.入门案例
1.导入jar包

image-20240220110639212

2.Cal.java 接口
package com.sxs.spring.aop.aspectj;

/**
 * 计算数量的接口
 *
 * @author 孙显圣
 * @version 1.0
 */
public interface Cal {
    public double getSub(double num1, double num2);
    public double getSum(double num1, double num2);
}

3.CalImpl.java 实现类
package com.sxs.spring.aop.aspectj;

import org.springframework.stereotype.Component;

/**
 * @author 孙显圣
 * @version 1.0
 */

@Component //注解创建bean对象
public class CalImpl implements Cal {
    @Override
    public double getSub(double num1, double num2) {
        System.out.println("方法内部打印:" + (num1 - num2));
        return num1 - num2;
    }

    @Override
    public double getSum(double num1, double num2) {
        System.out.println("方法内部打印:" + (num1 + num2));
        return num1 + num2;
    }
}

4.CalAspect.java 切面类
package com.sxs.spring.aop.aspectj;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * 切面类
 *
 * @author 孙显圣
 * @version 1.0
 */
@Component //自动创建bean对象
@Aspect //切面类
public class CalAspect {
    /**
     * @param joinPoint 保存了要切入的方法的信息
     * @Before 前置通知
     * execution(。。。) 切入表达式,表明要切入的方法,格式:格式:访问修饰符+返回类型 全类名 方法名(参数类型)
     */
    @Before(value = "execution(public double com.sxs.spring.aop.aspectj.CalImpl.getSub(double, double))")
    public void before(JoinPoint joinPoint) {
        //获取方法签名
        Signature signature = joinPoint.getSignature();
        System.out.println("方法执行开始-日志-方法名-" + signature.getName()
                + "-参数" + Arrays.asList(joinPoint.getArgs()));
    }

    /**
     * @param joinPoint 保存了要切入的方法的信息
     * @AfterReturning 返回通知
     */
    @AfterReturning(value = "execution(public double com.sxs.spring.aop.aspectj.CalImpl.getSub(double, double))")
    public void afterReturning(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        System.out.println("方法执行正常结束-日志-方法名-" + signature.getName()
        );
    }

    /**
     * @param joinPoint
     * @AfterThrowing 异常通知
     */
    @AfterThrowing(value = "execution(public double com.sxs.spring.aop.aspectj.CalImpl.getSub(double, double))")
    public void throwing(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        System.out.println("方法出现异常-日志-方法名-" + signature.getName()
        );
    }

    /**
     * @param joinPoint
     * @After 后置通知
     */
    @After(value = "execution(public double com.sxs.spring.aop.aspectj.CalImpl.getSub(double, double))")
    public void after(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        System.out.println("方法最终执行完毕-日志-方法名-" + signature.getName()
        );
    }
}

5.beans06.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:context="http://www.springframework.org/schema/context"
       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/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--扫描普通注解-->
    <context:component-scan base-package="com.sxs.spring.aop.aspectj"/>
<!--开启基于aop的注解功能-->
    <aop:aspectj-autoproxy/>
</beans>
6.测试
package com.sxs.spring.aop.aspectj;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author 孙显圣
 * @version 1.0
 */
public class AopAspectjTest {
    public static void main(String[] args) {
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans06.xml");
        //注意:这里需要使用接口类型来获取代理对象,然后使用代理对象来执行方法,才能实现切面编程
        Cal bean = ioc.getBean(Cal.class);
        bean.getSub(1,22);
    }
}

image-20240220144144990

2.细节说明

image-20240220145619074

3.AOP理解(重点)
1.使用场景

需要对接口对象/普通对象的方法进行额外的操作而不想修改源代码时使用

2.代理对象理解

从接口类型或者接口对象id获取的bean对象的运行类型都是代理对象,编译类型是接口类型,最终执行方法的对象是代理对象

一个代理对象对应一个接口对象,在只有一个接口对象的时候才能使用类型来获取

3.AOP的实现方式
  1. 编写接口
  2. 编写实现类,使用注解自动创建bean对象
  3. 编写切面类,使用注解
    1. 自动创建bean对象
    2. 标识切面类
    3. 通知 + 切入表达式(切点)
  4. 编写xml文件
    1. 扫描普通注解
    2. 开启aop注解功能
  5. 使用方式
    1. 使用id或者类型获取针对接口的代理对象
    2. 使用代理对象执行方法
4.简化的AOP实现方式
  1. 接口,接口对象(注解)
  2. 切面(注解),切面对象(注解)
  3. 通知 + 切点
  4. 使用方式
    1. 使用id或者类型获取针对接口的代理对象
    2. 使用代理对象执行方法
4.课后练习
1.题目

image-20240220150422379

2.答案
1.UsbInterface.java
package com.sxs.spring.aop.homework01;

/**
 * @author 孙显圣
 * @version 1.0
 */
public interface UsbInterface {
    public void work();
}

2.Camera.java
package com.sxs.spring.aop.homework01;

import org.springframework.stereotype.Component;

/**
 * @author 孙显圣
 * @version 1.0
 */
@Component
public class Camera implements UsbInterface{
    @Override
    public void work() {
        System.out.println("相机正在工作。。。。。。");
    }
}

3.Phone.java
package com.sxs.spring.aop.homework01;

import org.springframework.stereotype.Component;

/**
 * @author 孙显圣
 * @version 1.0
 */
@Component
public class Phone implements UsbInterface{
    @Override
    public void work() {
        System.out.println("手机正在工作。。。。。。");
    }
}

4.Aspect.java
package com.sxs.spring.aop.homework01;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

/**
 * @author 孙显圣
 * @version 1.0
 */
@Component
@org.aspectj.lang.annotation.Aspect
public class Aspect {
    @Before(value = "execution(* com.sxs.spring.aop.homework01.*.*(..))")
    public void before(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        System.out.println("日志-方法执行前-方法名-" + signature.getName());
    }
}

5.beans06.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:context="http://www.springframework.org/schema/context"
       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/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--扫描普通注解-->
    <context:component-scan base-package="com.sxs.spring.aop.homework01"/>
<!--开启基于aop的注解功能-->
    <aop:aspectj-autoproxy/>
</beans>
6.测试
package com.sxs.spring.aop.homework01;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author 孙显圣
 * @version 1.0
 */
public class test {
    public static void main(String[] args) {
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans06.xml");
        //通过id获取代理对象
        UsbInterface bean1 = (UsbInterface) ioc.getBean("camera");
        //执行方法
        bean1.work();
        //通过id获取代理对象
        UsbInterface bean2 = (UsbInterface) ioc.getBean("phone");
        //执行方法
        bean2.work();
    }
}

image-20240220154136556

3.切入表达式

1.基本介绍

image-20240220154944257

2.举例说明

image-20240220155134259

image-20240220155150216

3.注意事项和细节(重点)
1.切入表达式格式
*(访问修饰符(空格)返回类型)(空格)*(全类名/接口名/简单类名/简单接口名).*(方法名)(..)(参数类型)
简称: 星 星点星(点点)    
注意:
  • 访问修饰符和返回类型可以使用单个*****来表示任意的,必须满足中间有空格,比如 public * …
  • 使用简单类名/简单接口名则必须与切面类在同一个包下
  • 如果配置了接口类型,则包括接口对象的所有方法
2.细节

image-20240220161248432

3.Proxy和CGlib的区别
  • Proxy是针对接口的代理对象,可以执行接口的所有方法
  • CGlib是针对父类的代理对象,可以执行该类的所有法

4.JoinPoint常用方法

1.基本介绍

image-20240220162304414

2.代码实例(使用普通对象)
1.Car.java
package com.sxs.spring.aop.joinpoint;

import org.springframework.stereotype.Component;

/**
 * @author 孙显圣
 * @version 1.0
 */
@Component
public class Car {
    public void run() {
        System.out.println("Car在运行!");
    }
}

2.Aspect02.java
package com.sxs.spring.aop.joinpoint;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.springframework.stereotype.Component;

/**
 * @author 孙显圣
 * @version 1.0
 */
@Component
@org.aspectj.lang.annotation.Aspect
public class Aspect02 {
    //返回通知
    @AfterReturning(value = "execution(* Car.run())")
    public void afterReturning(JoinPoint joinPoint) {
        System.out.println("方法执行完毕!");
        Signature signature = joinPoint.getSignature();
        System.out.println("name=" + signature.getName());
        System.out.println("simpleName=" + signature.getDeclaringType().getSimpleName());
        System.out.println("该方法所属类的类名=" + signature.getDeclaringTypeName());
        System.out.println("参数=" + joinPoint.getArgs());
    }
}

3.beans06.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:context="http://www.springframework.org/schema/context"
       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/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--扫描普通注解-->
    <context:component-scan base-package="com.sxs.spring.aop.joinpoint"/>
<!--开启基于aop的注解功能-->
    <aop:aspectj-autoproxy/>
</beans>
4.test.java
package com.sxs.spring.aop.joinpoint;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author 孙显圣
 * @version 1.0
 */
public class test {
    public static void main(String[] args) {
        //获取针对父类的代理对象
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans06.xml");
        Car bean = ioc.getBean(Car.class);
        bean.run();
    }
}

5.返回通知获取结果

代码实例
修改Aspect02.java
package com.sxs.spring.aop.joinpoint;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.springframework.stereotype.Component;

/**
 * @author 孙显圣
 * @version 1.0
 */
@Component
@org.aspectj.lang.annotation.Aspect
public class Aspect02 {
    /**
     * 返回通知获取结果
     *
     * @param joinPoint
     * @param res 参数名必须与returning的一致
     */
    @AfterReturning(value = "execution(* Car.run())", returning = "res")
    public void afterReturning(JoinPoint joinPoint, Object res) {
        System.out.println("返回结果为=" + res);
    }
}

image-20240220170459897

6.异常通知获取异常

代码实例
1.修改Car.java

image-20240220172325445

2.修改Aspect02.java
    /**
     * 异常通知获取异常
     *
     * @param joinPoint
     * @param throwable 参数名必须与throwing一致
     */
    @AfterThrowing(value = "execution(* Car.run())", throwing = "throwable")
    public void afterThrowing(JoinPoint joinPoint, Throwable throwable) {
        System.out.println("异常通知获取异常:" + throwable);
    }

image-20240220172407848

7.环绕通知

代码实例
1.Dog.java
package com.sxs.spring.aop.doArround;


import org.springframework.stereotype.Component;

/**
 * @author 孙显圣
 * @version 1.0
 */
@Component
public class Dog {
    public String sayHi(String name) {
        System.out.println(name + "wang,wang!");
        return name + "wang,wang!";
    }
}

2.Aspect03.java
package com.sxs.spring.aop.doArround;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;

/**
 * 环绕通知
 *
 * @author 孙显圣
 * @version 1.0
 */
@Component
@Aspect
public class Aspect03 {
    /**
     * @param joinPoint 连接点对象
     * @return 返回结果
     */
    @Around(value = "execution(public String sayHi(String))")
    public Object doArround(ProceedingJoinPoint joinPoint) {
        Object result = null;
        String methodName = joinPoint.getSignature().getName();
        try {
            Object[] args = joinPoint.getArgs();
            List<Object> list = Arrays.asList(args);
            //1.前置通知
            System.out.println("AOP环绕通知-前置通知-方法名=" + methodName + "-参数-" + list);
            //执行方法
            result = joinPoint.proceed();
            //2.返回通知
            System.out.println("AOP环绕通知-返回通知-方法名=" + methodName + "-结果为=" + result);
        } catch (Throwable e) {
            //3.异常通知
            System.out.println("AOP环绕通知-异常通知-方法名=" + methodName + "-异常=" + e);
        } finally {
            //4.后置通知
            System.out.println("AOP环绕通知-后置通知-方法名=" + methodName);
        }
        return result;
    }
}

3.beans06.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:context="http://www.springframework.org/schema/context"
       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/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--扫描普通注解-->
    <context:component-scan base-package="com.sxs.spring.aop.doArround"/>
<!--开启基于aop的注解功能-->
    <aop:aspectj-autoproxy/>
</beans>
4.Test.java
package com.sxs.spring.aop.doArround;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author 孙显圣
 * @version 1.0
 */
public class Test {
    public static void main(String[] args) {
        //读取配置文件获取容器
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans06.xml");
        //获取针对父类的代理对象
        Dog bean = ioc.getBean(Dog.class);
        //执行方法
        bean.sayHi("小白");
    }
}

image-20240220184215190

8.切入表达式重用

代码实例
1.Car.java
package com.sxs.spring.aop.joinpoint;

import org.springframework.stereotype.Component;

/**
 * @author 孙显圣
 * @version 1.0
 */
@Component
public class Car {
    public void run() {
        System.out.println("Car在运行!");
    }
}

2.Aspect02.java
package com.sxs.spring.aop.joinpoint;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * @author 孙显圣
 * @version 1.0
 */
@Component
@org.aspectj.lang.annotation.Aspect
public class Aspect02 {
    //定义切点函数,实现切入表达式重用
    @Pointcut(value = "execution(* Car.run())") //设置切入表达式
    public void pointCut() {

    }

    /**
     * 前置通知
     *
     * @param joinPoint
     */
    @Before(value = "pointCut()")
    public void before(JoinPoint joinPoint) {
        System.out.println("前置通知");
    }

    /**
     * 返回通知获取结果
     *
     * @param joinPoint
     * @param res       参数名必须与returning的一致
     */
    @AfterReturning(value = "pointCut()", returning = "res")
    public void afterReturning(JoinPoint joinPoint, Object res) {
        System.out.println("返回结果为=" + res);
    }


    /**
     * 异常通知获取异常
     *
     * @param joinPoint
     * @param throwable 参数名必须与throwing一致
     */
    @AfterThrowing(value = "pointCut()", throwing = "throwable")
    public void afterThrowing(JoinPoint joinPoint, Throwable throwable) {
        System.out.println("异常通知获取异常:" + throwable);
    }

    /**
     * 后置通知
     * @param joinPoint
     */
    @After(value = "pointCut()")
    public void after(JoinPoint joinPoint) {
        System.out.println("后置通知");
    }
}

3.beans06.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:context="http://www.springframework.org/schema/context"
       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/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--扫描普通注解-->
    <context:component-scan base-package="com.sxs.spring.aop.joinpoint"/>
<!--开启基于aop的注解功能-->
    <aop:aspectj-autoproxy/>
</beans>
4.测试
package com.sxs.spring.aop.joinpoint;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author 孙显圣
 * @version 1.0
 */
public class test {
    public static void main(String[] args) {
        //获取针对父类的代理对象
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans06.xml");
        Car bean = ioc.getBean(Car.class);
        bean.run();
    }
}

image-20240220185731772

9.AOP多切面优先级问题

image-20240220190818126

解释
  1. 多个切面同时切一个方法
  2. 可以给切面类配置Order注解,数值越小,前置通知先执行
  3. 执行完前置通知之后执行目标方法
  4. 然后按照相反的顺序执行多个切面的返回通知、异常通知、最终通知

10.根据xml配置AOP

代码实例
1.UsbInterface.java
package com.sxs.spring.aop.xml;

/**
 * @author 孙显圣
 * @version 1.0
 */
public interface UsbInterface {
    public void work();
}

2.Camera.java
package com.sxs.spring.aop.xml;


/**
 * @author 孙显圣
 * @version 1.0
 */
public class Camera implements UsbInterface {
    @Override
    public void work() {
        System.out.println("相机正在工作。。。。。。");
    }
}

3.Aspect.java
package com.sxs.spring.aop.xml;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * @author 孙显圣
 * @version 1.0
 */
public class Aspect {
    /**
     * @param joinPoint 保存了要切入的方法的信息
     * @Before 前置通知
     * execution(。。。) 切入表达式,表明要切入的方法,格式:访问修饰符+返回类型 全类名 方法名(参数类型)
     */
    public void before(JoinPoint joinPoint) {
        //获取方法签名
        Signature signature = joinPoint.getSignature();
        System.out.println("方法执行开始-日志-方法名-" + signature.getName()
                + "-参数" + Arrays.asList(joinPoint.getArgs()));
    }

    /**
     * @param joinPoint 保存了要切入的方法的信息
     * @AfterReturning 返回通知
     */
    public void afterReturning(JoinPoint joinPoint, Object res) {
        Signature signature = joinPoint.getSignature();
        System.out.println("方法执行正常结束-日志-方法名-" + signature.getName()
        );
    }

    /**
     * @param joinPoint
     * @AfterThrowing 异常通知
     */
    public void throwing(JoinPoint joinPoint, Throwable throwable) {
        Signature signature = joinPoint.getSignature();
        System.out.println("方法出现异常-日志-方法名-" + signature.getName()
        );
    }

    /**
     * @param joinPoint
     * @After 后置通知
     */
    public void after(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        System.out.println("方法最终执行完毕-日志-方法名-" + signature.getName()
        );
    }}

4.beans07.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">
    <!--创建被切入的接口对象-->
    <bean class="com.sxs.spring.aop.xml.Camera" id="camera"/>
    <!--配置切面对象-->
    <bean class="com.sxs.spring.aop.xml.Aspect" id="aspect"/>
    <!--配置AOP-->
    <aop:config>
        <!--配置切点-->
        <aop:pointcut id="poingCut" expression="execution(public void work())"/>
        <!--配置切面-->
        <aop:aspect ref="aspect" order="10">
            <!--前置通知-->
            <aop:before method="before" pointcut-ref="poingCut"/>
            <!--返回通知-->
            <aop:after-returning method="afterReturning" pointcut-ref="poingCut" returning="res"/>
            <!--异常通知-->
            <aop:after-throwing method="throwing" pointcut-ref="poingCut" throwing="throwable"/>
            <!--后置通知-->
            <aop:after method="after" pointcut-ref="poingCut"/>
        </aop:aspect>
    </aop:config>
</beans>
5.测试
package com.sxs.spring.aop.xml;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author 孙显圣
 * @version 1.0
 */
public class Test {
    public static void main(String[] args) {
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans07.xml");
        //获得针对接口的代理对象
        UsbInterface bean = ioc.getBean(UsbInterface.class);
        bean.work();
    }
}

image-20240220195346934

11.课后练习

image-20240220202013336

1.注解实现
1.Cal.java
package com.sxs.spring.aop.homework02;

/**
 * @author 孙显圣
 * @version 1.0
 */
public interface Cal {
    public void cal1(int n);
    public void cal2(int n);
}

2.CalImpl.java
package com.sxs.spring.aop.homework02;

import org.springframework.stereotype.Component;

/**
 * @author 孙显圣
 * @version 1.0
 */
@Component
public class CalImpl implements Cal{
    /**
     * 计算1到n的和
     * @param n
     */
    @Override
    public void cal1(int n) {
        int sum = 0;
        for (int i = 1; i <= n; i++) {
            sum += i;
        }
        System.out.println("1到n的和=" + sum);
    }

    /**
     * 计算1乘到n
     * @param n
     */
    @Override
    public void cal2(int n) {
        int accumulate = 1;
        for (int i = 1; i <= n; i++) {
            accumulate *= i;
        }
        System.out.println("1到n的积=" + accumulate);
    }
}

3.Aspect_ann.java
package com.sxs.spring.aop.homework02;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;


/**
 * @author 孙显圣
 * @version 1.0
 */
@Component
@Aspect
public class Aspect_ann {
    //切入表达式重用
    @Pointcut(value = "execution(* CalImpl.*(..))")
    public void pointCut() {

    }

    //前置通知
    @Before(value = "pointCut()")
    public void before(JoinPoint joinPoint) {
        //获取目前的毫秒数
        long start = System.currentTimeMillis();
        //获取函数名
        String name = joinPoint.getSignature().getName();
        System.out.println(name + "开始时间=" + start);
    }

    //返回通知
    @AfterReturning(value = "pointCut()")
    public void afterReturning(JoinPoint joinPoint) {
        //获取目前的毫秒数
        long end = System.currentTimeMillis();
        //获取函数名
        String name = joinPoint.getSignature().getName();
        System.out.println(name + "结束=" + end);
    }
}

4.beans06.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:context="http://www.springframework.org/schema/context"
       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/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--扫描普通注解-->
    <context:component-scan base-package="com.sxs.spring.aop.homework02"/>

<!--开启基于aop的注解功能-->
    <aop:aspectj-autoproxy/>
</beans>
5.测试
package com.sxs.spring.aop.homework02;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author 孙显圣
 * @version 1.0
 */
public class Test_ann {
    public static void main(String[] args) {
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans06.xml");
        Cal bean = ioc.getBean(Cal.class);
        bean.cal1(5);
        System.out.println("===========================");
        bean.cal2(5);
    }
}

image-20240220202209913

2.xml实现
1.Cal.java
package com.sxs.spring.aop.homework03;

/**
 * @author 孙显圣
 * @version 1.0
 */
public interface Cal {
    public void cal1(int n);
    public void cal2(int n);
}

2.CalImpl.java
package com.sxs.spring.aop.homework03;


/**
 * @author 孙显圣
 * @version 1.0
 */
public class CalImpl implements Cal {
    /**
     * 计算1到n的和
     * @param n
     */
    @Override
    public void cal1(int n) {
        int sum = 0;
        for (int i = 1; i <= n; i++) {
            sum += i;
        }
        System.out.println("1到n的和=" + sum);
    }

    /**
     * 计算1乘到n
     * @param n
     */
    @Override
    public void cal2(int n) {
        int accumulate = 1;
        for (int i = 1; i <= n; i++) {
            accumulate *= i;
        }
        System.out.println("1到n的积=" + accumulate);
    }
}

3.Aspect_xml.java
package com.sxs.spring.aop.homework03;

import org.aspectj.lang.JoinPoint;


/**
 * @author 孙显圣
 * @version 1.0
 */
public class Aspect_xml {

    //前置通知
    public void before(JoinPoint joinPoint) {
        //获取目前的毫秒数
        long start = System.currentTimeMillis();
        //获取函数名
        String name = joinPoint.getSignature().getName();
        System.out.println(name + "开始时间=" + start);
    }

    //返回通知
    public void afterReturning(JoinPoint joinPoint) {
        //获取目前的毫秒数
        long end = System.currentTimeMillis();
        //获取函数名
        String name = joinPoint.getSignature().getName();
        System.out.println(name + "结束=" + end);
    }
}

4.beans08.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">
    <!--反射创建实现类bean对象-->
    <bean class="com.sxs.spring.aop.homework03.CalImpl" id="calImpl"/>
    <!--反射创建切面类bean对象-->
    <bean class="com.sxs.spring.aop.homework03.Aspect_xml" id="aspect_xml"/>
    <!--配置aop-->
    <aop:config>
        <!--配置切点-->
        <aop:pointcut id="pointCut" expression="execution(* com.sxs.spring.aop.homework03.CalImpl.*(..))"/>
        <!--配置切面-->
        <aop:aspect ref="aspect_xml" id="aspect" order="10">
            <aop:before method="before" pointcut-ref="pointCut"/>
            <aop:after-returning method="afterReturning" pointcut-ref="pointCut"/>
        </aop:aspect>
    </aop:config>
</beans>
5.测试
package com.sxs.spring.aop.homework03;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author 孙显圣
 * @version 1.0
 */
public class Test_xml {
    public static void main(String[] args) {
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans08.xml");
        //获取针对接口的代理对象
        Cal proxy = ioc.getBean("calImpl", Cal.class);
        proxy.cal1(100);
        System.out.println("=========================");
        proxy.cal2(5);
    }
}

image-20240220203820676