详述Spring AOP的实现及执行过程

Spring AOP的实现



1、AOP的定义

AOP(Aspect Oriented Programming 面向切面编程)是一种通过运行期动态代理实现代码复用的机制,是对传统OOP(Object Oriented Programming,面向对象编程 )的补充。

2、AOP的配置方法

目前,Aspectj是Java社区里最完整最流行的AOP框架,在Spring 2.0以上版本中可以通过Aspectj注解或基于XML配置AOP。

3、AOP的实现

      1、新建一个Java工程;

      2、添加jar类库,如下图所示:

     详述Spring AOP的实现及执行过程_第1张图片

     3、按下图结构创建工程目录

    详述Spring AOP的实现及执行过程_第2张图片

    4、根据上图的框架写出如下代码:

ICalculatorService.java

package com.jd.calculator;

public interface ICalculatorService {

    int mul(int a,int b);
	
	int div(int a,int b);
}

CalculatorService.java

package com.jd.calculator;

import org.springframework.stereotype.Service;

@Service
public class CalculatorService implements ICalculatorService {

	@Override
	public int mul(int a, int b) {
		int result = a*b;
		return result;
	}

	@Override
	public int div(int a, int b) {
		int result = a/b;
		return result;
	}
}

CalculatorAspect.java

package com.jd.calculator;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component/*将CalculatorAspect类创建对象并保存到Spring容器*/
public class CalculatorAspect {
	
	//前置增强:在目标方法执行之前执行
	@Before("execution(int mul(int, int))")
	public void before(JoinPoint jp) {
		Object object = jp.getTarget();
		Object [] args = jp.getArgs();
		String name = jp.getSignature().getName();
		System.out.println(object.getClass().getName()+":The "+name+" method begins.");
		System.out.println(object.getClass().getName()+":Parameters of the "+name+" method: ["+args[0]+","+args[1]+"]");
	}
	//后置增强:在目标方法执行后执行,无论目标方法运行期间是否出现异常。注意:后置增强无法获取目标方法执行结果,可以在返回增强中获取
	@After("execution(int mul(int, int))")
	public void after(JoinPoint jp) {
		Object object = jp.getTarget();
		String name = jp.getSignature().getName();
		System.out.println(object.getClass().getName()+":The "+name+" method ends.");
	}
}

application.xml


测试类:Test

package com.jd.test;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.jd.calculator.CalculatorService;
import com.jd.calculator.ICalculatorService;

public class Test {

	public static void main(String[] args) {
		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
		ICalculatorService calculatorService = applicationContext.getBean(ICalculatorService.class);
		System.out.println(calculatorService.getClass().getName());
		int result = calculatorService.div(1, 1);
		System.out.println("——>"+result);
	}
}

Spring AOP的执行过程

1、根据Tset类中的main方法开始执行;

ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");

2、第一行的执行分析:

  (1)创建Spring IOC容器,加载application.xml中的配置;
  (2)application.xml中的配置分析

        <1>第一行:扫描所有以“com.jd”开头的包,并为其中加有@Component、@Service等注解的类创建对象

        <2>第二行: aop:aspectj-autoproxy

                  该配置作用:

                          a.如果创建目标对象的目标类中的方法与AspectJ切面中切入点表达式匹配,则自动为该目标对象生成动态代理对象,该代理对象默认使用JDK动态代理

                           b.当配置为"true"/>时,则使用CGLib动态代理

                  执行过程:

                          ①Spring寻找含有@Aspect注解的类(CalculatorAspect);

                          ②接着寻找该类中的所有方法;

                          ③从而获取到该类中所有方法的注解;

                          ④然后获取注解中的表达式(execution(int mul(int , int ));

                          ⑤然后再此检查Spring能扫描到的所有类,找到与表达式能够匹配的方法所对应的类;

                          ⑥最后为匹配到的类创建动态对象。

   (3)举例:

       ①Spring找到CalculatorAspect类上方有@Aspect注解;

       ②该类中有before和after方法;

       ③从而获取到里面有@Before和@After的注解

       ④然后获取注解中的表达式(execution(int mul(int , int ));

       ⑤然后再此检查Spring能扫描到的以com.jd开头的类,找到与表达式能够匹配的方法所对应的类CalculatorService

        ⑥最后为匹配到的CalculatorService类创建动态对象。

   (4)注意④中的execution表达式中的参数不能具体化,要么写成execution(int mul(int , int )或者execution(int mul(..)

	ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");

3、第二行的执行分析

             通过IOC容器对象applicationContext的getBean()方法来获取Spring容器中已初始化的bean,即获取代理对象

System.out.println(calculatorService.getClass().getName());

4、第三行的执行分析:通过反射获得动态代理对象的名字

int result = calculatorService.div(1, 1);

5、第四行的执行分析:

             先执行CalculatorAspect类中带有@Before注解的前置增强,再通过动态代理对象执行目标方法(详情移至https://blog.csdn.net/qq_42865575/article/details/95938860),最后执行CalculatorAspect类中带有@After注解的后置增强,将返回的值赋给result。

System.out.println("——>"+result);

6、第五行的执行分析:最后输出result结果

补充:

(1)为什么没有引asm和CGLib的jar包,还可以用CGLib动态代理?

原因:

①从Spring 3.2开始spring-core-xxx.jar包已集成CGLib和ASM 相关jar包,所以Spring工程不需再额外引入这些jar包,如下:

å¨è¿éæå¥å¾çæè¿°

②即使proxy-target-class设置为false,如果目标类没有声明接口,则Spring将自动使用CGLib生成代理对象

(2)当aop:aspectj-autoproxy标签内的proxy-target-class标签属性为"false"时,

applicationContext.getBean(ICalculatorService.class)为什么不能写作
applicationContext.getBean(CalculatorService.class)?

原因:

①proxy-target-class标签属性为"false"表示使用JDK生成代理对象,此时创建代理对象的代理类与创建目标对象的类之间没有继承关系,所以不能写成applicationContext.getBean(CalculatorService.class),但是由于此时创建代理对象的代理类实现了ICalculatorService接口,所以可以写成applicationContext.getBean(ICalculatorService.class);

②当proxy-target-class标签属性为"true"表示使用CGLib生成代理对象,此时创建代理对象的代理类继承创建目标对象的类,所以可以写作applicationContext.getBean(CalculatorService.class)

你可能感兴趣的:(详述Spring AOP的实现及执行过程)