实现SpingAOP及其实现过程分析
文章目录
一、实现SpingAOP
二、执行过程分析
一、实现SpingAOP
1、创建Java工程
2、创建lib文件夹,导入所需jar包
3、配置Sping配置文件,如下所示:
<?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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="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>
4、创建项目模块,其中自定义一个@Aspect修饰的切面类——>将其创建的对象保存于Spring IOC容器——>自定义增强方法,增强方法也称为通知方法
如图所示
ICalculatorService代码
package com.jd.calculator;
public interface ICalculatorService {
int mul(int a, int b);
int div(int a, int b);
}
CalculatorService代码
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) {
System.out.println(this.getClass().getName()+":The div method begins.");
System.out.println(this.getClass().getName()+":Parameters of the div method: ["+a+","+b+"]");
int result = a/b;
System.out.println(this.getClass().getName()+":Result of the div method:"+result);
System.out.println(this.getClass().getName()+":The div method ends.");
return result;
}
}
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;
@Component
@Aspect("")
public class CalculatorAspect {
@Before("execution( int mul(..))") //前置增强:在目标方法执行之前执行,切入点表达式:用于指定执行哪些类中的哪些方法时触发增强方法
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(..))") //后置增强:在目标方法执行之后执行不能得到方法的结果
public void after(JoinPoint jp) {
Object object = jp.getTarget();
Object [] args =jp.getArgs();
String name = jp.getSignature().getName();
System.out.println(this.getClass().getName()+":The "+name+" method ends.");
}
}
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 application= new ClassPathXmlApplicationContext("application.xml");
ICalculatorService calculatorService = application.getBean(ICalculatorService.class);
int result = calculatorService.mul(1, 1);
System.out.println("-->"+result);
}
}
二、执行过程分析
Test类main方法中的第一行:执行流到达配置文建中,会创建IoC容器,并执行一下说明的操作
<context:component-scan base-package="com.jd"></context:component-scan>
<!--扫描加了Service,Component,Repository注解的类,为其创建对象-->
<aop:aspectj-autoproxy proxy-target-class="false"></aop:aspectj-autoproxy>
<!--
Spring寻找@Aspect类(到达CalculatorAspect中)
——>寻找该类中方法(该类中方法为mul方法)
——>获取方法注解 ——> 获取表达式(execution(int mul(int, int)))
——>检查Spring能扫描到的所有类,将与表达式匹配的方法对应的类——>为该类创建动态对象
-->
Test类main方法中的第二行:获取所创建的动态代理对象
Test类main方法中的第三行:执行步骤参照另一篇文章,动态代理的过程,可参考所写的另一篇文章,这里就不过多的赘述
文章链接:https://blog.csdn.net/weixin_42867975/article/details/95983439
Test类main方法中的第四行:输出结果,如下图所示
特变说明:
① 默认情况下Sping是JDK动态代理,即在配置文件中,proxy-target-class="false",如果要改为CGlib动态处理,只需要
proxy-target-class="true"
② 该行代码说明
ICalculatorService calculatorService = application.getBean(CalculatorService.class);
a、如果是JDK动态代理,以上代码就是错误的,运行会出现报如下错误
这是因为所生成的动态代理对象的代理类与目标类之间没有继承关系,他们都是实现ICalculatorService接口,是同级关系,因 此代码应改为
ICalculatorService calculatorService = application.getBean(ICalculatorService.class);
b、 如果是CGLib动态代理,以上两种情况都是正确的,此时创建代理对象的代理类继承创建目标对象的类,且目标类实现了 ICalculatorService接口,因此在以上两种情况都可以
③ Sping实现CGLib动态代理时,不需要实现CGLib动态代理所需jar包,这是应为从Spring 3.2开始spring-core-xxx.jar包已集成CGLib和ASM 相关jar包,如下图所示