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三步走:
第一步: 引入所需依赖:


		
			org.springframework
			spring-context
		
		
		
		
		
			org.springframework
			spring-aspects
		

		
		
			junit
			junit
			test
		

		
		
			org.slf4j
			slf4j-log4j12
		
		
		
		
			org.springframework
			spring-test
test
		

引入applicationContext.xml配置文件和日志文件:
SpringAOP的操作和具体的使用方法三步走(传统方法)_第1张图片
创建一个包,随便里面扔俩类
SpringAOP的操作和具体的使用方法三步走(传统方法)_第2张图片
如果直接在源代码上增加功能的话,那就变成了侵入式编程了,所以在不更改源代码的情况下,使用AOP进行方法的更新。
使用动态代理的代码将对象配置到spring工厂中:

	 
    
    
    

SpringAOP的操作和具体的使用方法三步走(传统方法)_第3张图片

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

首先我们新建一个包,名字叫oldaop,因为是用老的传统的方法来搞,然后包里创建一个类,名字叫TimeLogin,意思是运行时间。让他实现MethodInterceptor这个接口
注意啦,这里有坑,就是要选择的是上面这个aop的接口。
SpringAOP的操作和具体的使用方法三步走(传统方法)_第4张图片
然后实现这个接口的方法
SpringAOP的操作和具体的使用方法三步走(传统方法)_第5张图片
在此方法中,填写如下代码

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

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

即下图:
SpringAOP的操作和具体的使用方法三步走(传统方法)_第6张图片
配置好之后,接下来就可以写你需要创建一个日志记录器来记录方法的运行时间:

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

注意这里要选择log4j这个包
SpringAOP的操作和具体的使用方法三步走(传统方法)_第7张图片

然后开始在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

SpringAOP的操作和具体的使用方法三步走(传统方法)_第8张图片
SpringAOP的操作和具体的使用方法三步走(传统方法)_第9张图片
最好这里先把他的日志级别设置的小一点,我们把他改成INFO级别
SpringAOP的操作和具体的使用方法三步走(传统方法)_第10张图片
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();
    }
}

SpringAOP的操作和具体的使用方法三步走(传统方法)_第11张图片
然后测试方法运行之后我们发现:
SpringAOP的操作和具体的使用方法三步走(传统方法)_第12张图片

我们之前写的记录运行时间的功能并没有生效
SpringAOP的操作和具体的使用方法三步走(传统方法)_第13张图片
那我们去G盘里看下文件有没有生成:
在这里插入图片描述

文件居然生成了,
SpringAOP的操作和具体的使用方法三步走(传统方法)_第14张图片
这是什么原因呢?仔细想想是不是少了点什么东西?
我们的AOP三步走才走了两步吧 ,把最关键的一步忘记了,那就是配置切入点和切面:

第三步:配置切入点和切面
我们进入applicationContext.xlm这个配置文件中发现:
SpringAOP的操作和具体的使用方法三步走(传统方法)_第15张图片

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




    
    
    
    
    

    
    
    

    
    
        
        
        
        
        
        
        
        

    


这张图就可以很清晰的看出来他们之间的关系:
切面的作用是将切点和通知关联起来。
切点的作用是关联目标对象,确认目标对象,拦截其方法
然后他们之间就产生了一种不可言语的关系…
SpringAOP的操作和具体的使用方法三步走(传统方法)_第16张图片
产生关系之后呢,我们就可以重新快乐的跑一下了:
SpringAOP的操作和具体的使用方法三步走(传统方法)_第17张图片

ok 成功的将记录运行方法运行时间的这个新功能鬼畜的实现了,而且最关键的是,没有代码的侵入行为,原来的代码依旧是原来的代码,一个字都没碰
SpringAOP的操作和具体的使用方法三步走(传统方法)_第18张图片

ok那我们再去G盘里看一下日志文件进去没有:
SpringAOP的操作和具体的使用方法三步走(传统方法)_第19张图片
大工搞成啦!

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

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

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

最后,如果有哪里看不懂的或者有什么问题就留下评论吧,我特别喜欢和大佬们在学术上交流、一起探讨一些问题,而且是越激烈,我越兴奋哦
SpringAOP的操作和具体的使用方法三步走(传统方法)_第20张图片

你可能感兴趣的:(Spring中遇到的问题,Spring,SpringAOP,AOP,切入点和切面,SpringAOP的操作)