一、在applicationContext的beanFactory.preInstantiateSingletons方法中,会初始化所有的单例BEAN.

二、

1.AbstractAutowireCapableBeanFactory.doCreateBean在调用BEAN默认构造函数反射生成实例对象后,会populateBean填充属性,
2.如果属性是通过AUTOWIRED或者RESOURCE依赖注入时,则会触发CommonAnnotationBeanPostProcessor的处理器,此处理器会再次去BEAN工厂获取属性BEAN,不存在则再次调用createBean创建。

3.在实例化完属性对象后,会调用AbstractAutowireCapableBeanFactory.initializeBean再次对BEAN进行后置处理,

4.然后又会调用AnnotationAwareAspectJAutoProxyCreator.postProcessAfterInitialization对BEAN对象进行修改。

5.最后调用AbstractAutoProxyCreator.createProxy创建代理对象。此函数创建代理对象时会传入所有当前系统注册的切面注入到代理对象,ExposeInvocationInterceptor--这个是系统默认的拦截对象。

三、实际生成cglib/jdk proxy object,的流程。

1.接上面最后一步,在public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport这个类中,会调用createAopProxy().getProxy(classLoader)

2.createAopProxy()会调用getAopProxyFactory().createAopProxy(this);这个接口返回的对象为

AopProxy,有两种实现,分为CglibAopProxy,JdkDynamicAopProxy

getAopProxyFactory为DefaultAopProxyFactory

