学习Spring的第5天

学习Spring的第5天

可以使用动态代理来将日志代码动态的写在核心方法执行的前后。

但是,我们发现,虽然动态代理很强大,但是写起来好难。
当然,这个动态代理技术最大的缺陷就是:
如果目标对象没有实现任何接口

在这里插入图片描述

在这里插入图片描述在这里插入图片描述

动态代理最大的缺陷:

JDK默认的动态代理,如果目标对象没有实现任何接口,是无法为它创建代理对象的。
我们看一下我们自己定义的getProxy()返回的对象是什么类型的。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
之所以代理对象可以调用被代理对象的加减乘除的方法,就是因为,代理对象也实现了被代理对象的所有接口。

在这里插入图片描述
代理对象和被代理对象唯一能产生的关联就是实现了同一个接口。

在这里插入图片描述
在这里插入图片描述
这个结果可以看出我们获取的proxy对象,它也实现了Calculator接口。
如果目标对象(被代理对象)没有实现任何接口,是无法为他创建代理对象的。
动态代理已经是面向切面编程了。
因为,动态代理就是将日志代码动态的切入到加减乘除方法的指定位置(method.invoke()这个运行的前后)。
Spring知道动态代理的写法,太难了,所以就弄了一个AOP。
其实 AOP的底层就是:动态代理
可以利用Spring一句代码都不写的去创建动态代理。
实现简单,而且没有强制要求,目标对象必须实现接口。

AOP简单总结:

AOP:
将某段代码:这里举例子就是日志的打印代码
动态的切入:没有把日志代码和逻辑代码(加减乘除)写在一起

指定的方法:加减乘除

指定位置:方法的开始,结束,出异常之后…

Spring简化了切面编程。

AOP的几个专业术语:(抽象)

按照之前的例子来讲解。
1、接口,有加减乘除四个方法。
在这里插入图片描述
2、在方法的开始前,执行后,或者出现异常的时候,都可以选择打印日志。

术语1:横切关注点。

无论是加,减,乘,除四个方法,都是在它的方法开始的时候,加了日志打印。这就是横切关注点。
所以有四个横切关注点。
在这里插入图片描述
在这里插入图片描述
这个就是横切关注点

术语2:通知方法。

在这里插入图片描述
我们把方法执行前的日志打印叫做:通知方法。
所以,通知方法也有四个。
在这里插入图片描述
在这里插入图片描述
其实这两个就是通知方法。

术语3:切面类

这些方法,我们统一写在了一个LogUtils里面了。
在这里插入图片描述
这个类LogUtils叫做切面类。
在这里插入图片描述

1、接口类:
在这里插入图片描述
2、创建代理类:
在这里插入图片描述
3、日志打印工具类:
在这里插入图片描述
4、测试类:
在这里插入图片描述

执行结果:
在这里插入图片描述

术语4:连接点

每一个方法的每一个位置都是一个连接点。
比如:
拿add()方法来举例子。
add()方法,执行开始之前,要执行LogUtils.logStart()。开始执行add()之前的这个位置就是一个连接点,执行之后又是一个连接点。

术语5:切入点

但是现在我希望:
在这里插入图片描述
四个方法,每个方法有四个位置,我不希望每个方法的每个日志都进行日志的打印。
比如:
add:只有在方法结束的时候,打印日志
sub:从来都不打印日志
mul:只有在方法返回的时候,打印日志
div:只有在方法异常的时候,打印日志
也就是这三个点会打印日志。
我们把这三个点叫做切入点。
我们真正需要执行日志记录的地方叫做切入点。

切入点和连接点的关系:

我们在众多连接点中,选出我们感兴趣的地方,这些地方就是切入点。
在这里插入图片描述

术语6:切入点表达式:

刚才说了。要在众多连接点里面选出感兴趣的切入点。那怎么选呢?
就是写一个切入点表达式来选。

连接点 VS 切入点 VS 切入点表达式

类似于

表中所有数据 VS 只要性别是女生的数据 VS 查询出女生数据的sql语句

