SpringAOP的操作和具体的使用方法三步走(传统方法)

什么是SpringAOP?
通俗的话来讲:就是你的已经做好的项目,需要给他增加功能,或者在更新迭代的时候,把以前的老的程序里面的方法做增强的话,最原始的手段是去直接改代码,这样做的感觉是很不友好的,造成代码的侵入性。
而AOP的思想是,不去动原来的代码,而是基于原来代码产生代理对象,通过代理的方法,去包装原来的方法,就完成了对以前方法的增强。换句话说,AOP的底层原理就是动态代理的实现。

关于AOP的三个步骤,把他记住了,AOP就不会有问题:
1. 确定目标对象(target—>bean) 通俗的来讲就是“谁不行了,你要把他交给spring,就是哪个方法需要增强,你就把他交给spring。
2. 编写Advice通知方法 (增强代码) 就是写增强代码
3. 配置切入点和切面 第三点的作用就是:让你的增强代码作用于你要增强的目标对象上

SpringAOP有两种实现方式:传统版本和AspectJ。具体操作都能实现业务需求,但是在这里还是希望大家能使用AspectJ,毕竟整体配置起来较为简单、轻量化,而且现在企业几乎都是AspectJ,传统的方法了解一下即可。

1、首先介绍一下传统的方式:
传统SpringAOP的Advice编写:
AOP联盟为通知Advice定义了org.aopalliance.aop.Interface.Advice
Spring按照通知Advice在目标类方法的连接点位置,可以分为5类
(1)前置通知 org.springframework.aop.MethodBeforeAdvice
* 在目标方法执行前实施增强
(2)后置通知 org.springframework.aop.AfterReturningAdvice
* 在目标方法执行后实施增强
(3)环绕通知 org.aopalliance.intercept.MethodInterceptor
* 在目标方法执行前后实施增强
(4)异常抛出通知 org.springframework.aop.ThrowsAdvice
* 在方法抛出异常后实施增强
(5)引介通知 org.springframework.aop.IntroductionInterceptor
* 在目标类中添加一些新的方法和属性
简单的说:通知就是增强的方式方法
遵循aop联盟规范,传统Spring AOP编程的Advice有五种(前置通知、后置通知、环绕通知、异常通知、引介通知) ,
注意:传统SpringAOP的Advice 必须实现对应的接口!

那小猴就以案例驱动来带你认识一下AOP,以环绕通知为例:
【需求】:开发一个记录方法运行时间的例子。将目标方法的运行时间,写入到log4j的日志中。
传统AOP三步走:
第一步: 引入所需依赖:

<!-- spring核心依赖 -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
		</dependency>
		
		<!—- springaspect集成 -->
		<!--这里要注意一下,这个aspects这个依赖里是AOP的相关配置的关键 -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aspects</artifactId>
		</dependency>

		<!-- 单元测试 -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<scope>test</scope>
		</dependency>

		<!-- 日志 -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
		</dependency>
		
		<!-- spring集成测试 -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
<scope>test</scope>
		</dependency>

引入applicationContext.xml配置文件和日志文件:
在这里插入图片描述
创建一个包,随便里面扔俩类
在这里插入图片描述
如果直接在源代码上增加功能的话,那就变成了侵入式编程了,所以在不更改源代码的情况下,使用AOP进行方法的更新。
使用动态代理的代码将对象配置到spring工厂中:

	 <!--消费者-->
    <bean class="com.beijihou.spring.a_proxy.customerService" id="customerService"/>
    <!--商品-->
    <bean class="com.beijihou.spring.a_proxy.productService" id="productService"/>

在这里插入图片描述

第二步:编写传统aop的Advice通知类。

首先我们新建一个包,名字叫oldaop,因为是用老的传统的方法来搞,然后包里创建一个类,名字叫TimeLogin,意思是运行时间。让他实现MethodInterceptor这个接口
注意啦,这里有坑,就是要选择的是上面这个aop的接口。
在这里插入图片描述
然后实现这个接口的方法
在这里插入图片描述
在此方法中,填写如下代码

//这个类是记录方法运行时间的
public class TimeLogin implements MethodInterceptor {

