【Spring框架学习】AOP机制 配置文件式 详解

首先是 applicationContext.xml(核心配置文件):

配置文件:

首先,我们需要在配置文件的头部,beans标签的属性中 加上aop命名空间:

xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/aop
         https://www.springframework.org/schema/aop/spring-aop.xsd"

仅加入aop命名空间后,配置文件内容如下:

<?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">
</beans>

那么,配置文件式 也存在着两种使用方式,本人在这里一一来讲解下:

方式一 —— 原生 spring API接口:

配置文件 语法:

beans标签内,增加如下子级标签导入aop约束

<aop:config>
	<!--aop配置内容-->
</aop:config>

在config标签内部,配置aop的内容:
config配置内容,总共分为三类:

配置内容 分类:

  1. 用于配置切面

在第二种使用方式中会进行讲解:

<aop:aspect/>
  1. 用于配置切入点
<aop:pointcut id="切入点id" expression="execution(表达式)"/>

现在,本人来讲解下 上述表达式的语法
表达式语法

权限名 返回值类型 类的全路径名.目标方法名(参数全路径类型1, 参数全路径类型2 ...)

那么,我们在使用的时候也可以对其进行简化:
简化:

  • 权限名可以省略
  • 返回值可以设置为 ‘*‘,表示任意返回值都能匹配上
  • 包名可以用‘.‘代替,表示其父包下的所有子包都能匹配上
  • 类名/方法名 可以设置为‘*‘,表示 其父包下的所有类/其所属类中的所有方法 都能匹配上
  • 参数可以用‘. .‘代替,表示任意个数、任意种类的参数都能被匹配上
  1. 用于为切入点配置拦截器
<aop:advisor advice-ref="横切关注点的bean id" pointcut="切入点 id" />

那么,我们该如何去定义一个拦截器呢?

定义拦截器 语法:

首先,我们需要写一个类,继承如下四个几口中的一个:

MethodBeforeAdvice接口 —— 提供前置拦截方法:

参数

  • method:
    被拦截的方法(即:切入点)
  • objects:
    执行该方法的参数
  • Object o:
    执行该方法的代理对象

AfterReturningAdvice接口 —— 提供最终拦截方法:

参数

  • returnValue:
    目标方法(即:切入点)的返回值
  • method:
    目标方法(即:切入点)
  • args:
    目标方法(即:切入点)的参数
  • target:
    执行该方法的代理对象

MethodInterceptor接口 —— 提供环绕拦截方法:

提供 public Object invoke(MethodInvocation invocation) throws Throwable 方法
参数类型MethodInvocation,主要是用于 获取 目标对象 以及 方法信息


ThrowsAdvice接口 —— 提供异常抛出拦截方法

无需要重写的方法


那么,现在本人就来展示下方式一的使用:

使用展示:

首先,本人给出一个dao层实现类:

package edu.youzg.about_aop.test.dao;

import org.springframework.stereotype.Repository;

/**
 * @Author: Youzg
 * @CreateTime: 2020-05-01 20:31
 * @Description:带你深究Java的本质!
 */
@Repository
public class UserDaoImpl implements IUserDao {

    @Override
    public void add() {
        System.out.println("dao层add方法被调用!");
    }

    @Override
    public void delete() {
        System.out.println("dao层delete方法被调用!");
    }

    @Override
    public void alter() {
        System.out.println("dao层alter方法被调用!");
    }

    @Override
    public void select() {
        System.out.println("dao层select方法被调用!");
    }

}

接下来,本人来给出一个service层的实现类:

package edu.youzg.about_aop.test.service;

/**
 * @Author: Youzg
 * @CreateTime: 2020-05-01 20:33
 * @Description:带你深究Java的本质!
 */
public interface IUserService {
    public void login();

    public void register();

    public void rename();

    public void cancellat();
}

现在,本人来给出一个通知器类:

package edu.youzg.about_aop.test.aspect;

import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Component	//将其注入IoC容器中
public class MyAspect implements MethodBeforeAdvice {	//继承Adice接口,实现其自带方法,成为一个拦截器(通知器)

    @Override
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("===== Youzg代理执行 之 前置增强 =====");
    }

}

最后,现在本人 来给出配置文件:

<?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="edu.youzg.about_aop" />
    
    <aop:config>
        <!-- 定义拦截器 -->
        <aop:advisor advice-ref="myAspect" pointcut="execution(* edu.youzg.about_aop..*.*(..))" />
    </aop:config>