在这里插入图片描述

使用AOP来将日志记录动态的加进去。

学习AOP的简单配置。

目标:
如何将LogUtils这个类(切面类)
中的这些logStart()和logEnd()等这些方法(通知方法)
动态的在加法,或者乘法,或者触发,或者减法运行的各个位置去切入。
现在不写动态代理了。

AOP的使用步骤。

1、导包。下面是基础的包
在这里插入图片描述
Spring支持面向切面编程的包是:
这是基本版的面向切面编程的包
在这里插入图片描述
在这里插入图片描述
还有加强版的面向切面编程:在这里插入图片描述

导这三个加强版的jar包的原因就是,即使目标对象没有实现任何接口,也能创建动态代理。
在这里插入图片描述
2、写配置:
第一步:
将目标类和切面类加入到IOC容器中。
目标类:MyMathCaculator
切面类:LogUtils
将类加入到IOC容器中:
1、加注解。
在这里插入图片描述
2、写好ioc.xml配置文件
context 扫描基础包

<?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"
       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-4.3.xsd">
    <context:component-scan base-package="com.rtl" ></context:component-scan>
</beans>

在这里插入图片描述
第二步:
告诉Spring,哪个是切面类。
在这里插入图片描述
告诉Spring,哪个是切面类。就是在切面类上面在加上注解@Aspect
我们学习过程中,一直没有使用maven做。直接导入自己去网上找的jar包。发现学习AOP编程的时候无法找到@Aspect注解的包
在这里插入图片描述
在这里插入图片描述
所以我们选择重新new一个项目,这个是maven项目。
自己改成maven项目之后,就已经解决@Aspect注解加不上的问题了。
在这里插入图片描述
那就重新介绍一下项目的架构。
本项目是一个学习AOP编程的项目。使用maven技术。
在这里插入图片描述
在这里插入图片描述

pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>spring_aop</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <spring.version>5.2.2.RELEASE</spring.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.6.12</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.6.12</version>
        </dependency>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2</version>
        </dependency>
    </dependencies>

</project>

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

jdbc.username=root
jdbc.password=root
jdbc.jdbcUrl=jdbc:mysql://localhost:3306/test?useSSL=false
jdbc.driverClass=com.mysql.jdbc.Driver

在这里插入图片描述

<?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"
       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-4.3.xsd">
    <context:component-scan base-package="com.rtl" ></context:component-scan>

</beans>

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

package com.rtl.impl;

import com.rtl.inter.Calculator;
import org.springframework.stereotype.Service;

@Service
public class MyMathCalculator implements Calculator {

    @Override
    public int add(int i, int j) {
        int result = i + j ;
        return result;
    }

    @Override
    public int sub(int i, int j) {
        int result = i - j ;
        return result;
    }

    @Override
    public int mul(int i, int j) {
        int result = i * j ;
        return result;
    }

    @Override
    public int div(int i, int j) {
        int result = i / j ;
        return result;
    }
}

在这里插入图片描述

package com.rtl.inter;

public interface Calculator {
    int add(int i, int j);
    int sub(int i, int j);
    int mul(int i, int j);
    int div(int i, int j);
}

在这里插入图片描述

package com.rtl.utils;

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

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

@Aspect
@Component
public class LogUtils {
    public static void logStart(Method method, Object... args){
        System.out.println("【"+method.getName()+"】方法开始执行,使用的参数列表是:【"+ Arrays.asList(args)+"】");
    }

    public static void logEnd(Method method,Object result){
        System.out.println("【"+method.getName()+"】方法执行完成,它的计算结果是:"+result);
    }
}

在这里插入图片描述

package com.rtl.test;

import com.rtl.impl.MyMathCalculator;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AopTest {
    @Test
    public void test01(){
        ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("ioc.xml");

    }


}

