Spring AOP -- 重点

二、AOP重点

这部分看不懂,可以先看下面的细节部分。

1、AOP简单配置

1.1、AOP使用步骤

1.1.1、导包(创建一个lib文件,用于存放jar包)

spring-aop-4.0.0.RELEASE.jar
spring-beans-4.0.0.RELEASE.jar
spring-context-4.0.0.RELEASE.jar
spring-core-4.0.0.RELEASE.jar
spring-expression-4.0.0.RELEASE.jar
commons-logging-1.1.3.jar

Spring支持面向切面编程的基础版包:

spring-aspects-4.0.0.RELEASE.jar   这是基础版的,功能不是太强大

Spring支持面向切面编程的加强版版包:(即使目标对象没有实现接口,也能创建动态代理)

com.springsource.net.sf.cglib-2.2.0.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar

1.1.2、写配置

(1)、创建一个conf文件,用于存放配置文件,注意这个conf文件夹,必须是源码文件夹,在src目录下创建好conf之后,需要点击菜单栏的file,选择project Structure,然后找到conf文件夹,右键选择source
在这里插入图片描述
然后选择apply应用,ok即可。

(2)、在conf文件夹里创建一个spring的xml文件
在这里插入图片描述
我们是要在配置文件里面进行配置,要让Logutils类中的方法动态切入到目标类中,就需要将目标类和切面类都加入到IOC容器中

(3)、将目标类和切面类加入到IOC容器中
在这里插入图片描述
在这里插入图片描述

(4)、在IOC容器中自动扫描包
自动扫描包需要用到context名称空间

xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
导入context名称空间,就必须写上这三条语句

在配置文件里写上:

<context:component-scan base-package="com.fxp"></context:component-scan>

在这里插入图片描述

(5)、告诉Spring到底哪个是切面类
这是一个新的注解,@Aspect,在切面类上加上这个注解,就是告诉spring这个类是切 面类
在这里插入图片描述

(6)、告诉Spring切面类里面的方法,在何时何地运行
告诉Spring每个方法什么时候运行,需要在方法的前面加上注解

 **5个通知注解**
 @Before:在目标方法运行之前运行;                          前置通知
 @After:在目标方法运行结束之后运行                         后置通知
 @AfterReturning:在目标方法正常返回之后运行                返回通知
 @AfterThrowing:目标方法抛异常之后运行                     异常通知
 @Around:环绕                                           环绕通知

//这个方法想在执行目标方法之前运行,写切入点表达式
//切入点表达式写法:("execution(访问权限符 返回值类型 方法签名)")
//如果想在所有方法执行之前都先执行这个方法,只需要将方法签名改成:com.fxp.impl.MyCalculator.*  即可
@Before("execution(public int com.fxp.impl.MyCalculator.*(int,int ))")
public static void logStart(){
    System.out.println("[xxx]开始执行.....它的参数是:xxx");
}
//这个方法想在目标方法正常执行结束之后运行
@AfterReturning("execution(public int  com.fxp.impl.MyCalculator.*(int,int))")
public static void LogReturn(){
    System.out.println("[xxx]正常执行完毕.....,结果是:xxx");
}
//这个方法想在目标方法出现异常的时候执行
@AfterThrowing("execution(public int com.fxp.impl.MyCalculator.*(int,int))")
public static void LogErr() {
    System.out.println("[xxx]出现异常:xxx");
}
//这个方法想在方法执行结束之后运行
@After("execution(public int com.fxp.impl.MyCalculator.*(int,int))")
public static void LogEnd() {
    System.out.println("方法最终执行完毕");
}
}

注意:
com.fxp.impl.MyCalculator.*(int,int )
这里一定要加上参数的类型(int,int ),否则会报错。

(7)、开启基于注解的AOP模式
需要用到aop名称空间,原理一样,具体原理在SpringIOC的context名称空间有讲解

xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd

在这里插入图片描述

1.1.3、测试