3.CglibAopProxy的getProxy接口来生成实际的CGLIB或者 JDK代理类。生成代理类中会设置一系列的callback
就是拦截器,也就是系统容器中定义的通知处理方法(如执行前,执行后,环绕,返回前,抛出异常前)。
package com.tpw.newday.aspect;import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.tpw.newday.annation.CacheProcesser;
import com.tpw.newday.common.MyConstants;
import com.tpw.newday.redis.RedisParam;
import com.tpw.newday.redis.RedisService;
import com.tpw.newday.utils.RedisUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;import java.lang.reflect.Method;/*** <h3>newday</h3>* <p>xx</p>** @author : lipengyao* @date : 2021-04-30 15:56:19**/
@Aspect
@Component
public class CacheAspect {private static final Log logger = LogFactory.getLog(CacheAspect.class);private RedisUtil redisUtil = new RedisUtil(MyConstants.redis_host_ip,MyConstants.redis_port,MyConstants.redis_password);@Autowiredprivate RedisService redisService;@Pointcut("execution(* com.tpw.newday.service..*.*(..)))")private void cacheMethod() {}/*** 前置通知:在目标方法执行前调用*/@Before("cacheMethod()")public void begin() {logger.info("==@Before== lipy cache method : begin");}/*** 后置通知:在目标方法执行后调用,若目标方法出现异常,则不执行*/@AfterReturning("cacheMethod()")public void afterReturning() {logger.info("==@AfterReturning== lipy cache method : after returning");}/*** 后置/最终通知:无论目标方法在执行过程中出现一场都会在它之后调用*/@After("cacheMethod()")public void after() {logger.info("==@After== lipy cache method : finally returning");}/*** 异常通知:目标方法抛出异常时执行*/@AfterThrowing("cacheMethod()")public void afterThrowing() {logger.info("==@AfterThrowing==  lipy cache method : after throwing");}/*** 环绕通知:灵活自由的在目标方法中切入代码*/@Around("cacheMethod()")public Object around(ProceedingJoinPoint joinPoint) throws Throwable {// 获取目标方法的名称String methodName = joinPoint.getSignature().getName();// 获取方法传入参数Object[] params = joinPoint.getArgs();logger.info("==@Around== lipy cache method --》 method name " + methodName + " args " + params[0]);return handleMethod(joinPoint);}/*** 获取redis的key*/private String parseKey(String fieldKey, Method method, Object[] args) {//获取被拦截方法参数名列表(使用Spring支持类库)LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();String[] paraNameArr = u.getParameterNames(method);//使用SPEL进行key的解析ExpressionParser parser = new SpelExpressionParser();//SPEL上下文StandardEvaluationContext context = new StandardEvaluationContext();//把方法参数放入SPEL上下文中for (int i = 0; i < paraNameArr.length; i++) {context.setVariable(paraNameArr[i], args[i]);}String key= parser.parseExpression(fieldKey).getValue(context, String.class);return  key;}/*** 获取方法中声明的注解** @param joinPoint* @return* @throws NoSuchMethodException*/public Object handleMethod(ProceedingJoinPoint joinPoint) throws Throwable {// 获取方法名String methodName = joinPoint.getSignature().getName();// 反射获取目标类Class<?> targetClass = joinPoint.getTarget().getClass();// 拿到方法对应的参数类型Class<?>[] parameterTypes = ((MethodSignature) joinPoint.getSignature()).getParameterTypes();// 根据类、方法、参数类型(重载)获取到方法的具体信息Method objMethod = targetClass.getMethod(methodName, parameterTypes);// 获取方法传入参数Object[] params = joinPoint.getArgs();// 拿到方法定义的注解信息CacheProcesser annotation = objMethod.getDeclaredAnnotation(CacheProcesser.class);if (ObjectUtil.isNull(annotation)){// 执行源方法return joinPoint.proceed();}if (annotation.cacheOperation() == CacheProcesser.CacheOperation.QUERY){String cacheKey = annotation.key()+ ":"+this.parseKey(annotation.fieldKey(),objMethod ,params );RedisParam redisParam = new RedisParam(cacheKey,annotation.expireTime());Object cacheResult = redisService.get(redisParam);if (ObjectUtil.isNotNull(cacheResult)){logger.info(" get from cache key:" + cacheKey);return cacheResult;}else{Object obj = joinPoint.proceed();redisService.set(redisParam,obj );logger.info(" call method,set to  cache key:" + cacheKey);return  obj;}}else if (annotation.cacheOperation() == CacheProcesser.CacheOperation.UPDATE ||annotation.cacheOperation() == CacheProcesser.CacheOperation.DELETE ){Object obj = joinPoint.proceed();String cacheKey = annotation.key()+ ":"+this.parseKey(annotation.fieldKey(),objMethod ,params );RedisParam redisParam = new RedisParam(cacheKey,annotation.expireTime());logger.info(" delete from cache key:" + cacheKey);redisService.remove(redisParam);return  obj;}return  joinPoint.proceed();}
}

4.最终把cglib或者JDK生成的代理类注入到属性中,或者返回给创建者。

四、最终HTTP请求调用过时,调用服务类接口时,首先会调用到代理类的方法。

1.上述接口会先调用DynamicAdvisedInterceptor.intercept方法,此接口实现了cglib的

MethodInterceptor方法,会被CGLIB反向调用。

2.上述方法内会调用 retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(), CglibMethodInvocation 会继承于 ReflectiveMethodInvocation,最终触发到

ReflectiveMethodInvocation.proceed()

3.ReflectiveMethodInvocation内有一个拦截器数组interceptorsAndDynamicMethodMatchers,存储了所有的切面方法,会根据索引逐个调用,拦截器内部又会再次调用此对象的ReflectiveMethodInvocation.proceed,调到下一个拦截器,

拦截器列表:

4.如果拦截器调用完,则会调用最终的methodProxy方法。

spring service ,controller反向代理生成AOP代理类流程相关推荐

  1. spring源码深度解析---创建AOP代理之获取增强器

    spring源码深度解析-创建AOP代理之获取增强器 在上一篇的博文中我们讲解了通过自定义配置完成了对AnnotationAwareAspectJAutoProxyCreator类型的自动注册,那么这 ...

  2. 查看动态代理生成的代理类字节码

    文章目录 动态代理的知识介绍 用java proxy实现动态代理 查看生成的class代理类字节码 创建代理的源码 动态代理的知识介绍 一.动态代理和Class字节码的关系 动态代理有什么作用及应用场 ...

  3. 填坑之动态代理生成的代理类文件在哪?

    初衷 最近想研究研究Mybatis源码,了解一下Mybatis的执行过程,从mybatis-config.xml配置文件开始,一直到Mybatis执行CRUD位置,中途出现很多疑惑,今天特记录一个! ...

  4. AOP的实现原理 —— 静态代理 和 动态代理( Spring AOP)

