Spring AOP源码深入剖析
1 Spring AOP源码深入剖析
AOP (Aspect Orient Programming):直译过来就是 面向切面编程。AOP 是一种编程思想
用途:Transactions (事务调用方法前开启事务, 调用方法后提交关闭事务 )、日志、性能(监控方法运行时间)、权限控制等也就是对业务方法做了增强
1.1 Spring AOP环境介绍
目标:认识AOP基础环境,后面讲使用这个基础环境进行源码讲解
**1)引入起步依赖 **
compile(project(':spring-aop'))
compile(project(':spring-context'))
compile 'org.aspectj:aspectjweaver:1.9.2'
2)新建接口和实现
public interface Slaver {
void work();
}
@Service
public class SlaverImpl implements Slaver {
//用来织入AOP的通知方法
@Override
public void work() {
System.out.println("进入实现类work.....");
try {
Thread.sleep(1000);
//此处决定拦截器的走向
// int s=1/0;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
3)新建切面类
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.util.Arrays;
//AspectJ 支持 5 种类型的通知注解
//将这个类声明为一个切面,需要将其放入IOC容器中
@Aspect//声明这是一个切面
@Component//声明这是一个组件
/**
* 执行顺序
* @Around进入环绕通知...
* @Before进入前置通知:[]
* 进入实现类 work.....
* @Around方法执行耗时>>>>>: 1001
* @After进入后置通知...
* @AfterReturning进入最终通知...End!
*/
public class SlaverAspect {
//环绕通知(连接到切入点开始执行,下一步进入前置通知,在下一步才是执行操作方法)
@Around(value = "pointCut()")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("@Around进入环绕通知...");
long startTime = System.currentTimeMillis();
// 调用了下一个拦截器,递归调用ReflectiveMethodInvocation#proceed
joinPoint.proceed();
long endTime = System.currentTimeMillis();
System.out.println(String.format("@Around方法执行耗时>>>>>: %s", endTime - startTime));
}
//前置通知(进入环绕后执行,下一步执行方法)
@Before(value = "pointCut()")
public void before(JoinPoint joinPoint) {
System.out.println("@Before进入前置通知:" + Arrays.toString(joinPoint.getArgs()));
}
//异常通知(出错时执行)
@AfterThrowing(value = "pointCut()", throwing = "ex")
public void afterThrowing(JoinPoint joinPoint, Throwable ex) {
System.out.println("@AfterThrowing进入异常通知" + Arrays.toString(joinPoint.getArgs()));
}
//后置通知(返回之前执行)
@After(value = "pointCut()")
public void after() {
System.out.println("@After进入后置通知...");
}
//最终通知(正常返回通知,最后执行,出现异常)
@AfterReturning(value = "pointCut()")
public void afterReturning() {
System.out.println("@AfterReturning进入最终通知...End!");
}
//定义一个切入点 后面的通知直接引入切入点方法pointCut即可
//参数:
//第一个”*“符号;表示返回值的类型任意
//.*(..)表示任何方法名,括号表示参数,两个点表示任何参数类型
@Pointcut(value = "execution(* com.spring.test.aop.impl.SlaverImpl.*(..))")
public void pointCut() {
System.out.println("@进入切点...");
}
}
AspectJ 支持 5 种类型的通知注解:
@Before: 前置通知, 在方法执行之前执行
@After: 后置通知, 在方法执行之后执行
@AfterRunning: 返回通知, 在方法返回结果之后执行
@AfterThrowing: 异常通知, 在方法抛出异常之后
@Around: 环绕通知, 围绕着方法执行
execution:用于匹配方法执行的连接点;
4)新建配置文件
resources/application-aop.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"
>
<!-- 使 AspectJ 的注解起作用 -->
<aop:aspectj-autoproxy/>
<!-- 扫描带有注解的类,交给ioc容器管理 -->
<context:component-scan base-package="com.spring.test.aop"/>
</beans>
常见错误
配置文件缺乏xsd的引用
5)新建入口类
public static void main(String[] args) throws InterruptedException {
ApplicationContext context =
new ClassPathXmlApplicationContext("classpath*:application-aop.xml");
Slaver slaver = (Slaver) context.getBean("slaverImpl");
//使用代理调用了JdkDynamicAopProxy.invoke
slaver.work();
}
}
6)运行效果
1.2 SpringAOP和AspectJ联系
Spring AOP:
Spring AOP旨在通过Spring IoC提供一个简单的AOP实现,以解决编码人员面临的最常出现的问题。这并不是完整的AOP解决方案,它只能用于Spring容器管理的beans。
AspectJ:
AspectJ是最原始的AOP实现技术,提供了完整的AOP解决方案。AspectJ更为健壮,相对于Spring AOP也显得更为复杂
总结
AOP是面向切面的一个思想
他有两种实现
1、Spring AOP
2、Aspectj
Spring AOP的实现没有AspectJ强大
所以,Spring把Aspectj给集成(如果用,还需要单独引jar)进来了
但是;spring aop已能满足我们的需求
在进行开发时候,这两个框架是完全兼容的
说白了,就是两个框架能一起使用,就看你项目需求用到的哪种程度了
简单的;spirng aop够用了,但是spring aop借助了aspectj的注解功能,
在高级点,比如切面很多,上万个,这是就要用到aspectj的高级功能了
区别:AspectJ使用的是编译期和类加载时进行织入,Spring AOP利用的是运行时织入
依赖:如果使用@Aspect注解,在xml里加上<aop:aspectj-autoproxy />。但是这需要额外的jar包(aspectjweaver.jar)
因为spring直接使用AspectJ的注解功能,注意只是使用了它 的注解功能而已。并不是核心功能 !
1.3 找到处理AOP的源头
1、Spring处理AOP源头在哪里(织入)
AspectJ编译期和类加载时进行织入、Spring AOP利用的是运行时织入
猜想:
- 在容器启动时创建?
- 在getBean时创建?
2、代理对象到底长什么样?
将断点打在getBean的返回对象上,发现这并不是一个我们定义的对象本身,而是一个Proxy
接下来,我们会找到$Proxy生成的始末
3、我的接口是怎么被A0P管理上的 ?
com.spring.test.aop.aop.SlaverAspect#pointCut
@Pointcut(value = "execution(* com.spring.test.aop.impl.SlaverImpl.*(..))")
public void pointCut() {
System.out.println("@进入切点...");
}
当然是execution声明,改成 SlaverImpl.aaaa*(..) , 再来看getBean的对象,不再是proxy
断点一下……
1.4 代理对象是怎么生成的
1、AOP其实就是用的动态代理模式,创建代理
2、AOP织入源头在哪里
目标:通过源头找代理对象是如何生成的
找到生成代理的地方Proxy.newProxyInstance
0)回顾助学
简单回顾一下,但是代理模式必须搞懂它的使用,尤其是动态代理。
开始之前,我们先必须搞懂一件事情:
那就是:代理模式
设计模式【静态代理】 【动态代理】
1)从源头找代理对象生成
记住目标:
spring aop使用的就是代理模式,那我们的目标就明确了:找到生成代理的地方
Proxy.newProxyInstance
先来张流程图:
下面我们沿着图中的调用链,找到aop 代理诞生的地方
从后置处理器开始
为什么要从后置处理器入手?
很容易理解,没初始化好没法用,等你初始化好了功能齐备了,我再下手,代替你
找到后置处理器
重点关注postProcessAfterInitialization
此处最好使用断点表达式,否则要循环很多次
因为在refresh方法中的invokeBeanFactoryPostProcessors方法也会调用到这个地方
断点表达式:
关注点:
在BeanPostProcessor循环中,观察AnnotationAwareAspectJAutoProxyCreator
这货就是切面的后置处理器
AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization
//目标:循环所有的后置处理器进行调用
//注意:
//AOP调试,此处最好使用断点表达式,否则要循环很多次
//因为在refresh方法中的invokeBeanFactoryPostProcessors方法也会调用到这个地方
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
//aop
//此处getBeanPostProcessors()有8个内置后置处理器;
// 生成代理会调用里面的 AnnotationAwareAspectJAutoProxyCreator
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
//Aop调用AbstractAutoProxyCreator#postProcessAfterInitialization
// 所以,最好在这个for里,下面这行打断点,加断点表达式:AnnotationAwareAspectJAutoProxyCreator
Object current = beanProcessor.postProcessAfterInitialization(result, beanName); // ===> aop 进!
if (current == null) {
return result;
}
result = current;
}
return result;
}
也就是说AOP模块是通过实现BeanPostProcessor集成进来的
2)进入后置处理器
tips:
aop这是spring内置的一个后置处理器,生效在postProcessAfterInitialization方法
AbstractAutoProxyCreator#postProcessAfterInitialization
重点关注wrapIfNecessary
//如果当前的bean适合被代理,则需要包装指定的bean
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
if (bean != null) {
// 根据给定的bean的class和name构建一个key
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
// 如果当前的bean适合被代理,则需要包装指定的bean
// aop:注意看这个bean,这还是SlaverImpl本尊,那么进去以后,情况变了~
return wrapIfNecessary(bean, beanName, cacheKey); // ===> aop 进!
}
}
return bean;
}
经历wrapIfNecessary方法,重点关注点有两个:
1是:getAdvicesAndAdvisorsForBean,找到哪些切面会作用在当前bean上,满足条件的抓出来!
2是:createProxy,生成代理,替代slaverImpl去做事
//目标:代理对象的创建就藏在这货里面!!!
//1、判断当前bean是否已经生成过代理对象
//2、拿到切面类中的所有增强方法(拦截器:环绕、前置、后置等)
//3、生成代理对象
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
//
// 判断是否为空 否在TargetSource缓存中存在
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// advisedBeans缓存了不需要代理的bean(为false的),如果缓存中存在,则可以直接返回
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
//Infrastructure基础设施
// 判断bean是否为Spring自带bean,如果是,不用进行代理的
// shouldSkip()则用于判断当前bean是否应该被略过
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
// 对当前bean进行缓存
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
//AOP: 【关键点 1 】
// 找到哪些aspect的execution能匹配上当前bean
// 匹配上的话列出前后和置换的方法(拦截器:环绕、前置、后置等),并且!!排好顺序
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); // ===> debug进
//debug后,仔细看一下上面这个数组内的值,其实就是SlaverAspect里的匹配上的方法信息!
//如果有匹配上的方法,就生成代理对象【关键点!】
if (specificInterceptors != DO_NOT_PROXY) {
// 允许创建代理对象的,设置为false
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 【关键节点 2 】
// 开始创建AOP代理!!!!!!!!!!
// !!!!!!!!!!!!!!
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); // ===>
// 缓存生成的代理bean的类型,并且返回生成的代理bean
this.proxyTypes.put(cacheKey, proxy.getClass());
//此处返回的代理和在Main函数中返回的是一样的
//说明此处代理成功创建,debug看一下proxy对象信息,变了~真身被隐藏
return proxy;
}
//如果拿到的增强方法为空,缓存起来(使用false标记不需要代理)
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
匹配上的话列出前后和置换的方法(拦截器:环绕、前置、后置等),并且!!排好顺序
@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
//AOP: 遍历所有注解了 @Aspectj 的类里的方法,将满足当前bean拦截条件的,封装成Advisor
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName); // ===> aop,debug 进
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray(); // 最终以数组形式返回
}
/**
* Find all eligible Advisors for auto-proxying this class.
* @param beanClass the clazz to find advisors for
* @param beanName the name of the currently proxied bean
* @return the empty List, not {@code null},
* if there are no pointcuts or interceptors
* @see #findCandidateAdvisors
* @see #sortAdvisors
* @see #extendAdvisors
*
* // ===【【【【注意!这货要分两步调试讲解,修改切面表达式做对比】】】】====
* // 将SlaverAspect的 execution改成 SlaverImpl.aaa*(..) 试试,eligibleAdvisors你将得到一个空数组……
*
* 1、找到所有的 @Aspect的bean,这些是在加载阶段 AspectJAutoProxyBeanDefinitionParser 解析进BD的
* 2、找到这些bean类里的切面方法,封装成Advisor
* 3、过滤一遍,只留那些能匹配当前slaverImpl的切面
* 4、对这些方法做个排序,返回去
*/
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 这是所有的切面里的方法(before,around,after……)!
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// ===> 这是Pointcut匹配符合当前bean的
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); // ===> 进去!
//spring帮你加了一个 ExposeInvocationInterceptor
// ExposeInvocationInterceptor就是用来传递MethodInvocation(当前方法信息)的。
// 仔细看这货的 invoke 方法就知道,它将当前MethodInvocation放入了一个threadlocal
// 那么后面你的所有其他切面,可以享受这个待遇了……
// 在后续的任何调用链环节,只要需要用到当前的MethodInvocation信息,
// 就可以通过ExposeInvocationInterceptor.currentInvocation()静态方法从threadloacl获得
// 细心不细心?体贴不体贴?
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
// 【注意】!在sort前后,debug一下eligibleAdvisors 列表的顺序
// 看一下这5个advisor属性里的 declarationOrder 的值,是不是从大到小的??明白了没?
eligibleAdvisors = sortAdvisors(eligibleAdvisors); // 排序,将来按这个顺序执行责任链!!!
} // 将来执行责任链的时候,就是按照这个顺序,一环环推进的
return eligibleAdvisors;
}
findAdvisorsThatCanApply
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass); // ===> aop , debug 进!
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new LinkedList<>();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor) {
// already processed
continue;
}
if (canApply(candidate, clazz, hasIntroductions)) { // ===> aop 会进canApply 判断 切面表达式是否符合当前bean
eligibleAdvisors.add(candidate); // 如果满足条件,就添加到可用数组里去,最终返回去
}
}
return eligibleAdvisors;
}
canApply
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
// 【关键点】debug变量,留心这个 MethodMatcher 里的:pointcutExpression , 发现了什么???
MethodMatcher methodMatcher = pc.getMethodMatcher();
if (methodMatcher == MethodMatcher.TRUE) {
// No need to iterate the methods if we're matching any method anyway...
return true;
}
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
Set<Class<?>> classes = new LinkedHashSet<>(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
classes.add(targetClass); // targetClass 就是我们的 SlaveImpl 这个bean
for (Class<?> clazz : classes) {
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz); // 遍历它所有的方法,跟aop切面表达式匹配!
for (Method method : methods) { // debug断点看看这个method,是不是我们的work方法???
if ((introductionAwareMethodMatcher != null &&
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||
methodMatcher.matches(method, targetClass)) { // 方法名是否匹配,就在这里!
return true; // 表达式 匹配这个方法,就返回true
}
}
}
return false;
}
3)开始创建代理对象
重点关注最下面的关键点:proxyFactory.getProxy(getProxyClassLoader())
//参数
//beanClass:目标对象class
//beanaName
//specificInterceptors:拦截器里面的拦截方法
//targetSource:目标资源
//目标:开始为bean创建代理
// 【重点关注】:最后一行
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
//为true,DefaultListableBeanFactory
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
//标记一下,当前的bean具备创建代理的资格
// 其实就是在BD设置了属性setAttribute("originalTargetClass",bean的class),进入===>
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass); // ===>
}
//创建一个默认的代理工厂DefaultAopProxyFactory,注意:父类无参构造器
ProxyFactory proxyFactory = new ProxyFactory();
//proxyFactory通过复制配置进行初始化
//this为AbstractAutoProxyCreator对象,说明AbstractAutoProxyCreator继承参数实际类型
proxyFactory.copyFrom(this); // ===> 其实就是设置了一堆值
/**
* true
*目标对象没有接口(只有实现类) – 使用CGLIB代理机制
* false
* 目标对象实现了接口 – 使用JDK代理机制(代理所有实现了的接口)
*/
//默认值为false,为true,使用CGLIB,
if (!proxyFactory.isProxyTargetClass()) {
//来判断@EnableAspectJAutoProxy注解或者XML的proxyTargetClass参数(true或者false)
//也就是:用户有没有明确指定什么方式生成代理
// 我们没指定,此处false
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
} else {
//评估接口的合理性,一些内部回调接口,比如InitializingBean等不要,我们自己的加入proxyFactory
evaluateProxyInterfaces(beanClass, proxyFactory); // ===>
}
}
// 把把前面我们过滤出来的那些切面方法,转成Advisor数组,specificInterceptors还有印象吧??
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
//加入到代理工厂
proxyFactory.addAdvisors(advisors);
//设置要代理的类(目标类)
proxyFactory.setTargetSource(targetSource);
//子类实现, 定制代理
customizeProxyFactory(proxyFactory);
//是否还允许修改通知,缺省值为false
proxyFactory.setFrozen(this.freezeProxy);
//设置预过滤
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
//【关键点!】proxyFactory携带了aop里配置的各种切面方法等等,由它来创建代理
return proxyFactory.getProxy(getProxyClassLoader()); // ===> aop进!藏在这里!代理类诞生的地方
}
进入getProxy
//通过类加载期获取代理【重点方法!】
public Object getProxy(@Nullable ClassLoader classLoader) {
//分别进入createAopProxy (获取aopProxy对象)和getProxy(代理实例的方法)
return createAopProxy().getProxy(classLoader); // ===> 先进create, 再进 get
}
先看createAopProxy
查看返回jdk代理还是cglib代理
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
//进入createAopProxy,查看返回jdk还是cglib
return getAopProxyFactory().createAopProxy(this); // ===> 进!
}
//走jdk? or 走Cglib?【关键方法】
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// isOptimize: 是否对代理进行优化
// isProxyTargetClass: 值为true,使用CGLIB代理,默认false
// hasNoUserSuppliedProxyInterfaces: 接口是不是满足
//1、如果长度为0;也就是接口为空,返回false
//or(或的关系)
//2、如果接口类型不是SpringProxy类型的;返回flase
//如果任意一个满足,走cglib代理,结果,特喵的,都不满足!
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
//Tips:
//如果目标对象实现了接口,默认情况下会采用JDK动态代理,
// 但也可以通过配置(proxy-target-class=true)强制使用CGLIB。
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
//jdk
return new JdkDynamicAopProxy(config);
}
//cglib
return new ObjenesisCglibAopProxy(config);
} else {
//jdk代理 , 走这里!
// 注意,config里面藏着了我们上面筛出来的那些 advisor,
// 也就是切面方法(before,after……)
// 并且,它们已经排好了顺序。
return new JdkDynamicAopProxy(config); // 【找到了!】 new出来的代理对象
}
}
//获取最终的代理对象(由JDK生成;运行时织入)
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
}
//获取代理对象需要实现的接口(业务接口和内置接口),不管他
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
//判断接口中是否重写了equals和hashCode方法,也不用搭理他
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
/**
* 【关键点】 jdk动态代理的诞生!Proxy是jdk的动态代理生成工具类
* 第一个参数是类加载器(目标类)
* 第二个参数是目标类实现的接口(含系统接口)(数组)
* 第三个是InvocationHandler,也就是这个JdkDynamicAopProxy自己,它实现了handler接口
* 而前面的步骤,把筛出来的 一堆排好序的 advisor ,给了这货
* 未来真正调用代理方法的时候,这货的invoke被触发,开始使用这些advisor当责任链列表,一环环被调用……
* 而这,就是aop的真相~ 其实很简单!
*/
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); // 真身被隐藏,proxy被创建!
}
找到了!代理对象在bean初始化阶段装配进了spring
4)代理对象验证
tips:
前面创建完成了代理对象,下面我们看下它调用的时候,是不是走了代理
这是我们一开始的结果,下面我们来再debug到work方法时,点击debug into试试,发现调到哪里去了???
结论:
没错!代理对象精准的调用了JdkDynamicAopProxy里面的invoke方法
这说明jdk动态代理生效,但是它生成的proxy字节码在jvm里,我们是看不到的,怎么破?
arthas上!
2)Arthas代理类验证
arthas,阿里神器,主页:https://arthas.aliyun.com/zh-cn/
获取之前,我们需要做点小事情,打出我们的 slaver的类路径,让arthas能找到它!
源码:
public static void main(String[] args) throws InterruptedException {
ApplicationContext context =
new ClassPathXmlApplicationContext("classpath*:application-aop.xml");
Slaver slaver = (Slaver) context.getBean("slaverImpl");
//使用代理调用了JdkDynamicAopProxy.invoke
slaver.work();
System.out.printf(slaver.getClass().getName());
Thread.sleep(Integer.MAX_VALUE);
// 必须停留在这里,debug是不行的,arthas会 连不上
System.out.println("over>>>>>>>>>>");
开启arthas:
- 很简单, java -jar arthas-boot.jar
- 启动后,在arthas里执行:jad com.sun.proxy.$Proxy17 反编译我们的代理类
注意,jad后面的,换成你上一步控制台打印出来的
见证奇迹的时刻……
找到里面的work方法,结果它长这样……
public final class $Proxy17
extends Proxy
implements Slaver,
SpringProxy,
Advised,
DecoratingProxy {
private static Method m1;
private static Method m12;
private static Method m20;
private static Method m5;
private static Method m21;
private static Method m17;
private static Method m4;
private static Method m8;
private static Method m15;
private static Method m14;
private static Method m0;
private static Method m18;
private static Method m24;
private static Method m11;
private static Method m6;
private static Method m2;
private static Method m26;
private static Method m19;
private static Method m27;
private static Method m22;
private static Method m9;
private static Method m10;
private static Method m23;
private static Method m7;
private static Method m3;
private static Method m25;
private static Method m13;
private static Method m16;
public final TargetSource getTargetSource() {
try {
return (TargetSource)this.h.invoke(this, m4, null);
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final boolean isProxyTargetClass() {
try {
return (Boolean)this.h.invoke(this, m5, null);
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final void setTargetSource(TargetSource targetSource) {
try {
this.h.invoke(this, m6, new Object[]{targetSource});
return;
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final void setPreFiltered(boolean bl) {
try {
this.h.invoke(this, m7, new Object[]{bl});
return;
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public $Proxy17(InvocationHandler invocationHandler) {
super(invocationHandler);
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m12 = Class.forName("org.springframework.aop.framework.Advised").getMethod("isExposeProxy", new Class[0]);
m20 = Class.forName("org.springframework.aop.framework.Advised").getMethod("addAdvisor", Class.forName("org.springframework.aop.Advisor"));
m5 = Class.forName("org.springframework.aop.framework.Advised").getMethod("isProxyTargetClass", new Class[0]);
m21 = Class.forName("org.springframework.aop.framework.Advised").getMethod("removeAdvisor", Integer.TYPE);
m17 = Class.forName("org.springframework.aop.framework.Advised").getMethod("getProxiedInterfaces", new Class[0]);
m4 = Class.forName("org.springframework.aop.framework.Advised").getMethod("getTargetSource", new Class[0]);
m8 = Class.forName("org.springframework.aop.framework.Advised").getMethod("indexOf", Class.forName("org.springframework.aop.Advisor"));
m15 = Class.forName("org.springframework.aop.framework.Advised").getMethod("addAdvice", Integer.TYPE, Class.forName("org.aopalliance.aop.Advice"));
m14 = Class.forName("org.springframework.aop.framework.Advised").getMethod("addAdvice", Class.forName("org.aopalliance.aop.Advice"));
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m18 = Class.forName("org.springframework.aop.framework.Advised").getMethod("isInterfaceProxied", Class.forName("java.lang.Class"));
m24 = Class.forName("org.springframework.aop.framework.Advised").getMethod("removeAdvice", Class.forName("org.aopalliance.aop.Advice"));
m11 = Class.forName("org.springframework.aop.framework.Advised").getMethod("setExposeProxy", Boolean.TYPE);
m6 = Class.forName("org.springframework.aop.framework.Advised").getMethod("setTargetSource", Class.forName("org.springframework.aop.TargetSource"));
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m26 = Class.forName("org.springframework.aop.framework.Advised").getMethod("getTargetClass", new Class[0]);
m19 = Class.forName("org.springframework.aop.framework.Advised").getMethod("addAdvisor", Integer.TYPE, Class.forName("org.springframework.aop.Advisor"));
m27 = Class.forName("org.springframework.core.DecoratingProxy").getMethod("getDecoratedClass", new Class[0]);
m22 = Class.forName("org.springframework.aop.framework.Advised").getMethod("removeAdvisor", Class.forName("org.springframework.aop.Advisor"));
m9 = Class.forName("org.springframework.aop.framework.Advised").getMethod("indexOf", Class.forName("org.aopalliance.aop.Advice"));
m10 = Class.forName("org.springframework.aop.framework.Advised").getMethod("isFrozen", new Class[0]);
m23 = Class.forName("org.springframework.aop.framework.Advised").getMethod("replaceAdvisor", Class.forName("org.springframework.aop.Advisor"), Class.forName("org.springframework.aop.Advisor"));
m7 = Class.forName("org.springframework.aop.framework.Advised").getMethod("setPreFiltered", Boolean.TYPE);
m3 = Class.forName("com.spring.test.aop.service.Slaver").getMethod("work", new Class[0]);
m25 = Class.forName("org.springframework.aop.framework.Advised").getMethod("toProxyConfigString", new Class[0]);
m13 = Class.forName("org.springframework.aop.framework.Advised").getMethod("getAdvisors", new Class[0]);
m16 = Class.forName("org.springframework.aop.framework.Advised").getMethod("isPreFiltered", new Class[0]);
return;
}
catch (NoSuchMethodException noSuchMethodException) {
throw new NoSuchMethodError(noSuchMethodException.getMessage());
}
catch (ClassNotFoundException classNotFoundException) {
throw new NoClassDefFoundError(classNotFoundException.getMessage());
}
}
public final boolean equals(Object object) {
try {
return (Boolean)this.h.invoke(this, m1, new Object[]{object});
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final String toString() {
try {
return (String)this.h.invoke(this, m2, null);
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final int hashCode() {
try {
return (Integer)this.h.invoke(this, m0, null);
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final int indexOf(Advisor advisor) {
try {
return (Integer)this.h.invoke(this, m8, new Object[]{advisor});
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final int indexOf(Advice advice) {
try {
return (Integer)this.h.invoke(this, m9, new Object[]{advice});
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final boolean isFrozen() {
try {
return (Boolean)this.h.invoke(this, m10, null);
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final void setExposeProxy(boolean bl) {
try {
this.h.invoke(this, m11, new Object[]{bl});
return;
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final boolean isExposeProxy() {
try {
return (Boolean)this.h.invoke(this, m12, null);
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final Advisor[] getAdvisors() {
try {
return (Advisor[])this.h.invoke(this, m13, null);
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final Class getDecoratedClass() {
try {
return (Class)this.h.invoke(this, m27, null);
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final Class getTargetClass() {
try {
return (Class)this.h.invoke(this, m26, null);
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final void addAdvice(int n, Advice advice) throws AopConfigException {
try {
this.h.invoke(this, m15, new Object[]{n, advice});
return;
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final void addAdvice(Advice advice) throws AopConfigException {
try {
this.h.invoke(this, m14, new Object[]{advice});
return;
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final boolean isPreFiltered() {
try {
return (Boolean)this.h.invoke(this, m16, null);
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final Class[] getProxiedInterfaces() {
try {
return (Class[])this.h.invoke(this, m17, null);
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final boolean isInterfaceProxied(Class clazz) {
try {
return (Boolean)this.h.invoke(this, m18, new Object[]{clazz});
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final void addAdvisor(Advisor advisor) throws AopConfigException {
try {
this.h.invoke(this, m20, new Object[]{advisor});
return;
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final void addAdvisor(int n, Advisor advisor) throws AopConfigException {
try {
this.h.invoke(this, m19, new Object[]{n, advisor});
return;
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final void removeAdvisor(int n) throws AopConfigException {
try {
this.h.invoke(this, m21, new Object[]{n});
return;
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final boolean removeAdvisor(Advisor advisor) {
try {
return (Boolean)this.h.invoke(this, m22, new Object[]{advisor});
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final boolean replaceAdvisor(Advisor advisor, Advisor advisor2) throws AopConfigException {
try {
return (Boolean)this.h.invoke(this, m23, new Object[]{advisor, advisor2});
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final boolean removeAdvice(Advice advice) {
try {
return (Boolean)this.h.invoke(this, m24, new Object[]{advice});
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final String toProxyConfigString() {
try {
return (String)this.h.invoke(this, m25, null);
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final void work() {
try {
this.h.invoke(this, m3, null);
return;
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
}
那么,this.h呢?
杀死进程,回到debug模式,看看
没错,就是我们的jdk动态代理类!
现在调用关系明确了,接下来,我们就来分析下这个invoke
1.5 代理对象如何调用
1)先看张图
代理对象调用链如下图 (责任链,先有个印象,很长,很长……)
2)理解责任链
代码中给大家准备了一个责任链小demo,它就是我们spring aop切面调用链的缩影
spring-aop-test 项目下的 com.spring.test.aop.chain 包。
执行里面的main方法
BaseHandler
public abstract class BaseHandler {
public void execute(Chain chain){
handlerProcess(); // 执行自己的业务逻辑
chain.proceed(); //执行完,继续调链的 proceed,推进链往前走
};
protected abstract void handlerProcess(); //抽象的,实际的切面逻辑,交给具体实现类来实现
}
Chain
public class Chain {
private List<BaseHandler> handlers;
private int index = -1; // 索引,表示当前链执行到第几个了
public Chain(List<BaseHandler> handlers){
this.handlers = handlers; // 所有的切面
}
public void proceed(){
if(index == handlers.size() - 1){ //链执行到最后一个后
System.out.println("i am here"); //执行真正的业务逻辑
}else{
handlers.get(++index).execute(this); // 否则,增加索引找下一个切面,先执行它的
}
}
}
Main
public class Main {
static class ChainHandlerA extends BaseHandler {
@Override
protected void handlerProcess() {
System.out.println("切面 a");
}
}
static class ChainHandlerB extends BaseHandler{
@Override
protected void handlerProcess() {
System.out.println("切面 b");
}
}
static class ChainHandlerC extends BaseHandler{
@Override
protected void handlerProcess() {
System.out.println("切面 c");
}
}
public static void main(String[] args) {
List<BaseHandler> handlerList = Arrays.asList(
new ChainHandlerA(),
new ChainHandlerB(),
new ChainHandlerC()
);
Chain chain = new Chain(handlerList);
chain.proceed();
}
}
3)invoke方法源码分析
通过上小节我们知道,代理模式下执行的是以下invoke
org.springframework.aop.framework.JdkDynamicAopProxy#invoke
代码重点关注
//目标
//1、调用增强方法
//2、反射调用目标方法
//重点关注:getInterceptorsAndDynamicInterceptionAdvice责任链方法
// 和invocation.proceed()方法(开始调用)
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
//一堆判断和加载,拖到最下面,看责任链部分,核心在那里。
Object oldProxy = null;
boolean setProxyContext = false;
//获取目标资源,此处就是slaverImpl,debug变量值试试
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try { // 一顿 if 猛如虎,一看跟业务没半毛钱关系,往下走!
//当前方法是否等于Equals,如果是,则重写
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
return equals(args[0]);
//当前方法是否等于HashCode,如果是,则重写
} else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
return hashCode();
//方法声明类是否等于DecoratingProxy
} else if (method.getDeclaringClass() == DecoratingProxy.class) {
//使用反射直接进行调用目标资源
return AopProxyUtils.ultimateTargetClass(this.advised);
//方法声明是否接口 、或者是否Advised类型
} else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// 用代理配置对ProxyConfig进行服务调用。。。
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
//如果暴露;就放到ThreadLocal,默认不暴露,不重要,不管他
if (this.advised.exposeProxy) {
// 放到ThreadLocal
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
//目标资源;对应业务实现类,这是我们的真身(SlaverImpl),debug变量看看??
target = targetSource.getTarget();
//目标类;对应业务实现类
Class<?> targetClass = (target != null ? target.getClass() : null);
//【关键点 1 】构建责任链,看一下它的值是什么???(前面整理过我们的切面方法)
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); // ===> aop,进!
// 如果为空,则直接调用target的method
if (chain.isEmpty()) {
//如果没有拦截器,直接调用
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); // 直接执行
} else {
//proxy代理对象
//target是目标类
//targetClass是目标类的class
//method是目标方法
//args是对应的方法参数
//chain是对应的拦截器
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
//!!!责任链即将开始调用的入口~~~
retVal = invocation.proceed(); // ===> debug 进去!【关键点 2 】
}
//以下方法,在责任链执行完成后,才会跑到,就一些收尾工作
// Massage return value if necessary.
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
retVal = proxy;
} else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
} finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// 重新设置下ThreadLocal
AopContext.setCurrentProxy(oldProxy);
}
}
}
责任链构建:chain里面为责任链的具体任务
接下来,我们具体看看责任链具体的处理逻辑
4)AOP核心之责任链
思考:
责任链调用,调用的什么?
责任链目标:
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
MethodCacheKey cacheKey = new MethodCacheKey(method);
List<Object> cached = this.methodCache.get(cacheKey);
if (cached == null) {
//cached===pointCut/afterThrowing/afterReturning/after/around/before
//开始构建责任链
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass); // ===> 进!
this.methodCache.put(cacheKey, cached);
}
return cached;
}
@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, @Nullable Class<?> targetClass) {
//config.getAdvisors()==pointCut/afterThrowing/afterReturning/after/around/before
List<Object> interceptorList = new ArrayList<>(config.getAdvisors().length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass()); //SlaverImpl.class
boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
for (Advisor advisor : config.getAdvisors()) { // 记得前面的Advisor不?排好序的切面方法列表!
//一个个循环遍历,配置好后放入一个列表返回,这里我们debug直接跳出
// ===debug out, 往回走!
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
//非运行时
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors() method
// isn't a problem as we normally cache created chains.
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
//将所有的方法添加到list
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
AOP责任链调用流程简图
注意,我们的链条如下:
调试技巧:
从 ReflectiveMethodInvocation.invoke() 开始,对照上面的责任链嵌套调用图
每次通过debug into 进行查看,每到一环,注意对照图上的节点,看到那个invocation了!
//开始责任链模式;遍历拦截器链,调用每个拦截器的invoke方法
@Override
@Nullable
public Object proceed() throws Throwable {
//1、currentInterceptorIndex 索引,-1开始并提前递增
//2、this.interceptorsAndDynamicMethodMatchers,就是前面的拦截方法集合,list
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
// 如果执行到链条的末尾 则开始调用原始方法,
// 第一次肯定进不来这里,由before执行过后才会进来!执行完后,会回到before
return invokeJoinpoint(); // ===> 反射执行业务方法,也就是我们的work方法
}
//自增。这个索引从-1开始的,所以先++
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
//判断类型执行invoke或proceed
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
//强制转换
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
// 动态判断拦截器是否匹配
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
} else {
// 不匹配会递归调用拦截链的下一个拦截器
return proceed();
}
} else {
//注意:debug into,注意每次进去后,看当前执行的类是什么,对照课件里的调用图 1.5 - 4
// 开始调用链第一环,为 ExposeInvocationInterceptor
// 也就是spring自动帮我们加上的,上下传递 MethodInvocation 的那货
// 注意这个参数:this 。
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); // ===>
}
}
责任链调用开始(重点)
ExposeInvocationInterceptor
//暴露调用拦截器方法,核心invocation.set(mi);
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
//将MethodInvocation mi 设置到 ThreadLocal invocation 里面,拿的时候也可以使用上面的 方法currentInvocation
MethodInvocation oldInvocation = invocation.get();
//第一环!expose
// 先干自己的活,本地线程局部变量,方法currentInvocation可以获取
invocation.set(mi);
try {
// 然后,继续调责任链的proceed推动链条前进!
//注意这个mi,上面传来的是 this,意味着,又回到了上面继续 proceed
// 回去以后,index会增加,将执行责任链的下一环,依次推进……
return mi.proceed(); // ===> debug into , 结果回去了~
}
finally {
//最后执行, 责任链,递归调用结束~~~完美!
invocation.set(oldInvocation);
}
}
AspectJAfterThrowingAdvice
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
//第二环:after throwing
// 它自己本身不干啥事,就捕获异常
// 责任链,继续!
return mi.proceed();
}
catch (Throwable ex) {
//如果出现异常,才是它干活的地方!
if (shouldInvokeOnThrowing(ex)) {
invokeAdviceMethod(getJoinPointMatch(), null, ex);
}
throw ex;
}
}
AfterReturningAdviceInterceptor
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
//第三环:after returning
// after,顾名思义它做的事情在后头,先放行,让责任链下一环走。
Object retVal = mi.proceed();
//反向第三环:等责任链走完了,它才执行自己的逻辑!
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
AspectJAfterAdvice
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
//第四环:after,它也是后置的,先放行
// 等责任链完事后,早晚会执行我的finally,跑不了你小子。
return mi.proceed();
}
finally {
//之所以after方法始终会走,是因为, 有个finally
invokeAdviceMethod(getJoinPointMatch(), null, null); //反向第二环:after - finally,必经之路
}
}
AspectJAroundAdvice
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
if (!(mi instanceof ProxyMethodInvocation)) {
throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
}
//第五环,around,自己有业务要开始执行了!看下面的【关键点】
ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
//延迟获取进程连接点;new一个MethodInvocationProceedingJoinPoint
//作用,作为参数传递到around业务方法,方便再次递归
ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
//获取连接点匹配对象,为null
JoinPointMatch jpm = getJoinPointMatch(pmi);
return invokeAdviceMethod(pjp, jpm, null, null); // ===> 【关键点】反射调用切面的around方法
}
MethodBeforeAdviceInterceptor
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
//第六环: before,先反射执行自己的逻辑
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
//然后,责任链,继续!注意debug into回到责任链后,已经到底了!!!
// 那么,我们预测下一步将开始执行业务逻辑,也就是work方法
return mi.proceed(); // 执行完还会回来的!回来后,开始单步debug(step over),回到环绕后置逻辑
}
2 AOP基础 - 代理模式
2.1 设计模式之代理
背景
举个例子
假设我们想邀请一位明星,不联系明星
而是联系明星的经纪人,来达到邀请的的目的
明星就是一个目标对象,他只要负责活动中的节目,而其他琐碎的事情就交给他的代理人(经纪人)来解决.
这就是代理思想在现实中的一个例子
什么是代理?
代理(Proxy)是一种设计模式
提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.
这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作
代理模式分类
1、静态代理
2、动态代理
2.2 静态代理模式
静态代理在使用时:
需要定义接口、目标对象与代理对象
重要特点:
静态代理是由程序员创建或工具生成代理类的源码,再编译代理类。
接口
public interface IStartBusiness {
//邀请明星唱歌
void sing();
}
实现类
//目标对象,实现类
public class StartBusinessImpl implements IStartBusiness {
@Override
public void sing() {
System.out.println("sing>>>>>>>>>>>>>>>>>>>>>>>>>>>");
}
}
目标对象,实现类
//代理对象,静态代理
public class AgentProxy implements IStartBusiness {
//代理类持有一个目标类的对象引用
private IStartBusiness iStartBusiness;
//构造注入目标对象
public AgentProxy(IStartBusiness iStartBusiness) {
this.iStartBusiness = iStartBusiness;
}
@Override
public void sing() {
//**********方法前增强****************
//将请求分派给目标类执行;通过注入进入来的目标对象进行访问
this.iStartBusiness.sing();
//**********方法后增强****************
}
}
静态代理测试
//静态代理测试
public class Test {
public static void main(String[] args) {
//目标对象
IStartBusiness target = new StartBusinessImpl();
//代理对象,把目标对象传给代理对象,建立代理关系
IStartBusiness proxy = new AgentProxy(target);
//调用的时候通过调用代理对象的方法来调用目标对象
proxy.sing();
}
}
优点:
可以在被代理方法的执行前或后加入别的代码,实现诸如权限及日志的操作。
缺点:
1、如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法
总结:(记住两点)
1、只需要知道静态代理是在运行前代理类就已经被织入进去了
2、大规模使用静态代理难以维护(增加方法)
有没有其他的方式可以减少代码的维护,那就是动态代理?
2.3 动态代理模式
什么是动态代理?
动态代理类的源码是在程序运行期间由JVM根据反射等机制动态织入的,
所以;不存在代理类的字节码文件,直接进了虚拟机。(但是有办法给抓到他)
JDK中生成代理对象的API最重要类和接口有两个,如下
Proxy
InvocationHandler
1)代理父类Proxy回顾
所在包:java.lang.reflect.Proxy
这是 Java 动态代理机制生成的所有动态代理类的父类,
提供了一组静态方法来为一组接口动态地生成代理类及其对象。
Proxy类的静态方法(了解)
// 方法 1: 该方法用于获取指定代理对象所关联的调用处理器
static InvocationHandler getInvocationHandler(Object proxy)
// 方法 2:该方法用于获取关联于指定类装载器和一组接口的动态代理类的类对象
static Class getProxyClass(ClassLoader loader, Class[] interfaces)
// 方法 3:该方法用于判断指定类对象是否是一个动态代理类
static boolean isProxyClass(Class cl)
// 方法 4:该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
static Object newProxyInstance(ClassLoader loader, Class[] interfaces,
InvocationHandler h)
重点关注newProxyInstance
这三个参数非常重要
Spring Aop也是使用这个机制
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces, InvocationHandler h)
throws IllegalArgumentException
注意该方法是在Proxy类中是静态方法,且接收的三个参数依次为: ClassLoader
- loader, :指定当前目标对象使用类加载器 ;负责将类的字节码装载到 Java 虚拟机 (JVM)中并为其定义类对象
- Class<?>[] interfaces, :目标对象实现的接口的类型,使用泛型方式确认类型
- InvocationHandler h :事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行 目标对象的方法作为参数传入
2)调用处理器接口回顾
java.lang.reflect.InvocationHandler
这是调用处理器接口,它自定义了一个 invoke 方法(只有一个)
用于集中处理在动态代理类对象上的方法调用,通常在该方法中实现对目标类的代理访问。
每次生成动态代理类对象时都要指定一个对应的调用处理器对象。
1、目标对象(委托类)通过jdk的Proxy生成了代理对象、
2、客户端访问代理对象,代理对象通过调用于处理器接口反射调用了目标对象方法
InvocationHandler的核心方法
仅仅一个方法
public interface InvocationHandler {
//第一个参数既是代理类实例
//第二个参数是被调用的方法对象
// 第三个方法是调用参数
Object invoke(Object proxy, Method method, Object[] args)
}
3)动态代理代码编写
沿用上面的 例子
代理对象不需要实现接口(业务),但是目标对象一定要实现接口,否则不能用动态代理
接口
目标对象接口
//动态代理实现
public class DynamicProxy implements InvocationHandler {
// 这个就是我们要代理的真实对象
private Object obj;
// 构造方法,给我们要代理的真实对象赋初值
public DynamicProxy(Object object) {
this.obj = object;
}
//相比静态代理,动态代理减只需要实现一个接口即可完成,而静态代理每次都要实现新加的方法以及维护被代理方法
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//********************方法前增强***************************
// 反射调用目标方法
return method.invoke(obj, args);
// return null;
//********************方法后增强***************************
}
}
测试
//动态代理测试
//目标:
//1、知道如何创建动态代理
//2、如何调用了invoke方法(拦截方法会用到当前知识点)
public class Test {
public static void main(String[] args) {
// 目标对象;要代理的真实对象
IStartBusiness target = new StartBusinessImpl();
// 我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的
InvocationHandler handler = new DynamicProxy(target);
/*
* 第一个参数:目标对象加载器
* 第二个参数:目标对象接口
* 第三个参数:实现InvocationHandler的代理类
*/
//生成代理对象
//目标:
//1、知道如何创建动态代理(源码中用到)
//2、如何调用了invoke方法(源码中用到)
IStartBusiness iStartBusiness = (IStartBusiness) Proxy.newProxyInstance(target.getClass().getClassLoader(), target
.getClass().getInterfaces(), handler);
iStartBusiness.sing();
}
}
总结
1、相比静态代理,动态代理减只需要实现一个接口即可完成,而静态代理每次都要实现新加的方法以及维护被代理方法
2、动态代理是靠Proxy.newProxyInstance() 生成的
3、动态代理在调用(iStartBusiness.sing())的时候,调用到了 implements InvocationHandler 的invoke
目标明确了:spring的代理就需要我们找到 Proxy.newProxyInstance() 在哪里……
4)动态代理原理(了解)
https://www.baiyp.ren/JAVA%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90.html
总结
容器启动:代理类怎么创建的,代理模式,动态代理
bean创建,doCreateBean(){
1.创建对象
2.放三级缓存
3.复制-对象完整了
4.BeanPostProcessor,aop代理对象(增强操作)
return bean
}
服务调用:切面方法怎么被执行的,责任链模式
aspect
切面方法:before after around…
业务方法前后,进行增强
invoke,植入的