详述SpringAOP实现及执行过程

本文深入探讨SpringAOP的实现,包括如何使用CGLib生成代理对象,详细分析代码执行过程,并解释即使未引入asm和CGLib的jar包,Spring依然可以工作的原因。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录:

1、代码:

2、如何使用CGLib产生代理对象:(在下面代码详细执行过程中,有产生动态代理对象的详细过程)

3、代码简略分析:

4、代码详细执行过程:

5、为什么没有引asm和CGLib的jar包,还可以用:

1、代码:

  application.xml

<?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:jee="http://www.springframework.org/schema/jee"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.3.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">

	<context:component-scan base-package="com.jd"></context:component-scan>

	<aop:aspectj-autoproxy proxy-target-class="false"></aop:aspectj-autoproxy>
	
</beans>

  CalculatorAspect.java

//CalculatorAspect中的代码
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
public class CalculatorAspect {

		@Before("execution(int mul (..))")
	public void before(JoinPoint joinPoint) {//前置增强;目标类的方法执行之前,会先执行此方法
		Object object = joinPoint.getTarget();
		Object [] args = joinPoint.getArgs();
		String name = joinPoint.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 joinPoint) {//后置增强;目标方法执行之后,执行此方法
		Object object = joinPoint.getTarget();
		String name = joinPoint.getSignature().getName();
		System.out.println(object.getClass().getName()+":The "+name+" method ends.");
	}
}

  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;
	}
}

  ICalculatorService.java

package com.jd.calculator;

public interface ICalculatorService {

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

  Test.java

//Test中的代码
package com.jd.test;

import org.springframework.context.support.ClassPathXmlApplicationContext;

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);
		int result = calculatorService.mul(1, 1);
		System.out.println("————>"+result);
		applicationContext.close();
	}
}

2、如何使用CGLib产生代理对象:

  (在代码详细执行过程中,有产生动态代理对象的详细过程)

    如图,在application.xml的<aop:aspectj-autoproxy proxy-target-class="false"></aop:aspectj-autoproxy>中,当 proxy-target-class="false"时,使用的是默认的动态代理方式jdk动态代理,当proxy-target-class="true"时,使用的是GCLib动态代理 ;这个时候由<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy> 产生代理对象 ;想知道使用的是jdk动态代理对象还是CGLib动态代理对象,需要在Test.java的mian方法中用System.out.println(calculatorService.getClass().getName());来输出值:

如果是就是jdk动态代理对象($Proxy后面不一定是数字8,也可能是0.1.2等), 

如果是就是CGLib动态代理类。

3、代码简略分析:

  CalculatorAspect.java中类上面的注解@Aspect是做的标记(切面),@Component是为了让Spring容器产生这个类的对象,在这个类中一共有两个方法,在两个方法上加的注解中,()里面的内容是表达式,用来匹配CalculatorService.java中的方法。

      before方法用来实现前置增强;joinPoint.getTarget()用来获得生成的代理对象;joinPoint.getArgs()获得传入before方法的参数值,并存放到args数组中。

      after方法用来实现部分后置增强;joinPoint.getTarget()用来获得生成的动态代理对象。

  Test.java中:

    第一行的结果,创建Spring容器,在非懒加载的情况下,为在com.jd包及其子包内加有注解@component,@repository,@Service,@controller的类创建对象,并且由<aop:aspectj-autoproxy proxy-target-class="false"></aop:aspectj-autoproxy>生成代理对象。

    第二行获取Spring中创建的动态代理对象;

    第三行调用动态代理类中的mul方法(和jdk动态代理中的add方法执行情况一致);

    第四行输出结果值;

    第五行关闭applicationContext;

4、代码详细执行过程:

    一:1、首先,在执行Test.java的main方法中的第一行代码时,会查看application.xml中的配置,这时候,程序执行跳到application.xml文件中。2、<context:component-scan base-package="com.jd"></context:component-scan>会扫描com.jd包及其子包内,标有注解@component,@repository,@Service,@controller的类创建对象(非懒加载的情况下)。3、然后在查看<aop:aspectj-autoproxy proxy-target-class="false"></aop:aspectj-autoproxy>时,Spring会寻找标有@Aspect的类,也就是上面代码段中的CalculatorAspect类,4、然后又寻找CalculatorAspect类中的方法,5、接着会获取这些方法中的注解,6、再然后会获取注解中的表达式,比如:@Before("execution(int mul (int ,int))")中的("execution(int mul (int ,int))"),7、紧接着,检查Spring能扫描到的所有类,也就是<context:component-scan base-package="com.jd"></context:component-scan>扫描到的类,并且找到与表达式匹配的方法所在的类,8、最终为该类创建动态对象;到这Test.java的main方法中的第一行代码执行完毕。

    二:获取application.xml文件中创建的动态对象,第二行代码执行完毕;注意:在使用jdk动态代理时,getBean(ICalculatorService.class)中的参数必须是ICalculatorService.class,因为jdk动态代理类实现了接口,但是和CalculatorService类是同级的;在使用CGLib动态代理时,可以是ICalculatorService.class也可以是CalculatorService.class,因为CGLib动态代理类继承了CalculatorService,是父子关系。

    三:这一步会调用动态对象的mul方法,和上篇文章jdk动态代理中add方法的执行过程一致 ,下面给出文章链接:                 

               https://blog.youkuaiyun.com/THG_TERCEL/article/details/95946200

           在这里有一点需要说明,在CalculatorAspect.java中,before和after方法上面,分别标注有@Before,@After,而且在注解中,有("execution(int mul (int ,int))"),在执行目录方法代码的时候,会先执行before方法,然后执行CalculatorService.java中的mul方法,最后再执行CalculatorAspect.java中的after方法。

5、为什么没有引asm和CGLib的jar包,还可以用:

 这是因为Spring的spring-core-4.3.10.RELEASE.jar中已经融入了asm和cglib:

                         

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值