</beans>

最后,本人再来给出一个测试类

package edu.youzg.about_aop.test;

import edu.youzg.about_aop.test.service.IUserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @Author: Youzg
 * @CreateTime: 2020-05-01 23:11
 * @Description:带你深究Java的本质!
 */
public class Test {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        IUserService userService = context.getBean("userServiceImpl", IUserService.class);
        userService.login();
    }
    
}

那么,现在本人来展示下运行结果:
【Spring框架学习】AOP机制 配置文件式 详解


方式二 —— 自定义类实现AOP机制:

方式二的通知有五个类型:

分类:

  • 前置通知
  • 后置通知
  • 最终通知
  • 环绕通知
  • 异常通知

格式:

首先得配置一个自定义拦截器类:

接下来是配置文件:

配置文件:

<aop:config>
    <aop:aspect  id="切面bean id" ref="切面">
        <!--切入点-->
        <aop:pointcut id="自定义拦截器 bean id" expression="execution(表达式)"/>
        <!--五种通知类型-->
        <!--前置通知-->
        <aop:before method="前置拦截方法名"  pointcut-ref="切入点id"  />
        <!--最终通知-->
        <aop:after-returning method="最终拦截方法名" pointcut-ref="切入点id" />
        <!--后置通知-->
        <aop:after method="后置拦截方法名" pointcut-ref="切入点id" />
        <!--环绕通知-->
        <aop:around method="环绕拦截方法名" pointcut-ref="切入点id" />
        <!--异常通知-->
        <aop:after-throwing method="异常拦截方法名" pointcut-ref="切入点id" />
    </aop:aspect>
</aop:config>

为了方便,在上文中,本人将所有通知方式都在一起展示了
那么,我们在使用的时候,只需要针对需求选取其中几种就行


那么,现在本人来展示下方式二的使用:

使用展示:

首先,本人来给出一个自定义拦截器类:

package edu.youzg.about_aop.test.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.stereotype.Component;

/**
 * @Author: Youzg
 * @CreateTime: 2020-05-01 21:56
 * @Description:带你深究Java的本质!
 */
@Component
public class YouzgAspect {

    public void myBefore() {
        System.out.println("==before拦截执行==");
    }

    public void myAfter() {
        System.out.println("==after拦截执行==");
    }

    public void myAfterReturning() {
        System.out.println("==afterReturning拦截执行==");
    }

    public void myThrowing() {
        System.out.println("==throwing拦截执行==");
    }

    public Object myAround(ProceedingJoinPoint pjp) {
        Object result = null;
        try {
            System.out.println("== around拦截执行 ==");
            result = pjp.proceed();
            // 方法执行完毕之后编写
            System.out.println("== around拦截完毕 ==");
            System.out.println("==方法执行的结果[" + result + "]==");
        }catch(Throwable t){
        // 可以处理,异常通知
            System.out.println("异常处理");
        }
        return result;
    }

}

现在,本人来给出配置文件的信息:

<?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="edu.youzg.about_aop" />

    <aop:config>
        <aop:aspect id="youzgAsp" ref="youzgAspect">
            <!--切入点-->
            <aop:pointcut id="youzgPoingcut" expression="execution(* edu.youzg.about_aop..*.*(..))"/>
            <!--五种通知类型-->
            <!--前置通知-->
            <aop:before method="myBefore" pointcut-ref="youzgPoingcut" />
            <!--后置通知-->
            <aop:after-returning method="myAfterReturning" pointcut-ref="youzgPoingcut" />
            <!--最终通知-->
            <aop:after method="myAfter" pointcut-ref="youzgPoingcut" />
            <!--环绕通知-->
            <aop:around method="myAround" pointcut-ref="youzgPoingcut" />
            <!--异常通知-->
            <aop:after-throwing method="myThrowing" pointcut-ref="youzgPoingcut" />
        </aop:aspect>
    </aop:config>

</beans>

最后,本人再来给出一个测试类

package edu.youzg.about_aop.test;

import edu.youzg.about_aop.test.service.IUserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @Author: Youzg
 * @CreateTime: 2020-05-01 23:11
 * @Description:带你深究Java的本质!
 */
public class Test {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        IUserService userService = context.getBean("userServiceImpl", IUserService.class);
        userService.login();
    }
    
}

那么,现在本人来展示下运行结果:【Spring框架学习】AOP机制 配置文件式 详解