    @Override
    		//methodInvocation:这个参数指的是代理对象的包装类,用来获取代理对象/目标对象/方法的参数等等...
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        //调用代理对象原来的方法并返回方法的返回值
        Object proceed = methodInvocation.proceed();
        //返回这个返回值,整个代理的过程就结束了
        return proceed;
    }

即下图:
在这里插入图片描述
配置好之后,接下来就可以写你需要创建一个日志记录器来记录方法的运行时间:

//比如我们要记录方法运行的时间,并把它保存到日志记录器里,所以创建一个日志记录器
    private static Logger logger = Logger.getLogger(TimeLogin.class);

注意这里要选择log4j这个包
在这里插入图片描述

然后开始在invoke方法中添加增强功能的代码:

//这个类是记录方法运行时间的
public class TimeLogin implements MethodInterceptor {

    //比如我们要记录方法运行的时间,并把它保存到本地日志文件里,所以创建一个日志记录器
    private static Logger logger = Logger.getLogger(TimeLogin.class);

    @Override
    //methodInvocation:这个指的是代理对象的包装类,用来获取代理对象/目标对象/方法的参数等等...
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {

        //首先在方法前,添加一个记录时间的功能
        long beforeTime = System.currentTimeMillis();

        //调用代理对象原来的方法并返回方法的返回值
        Object proceed = methodInvocation.proceed();

        //然后在方法之后也添加一个记录时间的功能
        long afterTime = System.currentTimeMillis();

        //最后求出差值便是方法使用的时间
        long useTime = afterTime - beforeTime;

        //打印一下这个时间:
        //methodInvocation.getMethod().getName()  代表哪一个方法名,修饰一下,即什么方法运行了多长时间
        //如果在详细一点的话,需要把类名也加上,那么methodInvocation.getThis().getClass().getName()   即什么类的什么方法运行了多长时间
        System.out.println(methodInvocation.getThis().getClass().getName()+"类的"+methodInvocation.getMethod().getName()+"方法使用了" + useTime+"毫秒");

        //当然上方只是打印一下,那我们还需要做日志的记录到文件中
        logger.info(methodInvocation.getThis().getClass().getName()+"类的"+methodInvocation.getMethod().getName()+"方法使用了" + useTime+"毫秒");


        //返回这个返回值,整个代理的过程就结束了
        return proceed;
    }
}

然后我们去配一下log4j.properties文件,需要将这段代码添加进去,修改保存位置即可

log4j.rootLogger=DEBUG,A1,file
log4j.logger.org.apache=DEBUG
log4j.appender.A1.Target=System.err
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n

log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.File=G:/mylog.log
log4j.appender.file.layout.ConversionPattern=%p\t%d{ISO8601}\t%r\t%c\t[%t]\t%m%n

在这里插入图片描述
在这里插入图片描述
最好这里先把他的日志级别设置的小一点,我们把他改成INFO级别
在这里插入图片描述
OK,设置好之后,接下来就创建一个测试类,并填写如下代码:

import com.beijihou.spring.a_proxy.CustomerService;
import com.beijihou.spring.a_proxy.ProductService;
import org.junit.Test;

import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

//spring里面的注解
@RunWith(SpringJUnit4ClassRunner.class)
//去读取配置文件
@ContextConfiguration(locations = "classpath:applicationConText.xml")

public class SpringTest {

    @Autowired //关联配置文件中ID为customerService的bean
    private CustomerService customerService;

    @Autowired //关联配置文件中ID为productService的bean
    private  ProductService productService;

    @Test
    public void test(){
    	//调用各自的方法
        customerService.shopping();
        productService.sellMilk();
    }
}

在这里插入图片描述
然后测试方法运行之后我们发现:
在这里插入图片描述

我们之前写的记录运行时间的功能并没有生效
在这里插入图片描述
那我们去G盘里看下文件有没有生成:
在这里插入图片描述

文件居然生成了,
在这里插入图片描述
这是什么原因呢?仔细想想是不是少了点什么东西?
我们的AOP三步走才走了两步吧 ,把最关键的一步忘记了,那就是配置切入点和切面:

第三步:配置切入点和切面
我们进入applicationContext.xlm这个配置文件中发现:
在这里插入图片描述

