详述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类库,如下图所示:

     

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

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

    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

<context:component-scan base-package="com.jd"></context:component-scan>
<aop:aspectj-autoproxy proxy-target-class="false"></aop:aspectj-autoproxy>

测试类: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.当配置为<aop:aspectj-autoproxy poxy-target-class="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)

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring AOP(面向切面编程)是Spring框架中的一个重要模块,它提供了一种在程序运行期间动态地将额外的行为织入到代码中的方式。通过使用Spring AOP,我们可以将与业务逻辑无关的横切关注点(如日志记录、性能统计、事务管理等)从业务逻辑中分离出来,使得代码更加清晰、可维护和可扩展。 Spring AOP实现主要依赖于以下几个核心概念: 1. 切面(Aspect):切面是一个模块化的单元,它封装了与横切关注点相关的行为。在Spring AOP中,切面可以包含通知(Advice)和切点(Pointcut)。 2. 通知(Advice):通知定义了在切面的特定位置执行的代码。在Spring AOP中,有以下几种类型的通知: - 前置通知(Before):在目标方法执行之前执行。 - 后置通知(After):在目标方法执行之后执行,无论是否发生异常。 - 返回通知(After-returning):在目标方法正常返回之后执行。 - 异常通知(After-throwing):在目标方法抛出异常后执行。 - 环绕通知(Around):包围目标方法执行,在前后都可以添加额外的逻辑。 3. 切点(Pointcut):切点定义了在哪些连接点(Joinpoint)上应用通知。通过使用切点表达式,我们可以指定需要拦截的方法或类。 4. 连接点(Joinpoint):连接点是在应用程序执行过程中能够插入切面的点,如方法调用、异常抛出等。 5. 织入(Weaving):织入是将切面应用到目标对象并创建代理对象的过程Spring AOP支持编译织入、类加载织入和运行织入三种方式。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值