Spring的AOP

AOP:面向切面编程,通过预编译的方式和运行期间动态代理实现程序功能的统一维护的一种技术

注意添加依赖(aspectjweaver)

测试程序结构:

  1. 使用Spring的原生API接口实现
public interface UserService {
    void add();
    void delete();
    void update();
    void query();
}
``````java
package service;

/**
 * @Author: nsk
 * @Description:
 * @Date: create in 2021/4/12 19:45
 */

public class UserServiceImpl implements UserService{

    public void add() {
        System.out.println("add方法");
    }

    public void delete() {
        System.out.println("delete方法");
    }

    public void update() {
        System.out.println("update方法");
    }

    public void query() {
        System.out.println("query方法");
    }
}
``````java
package log;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

/**
 * @Author: nsk
 * @Description:
 * @Date: create in 2021/4/12 19:47
 */

public class Log implements MethodBeforeAdvice {
    //method:要执行的目标对象的方法
    //args :参数
    //o :target 目标对象
    public void before(Method method, Object\[\] objects, Object o) throws Throwable {
        System.out.println(o.getClass().getName()+"的"+method.getName()+"被执行了");
    }
}
``````java
package log;

import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

/**
 * @Author: nsk
 * @Description:
 * @Date: create in 2021/4/12 19:51
 */

public class AfterLog  implements AfterReturningAdvice {
    public void afterReturning(Object o, Method method, Object\[\] objects, Object o1) throws Throwable {
        System.out.println("执行了"+method.getName()+"方法,返回对象是"+o);
    }
}

applicationContext.xml:(注意导入标签和dtd约束)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       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 id="userService" class="service.UserServiceImpl"/>
        <bean id="log" class="log.Log"/>
        <bean id="afterLog" class="log.AfterLog"/>
        <!--方式一:使用原生的AIP接口-->
        <!--配置AOP:需要导入dtd约束-->
        <aop:config>
               <!--配置切入点 expression:表达式execution(要执行的位置: 返回值类型 类名.方法名.参数() )-->
                <aop:pointcut id="us" expression="execution(* service.UserServiceImpl.*(..))"/>
                <!--执行环绕增加-->
                <aop:advisor advice-ref="log" pointcut-ref="us"/>
                <aop:advisor advice-ref="afterLog" pointcut-ref="us"/>
        </aop:config>
        
</beans>
``````java
    @Test
    public void test(){
        ApplicationContext cpx = new ClassPathXmlApplicationContext("applicationContext.xml");
         //动态代理,代理的是接口,返回的是接口类
        UserService userService = cpx.getBean("userService", UserService.class);
        userService.add();
    }
}
  1. 通过自定义的实现AOP
package diypointcut;

/**
 * @Author: nsk
 * @Description:
 * @Date: create in 2021/4/12 20:21
 */

public class DiyPointCut {
    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:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       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 id="userService" class="service.UserServiceImpl"/>
        <bean id="log" class="log.Log"/>
        <bean id="afterLog" class="log.AfterLog"/> 
        <!--方式二:使用切面自定义切点-->
        <bean id="diy" class="diypointcut.DiyPointCut"/>
        <aop:config>
            <!--定义切面ref是引用的类-->
            <aop:aspect ref="diy">
            <!--切入点-->
                <!--配置切入点 expression:表达式execution(要执行的位置: 返回值类型 类名.方法名.参数() )-->
                <aop:pointcut id="us" expression="execution(* service.UserServiceImpl.*(..))"/>
                <!--通知-->
                <aop:before method="before" pointcut-ref="us"/>
                <aop:after method="after" pointcut-ref="us"/>
            </aop:aspect>
        </aop:config>
</beans>

测试方法:

@Test
public void test(){
    ApplicationContext cpx = new ClassPathXmlApplicationContext("applicationContext.xml");
     //动态代理,代理的是接口,返回的是接口类
    UserService userService = cpx.getBean("userService", UserService.class);
    userService.add();
}

3、通过注解方式

  1. 注册切入点的bean,开启使用注解方

  2. 编写切入点的类,并且使用注解

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       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 id="userService" class="service.UserServiceImpl"/>
        <bean id="log" class="log.Log"/>
        <bean id="afterLog" class="log.AfterLog"/>
    <!--注解的方式定义切面-->
    <bean id="annotationAspect" class="annotation.AnnotationAspect"/>
    <!--开启注解支持-->
    <aop:aspectj-autoproxy/>
</beans>

切面类:

package annotation;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

/**
 * @Author: nsk
 * @Description:
 * @Date: create in 2021/4/13 19:58
 */
@Aspect
public class AnnotationAspect {
    @Before("execution(* service.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("======方法执行前======");
    }
    @After("execution(* service.UserServiceImpl.*(..))")
    public void after(){
        System.out.println("======方法执行后======");
    }

    @Around("execution(* service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("=====环绕前======");
        //执行切入点的程序
        Object proceed = jp.proceed();
        //打印执行的方法
        System.out.println("签名"+jp.getSignature());
        System.out.println("=====环绕后======");
    }
}

测试:同时使用方式二和方式三