@Test
public void test(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("aop1.xml");
//从IOC容器中拿对象,注意:如果想要用类型获取,一定要用它的接口类型,不要用它本类
Calculator bean = ioc.getBean(Calculator.class);
bean.add(1,2);

创建IOC容器,并在IOC容器中拿到对象,注意:如果想要用类型获取,一定要用它的接口类型,不能用本类类型
运行结果:
在这里插入图片描述

至此,最简单的AOP功能已实现

2、源码

2.1、复制之前SpringAOP工程,并将Proxy去掉

在这里插入图片描述

2.2、配置文件源码

<?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
   http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

<context:component-scan base-package="com.fxp"></context:component-scan>
<!--开启基于注解的AOP功能:aop名称空间-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

需要导入aop名称空间,然后自动扫描包,开启基于注解的AOP功能

2.3、切面类源码

Logutils:

package com.fxp.util;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
 * 如何将这个类(切面类)中的这些方法(通知方法)动态的在目标方法运行的各个位置切入
 * 1、导包
 * spring-aop-4.0.0.RELEASE.jar
 * spring-beans-4.0.0.RELEASE.jar
 * spring-context-4.0.0.RELEASE.jar
 * spring-core-4.0.0.RELEASE.jar
 * spring-expression-4.0.0.RELEASE.jar
 * commons-logging-1.1.3.jar
 *
 * Spring支持面向切面编程的基础版包:
 * spring-aspects-4.0.0.RELEASE.jar   这是基础版的,功能不是太强大
 *
 * Spring支持面向切面编程的加强版版包:(即使目标对象没有实现接口,也能创建动态代理)
 * com.springsource.net.sf.cglib-2.2.0.jar
 * com.springsource.org.aopalliance-1.0.0.jar
 * com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
 */
//新的注解,@Aspect,这个注解就是告诉Spring这个类是切面类
@Aspect
//添加@component注解,将这个类加入到IOC容器中
@Component
public class LogUtils {

 /**
 * 告诉Spring每个方法什么时候运行
 * 5个通知注解
 * @Before:在目标方法运行之前运行;                          前置通知
 * @After:在目标方法运行结束之后运行                         后置通知
 * @AfterReturning:在目标方法正常返回之后运行                返回通知
 * @AfterThrowing:目标方法抛异常之后运行                     异常通知
 * @Around:环绕                                             环绕通知
 */
//这个方法想在执行目标方法之前运行,写切入点表达式
//切入点表达式写法:("execution(访问权限符 返回值类型 方法签名(方法的参数类型))")
//如果想在所有方法执行之前都先执行这个方法,只需要将方法签名改成:com.fxp.impl.MyCalculator.*(方法的参数类型)  即可
@Before("execution(public int com.fxp.impl.MyCalculator.*(int,int ))")
public static void logStart(){
    System.out.println("[xxx]开始执行.....它的参数是:xxx");
}
//这个方法想在目标方法正常执行结束之后运行
@AfterReturning("execution(public int  com.fxp.impl.MyCalculator.*(int,int))")
public static void LogReturn(){
    System.out.println("[xxx]正常执行完毕.....,结果是:xxx");
}
//这个方法想在目标方法出现异常的时候执行
@AfterThrowing("execution(public int com.fxp.impl.MyCalculator.*(int,int))")
public static void LogErr() {
    System.out.println("[xxx]出现异常:xxx");
}
//这个方法想在方法执行结束之后运行
@After("execution(public int com.fxp.impl.MyCalculator.*(int,int))")
public static void LogEnd() {
    System.out.println("方法最终执行完毕");
}
}

注意:方法的参数类型一定要写,不然会报错

2.4、测试类源码

package com.fxp.test;
import com.fxp.impl.MyCalculator;
import com.fxp.inter.Calculator;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.Arrays;

import static org.junit.Assert.*;

public class AopTest {
@Test
public void test(){
    ApplicationContext ioc = new ClassPathXmlApplicationContext("aop1.xml");
    //从IOC容器中拿对象,注意:如果想要用类型获取,一定要用它的接口类型,不要用它本类
    Calculator bean = ioc.getBean(Calculator.class);
    bean.add(1,2);
}
}

我们的目标是:在Mycalculator运行的时候,LogUtils类里面的方法能够动态切入到Mycalculator的方法里面,至此目标已基本达成。

猜你喜欢

转载自blog.csdn.net/weixin_42389904/article/details/114405985