目录:
2、如何使用CGLib产生代理对象:(在下面代码详细执行过程中,有产生动态代理对象的详细过程)
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: