今日快讯:Spring源码核心剖析
2023-06-21 11:19:29来源:博客园
SpringAOP作为Spring最核心的能力之一,其重要性不言而喻。然后需要知道的是AOP并不只是Spring特有的功能,而是一种思想,一种通用的功能。而SpringAOP只是在AOP的基础上将能力集成到SpringIOC中,使其作为bean的一种,从而我们能够很方便的进行使用。
(资料图)
一、SpringAOP的使用方式1.1 使用场景当我们在日常业务开发中,例如有些功能模块是通用的(日志、权限等),或者我们需要在某些功能前后去做一些增强,例如在某些方法执行后发送一条mq消息等。
如果我们将这些通用模块代码与业务代码放在一块,那么每个业务代码都要写这些通用模块,维护成本与耦合情况都十分严重。
因此,我们可以将此模块抽象出来,就有了”切面“的概念。
1.2 常用方式AOP的使用方式相对比较简单,首先我们需要完成业务代码
@Servicepublic class AopDemo implements AopInterface{ public Student start(String name) { System.out.println("执行业务逻辑代码....."); return new Student(name); }}
业务逻辑比较简单,接收一个name参数。
接下来我们需要创建其对应的切面
//将该切面加入spring容器@Service//声明该类为一个切面@Aspectclass AopAspect { //声明要进行代理的方法 @Pointcut("execution(* com.example.demo.aop.AopInterface.start(..))") public void startAspect() { } //在方法执行之前的逻辑 @Before(value = "startAspect()") public void beforeAspect() { System.out.println("业务逻辑前代码....."); } //在方法执行之后的逻辑 @After(value = "startAspect()") public void afterAspect() { System.out.println("业务逻辑后代码....."); } //围绕方法前后的逻辑 @Around("startAspect()") public Object aroundAspect(ProceedingJoinPoint point) throws Throwable { Object[] requestParams = point.getArgs(); String name = requestParams[0].toString(); System.out.println("传入参数:" + name); requestParams[0] = "bob"; return point.proceed(requestParams); }}
可以看到,首先需要我们指明要代理的对象及方法,然后根据需要选择不同的注解即可实现代理对象。
传入参数:tom业务逻辑前代码.....执行业务逻辑代码.....业务逻辑后代码.....
二、SpringAOP源码解析2.1 被代理对象的开始initializeBean根据上面的使用情况,我们知道只需要声明对应的注解即可,不需要其他额外的配置,然后我们获得的bean对象就已经是被代理的了,那么我们可以推断代理对象的过程一定是发生在bean创建的过程的。
我们回顾一下创建bean的流程
实例化bean装配属性初始化bean只有第三步初始化bean的时候才会有机会进行代理。
找到对应的代码位置:
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) { Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { //前置处理器 wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } //... try { //对象的初始化方法 invokeInitMethods(beanName, wrappedBean, mbd); } if (mbd == null || !mbd.isSynthetic()) { //后置处理器,AOP开始的地方 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean;}
2.2 后置处理器applyBeanPostProcessorsAfterInitialization后置处理器会执行那些实现了后置处理器接口的代码:
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; //获取所有的后置处理器 for (BeanPostProcessor processor : getBeanPostProcessors()) { //实现其要执行的方法 Object current = processor.postProcessAfterInitialization(result, beanName); if (current == null) { return result; } result = current; } return result;}
而AOP的后置处理器就是其中的一个: AbstractAutoProxyCreator
其对应的方法为(以下代码不为同一个类,而是对应的执行顺序):
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (this.earlyProxyReferences.remove(cacheKey) != bean) { //执行到下面方法 return wrapIfNecessary(bean, beanName, cacheKey); } } return bean;}protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {// Create proxy if we have advice.Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);if (specificInterceptors != DO_NOT_PROXY) {this.advisedBeans.put(cacheKey, Boolean.TRUE); //创建代理对象Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));this.proxyTypes.put(cacheKey, proxy.getClass());return proxy;}this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;}protected Object createProxy(Class beanClass, @Nullable String beanName,@Nullable Object[] specificInterceptors, TargetSource targetSource) {//获取advisorsAdvisor[] advisors = buildAdvisors(beanName, specificInterceptors);proxyFactory.addAdvisors(advisors);proxyFactory.setTargetSource(targetSource);customizeProxyFactory(proxyFactory);proxyFactory.setFrozen(this.freezeProxy);if (advisorsPreFiltered()) {proxyFactory.setPreFiltered(true);}// Use original ClassLoader if bean class not locally loaded in overriding class loaderClassLoader classLoader = getProxyClassLoader();if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) {classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();} //通过代理工厂创建代理对象return proxyFactory.getProxy(classLoader);}public Object getProxy(@Nullable ClassLoader classLoader) { //首先获取对应的代理return createAopProxy().getProxy(classLoader);}//该方法根据要被代理的类选择使用jdk代理还是cglib代理public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {if (!NativeDetector.inNativeImage() &&(config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) {Class targetClass = config.getTargetClass(); //如果被代理的类是一个接口则使用jdk代理if (targetClass.isInterface() || Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) {return new JdkDynamicAopProxy(config);} //否则使用cglib代理return new ObjenesisCglibAopProxy(config);}else { //根据配置选择强制使用jdk代理return new JdkDynamicAopProxy(config);}}
我们知道,代理方式有jdk动态代理与cglib动态代理两种方式,而我们一个bean使用那种代理方式则由上述的方法决定。
至此,我们已经确定了使用那种代理方式获取代理对象。
2.3 获取代理对象从上文中,我们已经确定了选用何种方式构建代理对象。接下来就是通过不同的方式是如何获取代理对象的。
看懂本章需要实现了解jdk动态代理或者cglib动态代理的方式。
2.3.1 JDK代理首先在获取代理对象时选择 JdkDynamicAopProxy
public Object getProxy(@Nullable ClassLoader classLoader) { if (logger.isTraceEnabled()) { logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource()); } //这里通过反射创建代理对象 return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this);}
当被代理对象执行被代理的方法时,会进入到此方法。(jdk动态代理的概念)
JDK通过反射创建对象,效率上来说相对低一些。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {// 获取被代理对象的所有切入点List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);// 如果调用链路为空说明没有需要执行的切入点,直接执行对应的方法即可if (chain.isEmpty()) {// We can skip creating a MethodInvocation: just invoke the target directly// Note that the final invoker must be an InvokerInterceptor so we know it does// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);}else {// 如果有切入点的话则按照切入点顺序开始执行MethodInvocation invocation =new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);// Proceed to the joinpoint through the interceptor chain.retVal = invocation.proceed();}return retVal;}}
invocation.proceed();这个方法就是通过递归的方式执行所有的调用链路。
public Object proceed() throws Throwable { // We start with an index of -1 and increment early. if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return invokeJoinpoint(); } Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; Class targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass()); if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) { return dm.interceptor.invoke(this); } else { // 继续执行 return proceed(); } } else { // 如果调用链路还持续的话,下一个方法仍会调用proceed() return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); }}
2.3.2 cglib代理public Object getProxy(@Nullable ClassLoader classLoader) { try { //配置CGLIB Enhancer... Enhancer enhancer = createEnhancer(); if (classLoader != null) { enhancer.setClassLoader(classLoader); if (classLoader instanceof SmartClassLoader && ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) { enhancer.setUseCache(false); } } enhancer.setSuperclass(proxySuperClass); enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised)); enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE); enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader)); //1.获取回调函数,对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法 Callback[] callbacks = getCallbacks(rootClass); Class[] types = new Class[callbacks.length]; for (int x = 0; x < types.length; x++) { types[x] = callbacks[x].getClass(); } // fixedInterceptorMap only populated at this point, after getCallbacks call above enhancer.setCallbackFilter(new ProxyCallbackFilter( this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset)); enhancer.setCallbackTypes(types); //2.创建代理对象 return createProxyClassAndInstance(enhancer, callbacks); } catch (CodeGenerationException | IllegalArgumentException ex) { throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() + ": Common causes of this problem include using a final class or a non-visible class", ex); } catch (Throwable ex) { // TargetSource.getTarget() failed throw new AopConfigException("Unexpected AOP exception", ex); }}
可以看到我们在创建代理对象前会先获取代理对象的所有回调函数:
首先可以看到我们一共有7个回调方法,其中第一个为AOP相关的方法,其他的为spring相关。
在第一个对调对象中持有的 advised 对象中有 advisors 属性,就是对应我们的代理类中四个切片,@Before等等。
然后我们看一下 createProxyClassAndInstance()都做了什么。
//CglibAopProxy类的创建代理对象方法protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) { enhancer.setInterceptDuringConstruction(false); enhancer.setCallbacks(callbacks); return (this.constructorArgs != null && this.constructorArgTypes != null ? enhancer.create(this.constructorArgTypes, this.constructorArgs) : enhancer.create());}//ObjenesisCglibAopProxy继承了CglibAopProxy类,并覆写了其方法protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {Class proxyClass = enhancer.createClass();Object proxyInstance = null; //1.尝试使用objenesis创建对象if (objenesis.isWorthTrying()) {try {proxyInstance = objenesis.newInstance(proxyClass, enhancer.getUseCache());}catch (Throwable ex) {logger.debug("Unable to instantiate proxy using Objenesis, " +"falling back to regular proxy construction", ex);}} //2.根据commit的提交记录发现,objenesis有可能创建对象失败,如果失败的话则选用放射的方式创建对象if (proxyInstance == null) {// Regular instantiation via default constructor...try {Constructor ctor = (this.constructorArgs != null ?proxyClass.getDeclaredConstructor(this.constructorArgTypes) :proxyClass.getDeclaredConstructor());ReflectionUtils.makeAccessible(ctor);proxyInstance = (this.constructorArgs != null ?ctor.newInstance(this.constructorArgs) : ctor.newInstance());}catch (Throwable ex) {throw new AopConfigException("Unable to instantiate proxy using Objenesis, " +"and regular proxy instantiation via default constructor fails as well", ex);}} //((Factory) proxyInstance).setCallbacks(callbacks);return proxyInstance;}
2.3.3 cglib此处有个遇到的问题,当我在debug的时候,发现怎么都进不去 createProxyClassAndInstance(),百思不得其解,然后看到IDEA旁边有一个向下的箭头,代表该方法可能其子类被覆写了。然后在其子类处打断点果然发现是其子类的实现。
此处在2.2中也可看到:
可以看到返回的是其子类的对象,而不是CglibAopProxy本身的对象。
作者:京东科技 韩国凯
来源:京东云开发者社区
标签:
责任编辑:hnmd003
相关阅读
-
世界今日报丨5.75余亿元、客服接单量第一、孵化企业143家……海洋职教的双创特色为乡村振兴充“电”蓄能
5 75余亿元、客服接单量第一、孵化企业143家……海洋职教的双创特色为
2023-06-21
阅读排行
资讯播报
- 电视剧《琅琊榜》飞流是什么身份...
- 端午送“艾” 绿都物业人登山采艾叶
- 端午节给爸妈送健康 优选纽瑞健...
- 电视剧《锋刃》沈西林是黄渤饰演...
- 国乒开展“当粉丝遇见偶像”专题...
- 11年后广州剑客又出一条“好汉”
- 【时快讯】中国男足主帅扬科维奇...
- 亚洲藤球运动员浙江金华开赛 竞...
- 武磊追平国足队史头号射手进球纪录
- 再获世界亚军 中国轮椅女篮创世...
- 2023中国国际羽毛球挑战赛开赛 ...
- 2023年度中马协赛事企划营运高级...
- 两部门部署加强用人单位防暑降温...
- 焦点热议:浙江东阳城东街道寀卢...
- JBL TUNE BUDS 琉璃豆、J...
- “真想好好给医院写封感谢信”(...
- 复盘生活家地板全民恋家节,情感...
- 每日快播:生物中心组织召开“十...
- 甘肃省已建成戈壁设施农业40万亩...
- 中美将于何时增加航班数量?外交...
- 【世界聚看点】人民网评:“互联...
- 打通海上智慧油田的“信息大动脉”
- 当前最新:(成都大运纪事)科技...
- 展示新西藏 共谋新发展
- 今日热议:回收站图标显示不正常...
- 完美公司胡瑞连:制定“完美”标...
- 今日要闻!国家能源局局长章建华...
- 迈入强人工智能“长虹超脑”全球...
- 小米专利曝光:环形曲面屏、屏下...
- 我国已沦为美国第4大贸易伙伴,...
- 硬核快报 | 如何客观评价智能...
- 全球快讯:禁情仔仔秀儿笔趣阁_禁...
- 终结清华“三连冠”,广工是如何...
- 天天热文:净利润下滑逾八成后,...
- 【新时代 新征程 新伟业】垃圾...
- 贴心!社工进医院为民办实事-全...
- 天天观速讯丨“最美”解读:江浙...
- 氨基三甲叉膦酸商品报价动态(20...
- 浪里奔腾 奋“泳”前行——第十...
- 宜家使用 AI 设计可放入信封中...
- 一压定情在线阅读(一压定情)
- 两轮大范围强降雨来袭!高温“返...
- 五粮液也跨界光伏:1666万元投光...
- 每日快播:广东多地遭遇暴雨 最...
- 天天动态:每日看点!中国人寿的...
- 当前快播:金十数据整理:每日全...
- 《我的小尾巴》聂泽宁是谁的哥哥...
- 火狐浏览器 Firefox 114 启用...
- 网络用语中钝角是什么意思?钝角...
- 《雪中悍刀行》黄蛮儿是谁演的?...
- 焦点快报!腾讯云首次公开行业大...
- 【全球热闻】腾讯绿色征途还能玩...
- 快报:交流电源供应器6900_交流...
- 工人日报e网评丨“村超”“村BA...
- 世界关注:企业产品介绍类mg动画...
- 士农工商的工指哪些人_士农工商...
- 【环球快播报】成都大运会火炬传...
- 【全球新要闻】苏奥传感:DPF压...
- 新华网6月20日打开跌停 环球信息
- 复兴酃酒、振兴衡阳 新派酃酒00...
- 首战告捷,意大利专业女性健康品...
- 我国天文学家建立星系批量高精度...
- 安卓手机如何省电华为(安卓手机...
- 世界速看:国城矿业(000688.SZ)...
- 什么叫力的定义
- 【世界速看料】房贷降息!每月可...
- 世界讯息:长沙市天心区启动防汛...
- 普尔留队!格林成为自由球员!他...
- hpv16阳性怎么治疗_hpv16阳性几年得癌症
- 房贷降息:首套房利率下限降至4....
- 宁波财税网上申报(宁波市财税网
- 世界观热点:午评:指数在市场内...
- 雅创电子:6月19日融券卖出6600...
- 每日资讯:呼伦贝尔市气象台发布...
- 最新消息:万润科技6月20日快速上涨
- 视频丨5年期以上LPR下降10个基点...
- 天天日报丨阵发性心房颤动是什么...
- 福建省生态环境项目成果发布会举...
- 奋达科技:6月19日融资买入2100....
- 美民调:超半数美国非裔认为种族...
- 新华时评:拒绝过度包装,让粽子...
- 新华全媒+|探访国内首条跨海高...
- 以下属于环境监测的对象的是_环...
- 暴雨、雷电、大风,入梅后最强降...
- 环球快看:人民网评:备战电力迎...
- 天天热文:暑期旅游热潮来了
- 世界信息:U17亚洲杯丨杨晨:最后...
- 今亮点!林中鸟歌词莫问 林中鸟歌词
- 防范非法集资月|平安人寿上海分...
- 开封市通许县四所楼镇:精准施策...
- 混凝土取芯强度不够怎么办
- 劳动竞赛, 彰显技能,保质量提进度
- 鼠标右键不好使和服务有关系么_...
- 继承遗产房产要交多少钱|百事通
- 最新消息:产业帮扶“扶上马再送...
- 确山:“五路”并进 助力乡村振...
- “千万工程”调研行丨扮靓海上花...
- 焦点资讯:售18.99万~25.99万元...
- 乡村振兴要摆脱流量误区 全球焦点
- “两业融合”塑造竞争新优势(人...