栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

学习Spring的第5天

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

学习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 扫描基础包



    


第二步:
告诉Spring,哪个是切面类。

告诉Spring,哪个是切面类。就是在切面类上面在加上注解@Aspect
我们学习过程中,一直没有使用maven做。直接导入自己去网上找的jar包。发现学习AOP编程的时候无法找到@Aspect注解的包


所以我们选择重新new一个项目,这个是maven项目。
自己改成maven项目之后,就已经解决@Aspect注解加不上的问题了。

那就重新介绍一下项目的架构。
本项目是一个学习AOP编程的项目。使用maven技术。

pom.xml:



    4.0.0

    org.example
    spring_aop
    1.0-SNAPSHOT

    
        8
        8
        5.2.2.RELEASE
    

    
        
            junit
            junit
            4.10
        

        
            org.springframework
            spring-core
            ${spring.version}
        
        
            org.springframework
            spring-context
            ${spring.version}
        
        
            org.springframework
            spring-aop
            ${spring.version}
        
        
            org.aspectj
            aspectjrt
            1.6.12
        
        
            org.aspectj
            aspectjweaver
            1.6.12
        
        
            cglib
            cglib
            2.2
        
    





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



    




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里面去配置。)

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/434829.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号