你的目标对象有了,增强代码也有了,但是,增强代码并没有作用到你的目标对象上,所以这时,切入点和切面就来了,为了获得你目标对象中的方法,并拦截这些方法,拦截之后然后把通知代码(即增强代码)作用到这些方法上即可。进入到applicationcontext.xlm中进行如下配置:

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

    <!--第一步,确认目标对象-->
    <!--消费者-->
    <bean class="com.beijihou.spring.a_proxy.CustomerService" id="customerService"/>
    <!--商品-->
    <bean class="com.beijihou.spring.a_proxy.ProductService" id="productService"/>

    <!--第二步,编写并配置通知-->
    <!--需要注意的是,一般通知类的id末尾用Advice结尾-->
    <bean class="com.beijihou.spring.a_oldaop.TimeLogin" id="timeLogAdvice"/>

    <!--第三步,配置切入点和切面-->
    <aop:config>
        <!--切点-->
        <!--expression="bean(*Service) 表示切入点表达式,而他对应的值专属于AsspectJ这个框架-->
        <!--bean(*Service):这里的意思是指这个切点作用于所有ID以Service结尾的bean,将其对应的类中的所有的方法都拦截下来-->
        <aop:pointcut id="MyCut" expression="bean(*Service)"/>
        <!--切面-->
        <!--advisor advice-ref="timeLogAdvice" 指的是你要将什么作用于这个切点-->
        <!--pointcut-ref="MyCut" 指的是你要关联哪个切点-->
        <aop:advisor pointcut-ref="MyCut" advice-ref="timeLogAdvice"/>

    </aop:config>

</beans>

这张图就可以很清晰的看出来他们之间的关系:
切面的作用是将切点和通知关联起来。
切点的作用是关联目标对象,确认目标对象,拦截其方法
然后他们之间就产生了一种不可言语的关系…
在这里插入图片描述
产生关系之后呢,我们就可以重新快乐的跑一下了:
在这里插入图片描述

ok 成功的将记录运行方法运行时间的这个新功能鬼畜的实现了,而且最关键的是,没有代码的侵入行为,原来的代码依旧是原来的代码,一个字都没碰
在这里插入图片描述

ok那我们再去G盘里看一下日志文件进去没有:
在这里插入图片描述
大工搞成啦!

记住:玩转SpringAOP,牢记这三点即可

  1. 确定目标对象(target—>bean)
  2. 编写Advice通知方法 (增强代码)
  3. 配置切入点和切面

至于AspectJ 今天是没时间出了,只能改天吧。

最后,如果有哪里看不懂的或者有什么问题就留下评论吧,我特别喜欢和大佬们在学术上交流、一起探讨一些问题,而且是越激烈,我越兴奋哦
在这里插入图片描述

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring AOP(面向切面编程)是Spring框架中的一个重要特性,它通过将横切关注点与核心业务逻辑分离,实现了对系统的解耦和模块化。AOP通过在程序运行期间动态地将代码切入到对象的方法中,从而在不修改源代码的情况下,实现对方法的增强。 使用Spring AOP,我们可以通过以下步骤来实现: 1. 定义切面(Aspect):切面是一个类,其中包含了一些通知(Advice)和切点(Pointcut)。通知定义了在方法执行前、执行后、抛出异常等时机要执行的逻辑,而切点定义了哪些方法应该被增强。 2. 配置切面:在Spring配置文件中,我们需要声明和配置切面。 3. 启用AOP:在配置文件中启用AOP,以便Spring能够自动识别和处理切面。 4. 应用AOP:在需要应用AOP的地方,使用Spring提供的AOP支持,将切面织入到目标对象中。 两种常见的Spring AOP应用场景包括: 1. 日志记录:通过AOP可以在方法执行前后记录方法的调用信息、参数、返回值等,方便进行系统运行日志的记录和分析。 2. 事务管理:通过AOP可以在方法执行前开启事务,在方法执行后提交或回滚事务,实现对数据库操作的事务管理,保证数据的一致性。 以上是Spring AOP的概念及使用方法的简述,以及两种常见的应用场景。在实际开发中,我们可以根据具体需求结合AOP的特性,实现更多的功能和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值