写AOP编程
第一步:
导包(依赖形式)
第二步:
写配置。
1、目标类和切面类加入到IOC容器里面。
2、告诉Spring,我们哪个类是切面类。
也就是在LogUtils类头上,加上@Aspect注解
3、告诉Spring,切面类里面的每一个方法,都是何时运行的。
我们先把参数弄掉,简单一点开始。
之前的LogUtils:
在这里插入图片描述
现在的LogUtils:
没有方法的参数了
在这里插入图片描述

package com.rtl.utils;

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

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

@Aspect
@Component
public class LogUtils {
    //想在执行目标方法(加减乘除)之前执行
    public static void logStart(){
        System.out.println("【xxx】方法开始执行,使用的参数列表是:【xxx】");
    }

    //想在目标方法(加减乘除)正常执行完成之后执行
    public static void logReturn(){
        System.out.println("【xxx】方法执行完成,它的计算结果是:xxx");
    }

    //想在目标方法(加减乘除)执行的时候,出现异常执行
    public static void logException(){
        System.out.println("【xxx】方法执行的时候出现异常了,异常信息已经通知测试小组了。");
    }

    //想在目标方法(加减乘除)结束的时候执行
    public static void logEnd(){
        System.out.println("【xxx】方法最终执行完毕");
    }
}

3、告诉Spring,切面类里面的每一个方法,都是何时运行的。
我们先把参数弄掉,简单一点开始。
使用几个注解:
1、@Before 前置通知
org.aspectj.lang.annotation.Before;
在目标方法之前运行。

2、@After 后置通知
在目标方法运行结束之后
3、@AfterReturning 返回通知
在目标方法正常返回的时候

3、AfterThrowing 异常通知
在目标方法抛出异常时执行

4、@Around 环绕 环绕通知
它是最强大的通知,最后讲

在这里插入图片描述
写上注解之后,在括号里面加上切入点表达式
访问权限符 返回值类型 方法签名(copy reference)
在这里插入图片描述

比如这个logStart()方法,他就是在add()方法执行之前执行的。
所以:
@Before(“execution(public int com.rtl.impl.MyMathCalculator.add(int,int))”)
在这里插入图片描述

@Before("execution(public int com.rtl.impl.MyMathCalculator.add(int,int))")
    //想在执行目标方法(加减乘除)之前执行
    public static void logStart(){
        System.out.println("【xxx】方法开始执行,使用的参数列表是:【xxx】");
    }

在这里插入图片描述
这个就是在所有方法执行的时候,都选择执行。

我们先选择所有的方法。也就是用*,而不是具体方法
在这里插入图片描述
这些就是第三步,我们要告诉这些通知方法,在什么时候需要执行。

package com.rtl.utils;

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

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

@Aspect
@Component
public class LogUtils {
    @Before("execution(public int com.rtl.impl.MyMathCalculator.*(int,int))")
    //想在执行目标方法(加减乘除)之前执行
    public static void logStart(){
        System.out.println("【xxx】方法开始执行,使用的参数列表是:【xxx】");
    }

    @AfterReturning("execution(public int com.rtl.impl.MyMathCalculator.*(int,int))")
    //想在目标方法(加减乘除)正常执行完成之后执行
    public static void logReturn(){
        System.out.println("【xxx】方法执行完成,它的计算结果是:xxx");
    }

    @AfterThrowing("execution(public int com.rtl.impl.MyMathCalculator.*(int,int))")
    //想在目标方法(加减乘除)执行的时候,出现异常执行
    public static void logException(){
        System.out.println("【xxx】方法执行的时候出现异常了,异常信息已经通知测试小组了。");
    }

    @After(("execution(public int com.rtl.impl.MyMathCalculator.*(int,int))"))
    //想在目标方法(加减乘除)结束的时候执行
    public static void logEnd(){
        System.out.println("【xxx】方法最终执行完毕");
    }

}

配置里面的最后一个:
开启基于注解的AOP模式。
在配置文件ioc.xml里面去配置。
在这里插入图片描述
引入aop名称空间
在这里插入图片描述

在这里插入图片描述

66 20:37(在配置文件ioc.xml里面去配置。)

  • 10
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值