1、什么是AOP
全称是 Aspect Oriented Programming 即:面向切面编程。是OOP(面向对象编程)的延续,也是Spring框架中的一个重要内容,是函数式编程的一种衍生泛型。简单的说他就是把我们程序重复的代码抽取出来,在需要执行的时候使用动态代理技术在不修改源码的基础上,对我们的已有方法进行增强。
AOC在Spring中的作用


2、使用Spring实现AOP
方式一:使用Spring的API接口来做
1、导入AOP支持
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.19</version>
    <scope>runtime</scope>
</dependency>
2、创建测试类
抽象类:
package com.li.service;
public interface UserService {
    public void add();
    public void delete();
    public void update();
    public void select();
}
抽象类实现:
package com.li.service;
public class UserServiceImp implements UserService{
    @Override
    public void add() {
        System.out.println("增加");
    }
    @Override
    public void delete() {
        System.out.println("删除");
    }
    @Override
    public void update() {
        System.out.println("修改");
    }
    @Override
    public void select() {
        System.out.println("查询");
    }
}
3、创建切面类,编写切面方法
方法一:实现MethodBeforeAdvice 在切入点之前切入方法
package com.li.log;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class Log implements MethodBeforeAdvice {
    //实现MethodBeforeAdvice会在方法执行前运行
    //method: 要执行的目标对象的方法
    //args:参数
    //target:目标对象
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName()+"的"+method.getName()+"方法被执行了,"+"参数是:"+args.getClass().getName());
    }
}
方法二:实现 AfterReturningAdvice 在切入点后加入切面方法
package com.li.log;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class AfterLog implements AfterReturningAdvice {
    //实现AfterReturningAdvice会在方法执行后执行
    //method: 要执行的目标对象的方法
    //args:参数
    //target:目标对象
    //返回值:returnValue
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName()+"执行了:"+method.getName()+"方法,方法参数是:"+args.getClass().toString()+"返回值是:"+returnValue);
    }
}
4、创建配置文件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
		https://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 id="UserService" class="com.li.service.UserServiceImp"/>
    <bean id="log" class="com.li.log.Log"/>
    <bean id="AfterLog" class="com.li.log.AfterLog"/>
    <!--使用原生Spring api接口-->
    <!--配置aop: 需要先导入aop的约束 xmlns:aop="http://www.springframework.org/schema/aop"    http://www.springframework.org/schema/aop
		https://www.springframework.org/schema/aop/spring-aop.xsd"-->
    <aop:config>
    <!--需要一个切入点就是我们需要在什么地方去执行我们的Spring的方法-->
    <!--id后面接你想给切入点取的名字 expression需要接表达式,表达式是死的:execution(* 要执行的位置.*(..))    这里的.*表示位置下的所有方法 (..)表示可以有任意的参数-->
        <aop:pointcut id="poi" expression="execution(* com.li.service.UserServiceImp.*(..))"/>
    <!--执行环绕增强-->
        <aop:advisor advice-ref="log" pointcut-ref="poi"/>
        <aop:advisor advice-ref="AfterLog" pointcut-ref="poi"/>
    </aop:config>
</beans>5、测试类测试
package com.li.log;
import com.li.service.UserService;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestGo {
    @Test
    public void test1(){
        //通过配置文件获取ClassPath
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //根据抽象类获取Bean
        UserService user = context.getBean("UserService", UserService.class);
        //调用方法测试
        user.add();
    }
}
测试结果

方式二:使用自定义类来实现Aop
创建自定义类和方法
package com.li.diy;
public class Diy {
    public void before(){
        System.out.println("====切面之前执行====");
    }
    public void after(){
        System.out.println("====切面之后执行====");
    }
}
配置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
		https://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 id="UserService" class="com.li.service.UserServiceImp"/>
    <!--方式二: 通过自定义方法来Aop-->
    <!--注册Bean-->
    <bean id="diy" class="com.li.diy.Diy"/>
    <!--配置aop: 需要先导入aop的约束 xmlns:aop="http://www.springframework.org/schema/aop"    http://www.springframework.org/schema/aop
       https://www.springframework.org/schema/aop/spring-aop.xsd"-->
    <aop:config>
    <!--自定义切面,ref:接需要引用类的bean id-->
        <aop:aspect ref="diy">
            <!--id后面接你想给切入点取的名字 expression需要接表达式,表达式是死的:execution(* 要执行的位置.*(..))    这里的.*表示位置下的所有方法 (..)表示可以有任意的参数-->
            <aop:pointcut id="point" expression="execution(* com.li.service.UserServiceImp.*(..))"/>
            <!--通知 method后接前面类中自定义的方法名 pointcut-ref后接切入点的id -->
            <aop:before method="before" pointcut-ref="point"/>
            <aop:after method="after" pointcut-ref="point"/>
        </aop:aspect>
    </aop:config>
</beans>创建测试类
package com.li.log;
import com.li.service.UserService;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestGo {
    @Test
    public void test1(){
        //通过配置文件获取ClassPath
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //根据抽象类获取Bean
        UserService user = context.getBean("UserService", UserService.class);
        //调用方法测试
        user.add();
    }
}
测试结果




