    文章目录 一.AOP是什么? 二.静态代理 -- AspectJ 2.1.举例说明 三. 动态代理 3.1.JDK 动态代理 3.1.1. 核心类: 3.1.2. 示例1--JDK动态代理 3.2.C ...

  5. (转)java动态代理与aop

    转自: Java 动态代理与AOP - 如果的事 - 博客园动态代理与AOP 代理模式 代理模式给某一个目标对象(target)提供代理对象(proxy),并由代理对象控制对target对象的引用. ...

  6. 两万字吐血总结,代理模式及手写实现动态代理(aop原理,基于jdk动态代理)

    代理模式及手写实现动态代理 一.代理模式 1. 定义 2. 示例 (1)静态代理 (2)动态代理 3. 通用类图 4. 代理模式的优点 二.jdk动态代理实现原理 1. jdk动态代理源码分析(通过该 ...

  7. Spring学习8-Spring事务管理(AOP/声明式式事务管理)

    一.基础知识普及 声明式事务的事务属性: 一:传播行为 二:隔离级别 三:只读提示 四:事务超时间隔 五:异常:指定除去RuntimeException其他回滚异常.  传播行为: 所谓事务的传播行为 ...

  8. 4、MyBatis + Log4j日志查看Sql参数、结果集元数据、Mapper代理开发、JDK的动态代理与CGLib代理

    文章目录 MyBatis优化开发 日志 ResultSet如何转换为Java对象 数据库元数据 结果集元数据 Fastjson 基于MyBatis的DAO开发(传统) 推荐mapper代理开发 JDK ...

  9. Spring基础专题——第五章(Aop代理)

    前言:去年到现在一直没有很好的时间完成这个spring基础+源码的博客目标,去年一年比较懒吧,所以今年我希望我的知识可以分享给正在奋斗中的互联网开发人员,以及未来想往架构师上走的道友们我们一起进步,从 ...

最新文章

  1. git配置报错fatal: Authentication failed for ‘‘问题解决
  2. esjava 同步mysql_Elasticsearch和mysql数据同步(elasticsearch-jdbc)
  3. oracle定时加载文件,采用sqlldr定时将文本文件加载进入数据库
  4. 【AI视野·今日Robot 机器人论文速览 第十一期】Mon, 21 Jun 2021
  5. MFC多线程的创建,包括工作线程和用户界面线程
  6. 80行代码使用Python+tkinter实现一个计算器
  7. 发现孩子做作业用计算机,儿童不宜长期使用计算器做作业
  8. django基础篇01-环境的搭建和项目的创建
  9. ios appstore 上架应用被拒绝原因
  10. OpenCV 学习笔记(mean shift 算法)
  11. 25种提高网页加载速度的方法和技巧
  12. Ink脚本语言学习笔记(二)
  13. 自学MBA,我推荐你看这本《MBA必读12篇》
  14. 算法笔记(18)数据升维及Python代码实现
  15. 解决paramiko.ssh_exception.SSHException: Error reading SSH protocol banner问题
  16. 微信小程序超级占内存_手机APP占内存?4款超赞的微信小程序,不用下载,拿去即可使用!...
  17. 内存快速分配和慢速分配
  18. 【百人计划】图形4.1 Bloom算法
  19. 压缩图片(java)
  20. 开发板ARM加FPGA架构运动控制卡 运动控制器 架构源码 原理图 资料包含此运动控制卡原理图,PCB图

热门文章

  1. ABAP SAP 程序放在哪个库表中
  2. OO实现ALV TABLE 十一:ALV的聚合,排序,过滤
  3. AgilePoint商业流程管理平台
  4. “后完美日记”时代,橘朵、花知晓、funnyelves们还有机会吗?
  5. 数据数组赋值_嵌入式-数组赋值
  6. 荣耀手机现在可以升级鸿蒙系统吗,鸿蒙系统升级名单正式公布,华为手机90%能升,荣耀手机却有点意外...
  7. pydroid3怎么保存_pydroid3
  8. php mysql ajax 分页_ajax+php+mysql无刷新分页代码(1/2)_PHP教程
  9. 12c集群日志位置_Oracle 19C RAC 集群日志位置变化
  10. mysql开源内库_将内裤穿在外面的男人(mysql)