https://liayun.blog.csdn.net/article/details/110670961
1、@Bean注解中使用init-method属性和destroy-method属性来指定初始化方法和销毁方法。
你有没有想过这样一个问题,初始化方法和销毁方法是在什么时候被调用的啊?
多实例bean的生命周期不归Spring容器来管理,这里的DisposableBean接口中的方法是由Spring容器来调用的,所以如果一个多实例bean实现了DisposableBean接口是没有啥意义的,因为相应的方法根本不会被调用,当然了,在XML配置文件中指定了destroy方法,也是没有任何意义的。所以,在多实例bean情况下,Spring是不会自动调用bean的销毁方法的。
Spring中提供了一个InitializingBean接口,该接口为bean提供了属性初始化后的处理方法,它只包括afterPropertiesSet方法,凡是继承该接口的类,在bean的属性初始化后都会执行该方法。
//@Component public class Cat implements InitializingBean, DisposableBean { public Cat(){ System.out.println("Cat...constructor...构造器"); } @Override public void destroy() throws Exception { System.out.println("Cat...destroy...."); } @Override public void afterPropertiesSet() throws Exception { System.out.println("Cat...afterPropertiesSet..."); } }
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd) throws Throwable { boolean isInitializingBean = (bean instanceof InitializingBean); if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) { if (logger.isTraceEnabled()) { logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'"); } if (System.getSecurityManager() != null) { try { AccessController.doPrivileged((PrivilegedExceptionAction) () -> { ((InitializingBean) bean).afterPropertiesSet(); return null; }, getAccessControlContext()); } catch (PrivilegedActionException pae) { throw pae.getException(); } } else { ((InitializingBean) bean).afterPropertiesSet(); } } if (mbd != null && bean.getClass() != NullBean.class) { String initMethodName = mbd.getInitMethodName(); if (StringUtils.hasLength(initMethodName) && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) && !mbd.isExternallyManagedInitMethod(initMethodName)) { invokeCustomInitMethod(beanName, bean, mbd); } } } 分析上述代码后,我们可以初步得出如下信息: 1、Spring为bean提供了两种初始化的方式,实现InitializingBean接口(也就是要实现该接口中的afterPropertiesSet方法),或者在配置文件或@Bean注解中通过init-method来指定,两种方式可以同时使用。 2、实现InitializingBean接口是直接调用afterPropertiesSet()方法,与通过反射调用init-method指定的方法相比,效率相对来说要高点。但是init-method方式消除了对Spring的依赖。 3、如果调用afterPropertiesSet方法时出错,那么就不会调用init-method指定的方法了。 小结 也就是说Spring为bean提供了两种初始化的方式,第一种方式是实现InitializingBean接口(也就是要实现该接口中的afterPropertiesSet方法),第二种方式是在配置文件或@Bean注解中通过init-method来指定,这两种方式可以同时使用,同时使用先调用afterPropertiesSet方法,后执行init-method指定的方法。 * 在Spring容器创建完成时,会自动调用单实例bean的构造方法,对单实例bean进行了实例化操作。 * * 多实例的bean在容器关闭的时候是不进行销毁的,也就是说你每次获取时,IOC容器帮你创建出对象交还给你, * 至于要什么时候销毁这是你自己的事,Spring容器压根就不会再管理这些多实例的bean了。 * * 单实例:在容器启动的时候创建对象; * 多实例:在每次获取的时候创建对象; * * 初始化: * 对象创建好,并赋值好,调用初始化方法; * * 销毁: * 单实例:容器关闭的时候; * 多实例:容器不会管理Bean,只是负责创建,容器不会调用销毁方法; * * 1、指定初始化和销毁的方法; * 2、通过Bean 实现InitializingBean和DisposableBean * InitializingBean(定义初始化逻辑) * DisposableBean(定义销毁逻辑) 2、@PostConstruct和@PreDestroy这俩注解 @PostConstruct:在bean创建完成并且属性赋值完成之后,来执行初始化方法 @PreDestroy:在容器销毁bean之前通知我们进行清理工作 //@Component public class Dog { private Cat cat; public Dog(){ System.out.println("dog...constructor..构造器"); } public Cat getCat() { return cat; } public void setCat(Cat cat) { this.cat = cat; } //对象创建赋值之后调用 @PostConstruct public void init(){ System.out.println("dog...@PostConstruct..."); } //容器移除对象之前 @PreDestroy public void destory(){ System.out.println("dog...@PreDestroy..."); } } 3、通过让bean实现BeanPostProcessor接口 @Component public class MyBeanPostProcessor implements BeanPostProcessor, Ordered { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessBeforeInitialization--->"+beanName+"--->"+bean); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessAfterInitialization--->"+beanName+"--->"+bean); return bean; } @Override public int getOrder() { return 3; } } 通过以上这四种方式,我们就可以对bean的整个生命周期进行控制: bean的实例化:调用bean的构造方法,我们可以在bean的无参构造方法中执行相应的逻辑。 bean的初始化:在初始化时,可以通过BeanPostProcessor的postProcessBeforeInitialization()方法和postProcessAfterInitialization()方法进行拦截,执行自定义的逻辑;通过@PostConstruct注解、InitializingBean和init-method来指定bean初始化前后执行的方法,在该方法中咱们可以执行自定义的逻辑。 bean的销毁:可以通过@PreDestroy注解、DisposableBean和destroy-method来指定bean在销毁前执行的方法,在该方法中咱们可以执行自定义的逻辑。 所以,通过上述四种方式,我们可以控制Spring中bean的整个生命周期。 BeanPostProcessor后置处理器作用 后置处理器可用于bean对象初始化前后进行逻辑增强。 Spring提供了BeanPostProcessor接口的很多实现类,例如AutowiredAnnotationBeanPostProcessor用于@Autowired注解的实现,AnnotationAwareAspectJAutoProxyCreator用于Spring AOP的动态代理等等。 除此之外,我们还可以自定义BeanPostProcessor接口的实现类,在其中写入咱们需要的逻辑。下面我会以AnnotationAwareAspectJAutoProxyCreator为例,简单说明一下后置处理器是怎样工作的。 我们都知道spring AOP的实现原理是动态代理,最终放入容器的是代理类的对象,而不是bean本身的对象,那么Spring是什么时候做到这一步的呢?就是在AnnotationAwareAspectJAutoProxyCreator后置处理器的postProcessAfterInitialization方法中,即bean对象初始化完成之后,后置处理器会判断该bean是否注册了切面,若是,则生成代理对象注入到容器中。这一部分的关键代码是在哪儿呢?我们定位到AbstractAutoProxyCreator抽象类中的postProcessAfterInitialization方法处便能看到了,如下所示。 这里请看:https://liayun.blog.csdn.net/article/details/110442093 这里是源码讲解。我这里直接拿过来结果吧。 在applyBeanPostProcessorsBeforeInitialization()方法中,会遍历所有BeanPostProcessor对象,然后依次执行所有BeanPostProcessor对象的postProcessBeforeInitialization()方法,一旦BeanPostProcessor对象的postProcessBeforeInitialization()方法返回null以后,则后面的BeanPostProcessor对象便不再执行了,而是直接退出for循环。这些都是我们看源码看到的。 看Spring源码,我们还看到了一个细节,在Spring中调用initializeBean()方法之前,还调用了populateBean()方法来为bean的属性赋值, 这在上面我也已经说过了。 这里数属性填充工作:那么是怎样工作的那? 就是调用populateBean()方法 经过上面的一系列的跟踪源码分析,我们可以将关键代码的调用过程使用如下伪代码表述出来。 populateBean(beanName, mbd, instanceWrapper); // 给bean进行属性赋值 initializeBean(beanName, exposedObject, mbd) { applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); invokeInitMethods(beanName, wrappedBean, mbd); // 执行自定义初始化 applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } 也就是说,在Spring中,调用initializeBean()方法之前,调用了populateBean()方法为bean的属性赋值,为bean的属性赋好值之后,再调用initializeBean()方法进行初始化。 在initializeBean()中,调用自定义的初始化方法(即invokeInitMethods())之前,调用了applyBeanPostProcessorsBeforeInitialization()方法,而在调用自定义的初始化方法之后,又调用了applyBeanPostProcessorsAfterInitialization()方法。至此,整个bean的初始化过程就这样结束了。 概述 如果我们现在自定义的组件中需要用到Spring底层的一些组件,比如ApplicationContext(IOC容器)、底层的BeanFactory等等,那么该怎么办呢?先说说自定义的组件中能不能用Spring底层的一些组件吧?既然都这样说了,那么肯定是能够的。 回到主题,自定义的组件要想使用Spring容器底层的一些组件,比如ApplicationContext(IOC容器)、底层的BeanFactory等等,那么只需要让自定义组件实现XxxAware接口即可。此时,Spring在创建对象的时候,会调用XxxAware接口中定义的方法注入相关的组件。 XxxAware接口概览 其实,我们之前使用过XxxAware接口,例如,我们之前创建的Dog类,就实现了ApplicationContextAware接口,Dog类的源码如下所示。 package com.meimeixia.bean; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; /** * ApplicationContextAwareProcessor这个类的作用是可以帮我们在组件里面注入IOC容器, * 怎么注入呢?我们想要IOC容器的话,比如我们这个Dog组件,只需要实现ApplicationContextAware接口就行 * * @author liayun * */ @Component public class Dog implements ApplicationContextAware { private ApplicationContext applicationContext; public Dog() { System.out.println("dog constructor..."); } // 在对象创建完成并且属性赋值完成之后调用 @PostConstruct public void init() { // 在这儿打个断点调试一下 System.out.println("dog...@PostConstruct..."); } // 在容器销毁(移除)对象之前调用 @PreDestroy public void destory() { System.out.println("dog...@PreDestroy..."); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { // 在这儿打个断点调试一下 // TODO Auto-generated method stub this.applicationContext = applicationContext; } } 从以上Dog类的源码中可以看出,实现ApplicationContextAware接口的话,需要实现setApplicationContext()方法。在IOC容器启动并创建Dog对象时,Spring会调用setApplicationContext()方法,并且会将ApplicationContext对象传入到setApplicationContext()方法中,我们只需要在Dog类中定义一个ApplicationContext类型的成员变量来接收setApplicationContext()方法中的参数,那么便可以在Dog类的其他方法中使用ApplicationContext对象了。 其实,在Spring中,类似于ApplicationContextAware接口的设计有很多,本质上,Spring中形如XxxAware这样的接口都继承了Aware接口,我们来看下Aware接口的源码,如下所示。 接下来,我们看看都有哪些接口继承了Aware接口,如下所示。 XxxAware接口案例 接下来,我们就挑选几个常用的XxxAware接口来简单的说明一下。 ApplicationContextAware接口使用的比较多,我们先来说说这个接口,通过ApplicationContextAware接口我们可以获取到IOC容器。 首先,我们创建一个Red类,它得实现ApplicationContextAware接口,并在实现的setApplicationContext()方法中将ApplicationContext输出,如下所示。 package com.meimeixia.bean; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; /** * 以Red类为例来讲解ApplicationContextAware接口、BeanNameAware接口以及EmbeddedValueResolverAware接口 * @author liayun * */ public class Red implements ApplicationContextAware { private ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { System.out.println("传入的IOC:" + applicationContext); this.applicationContext = applicationContext; } } 其实,我们也可以让Red类同时实现几个XxxAware接口,例如,使Red类再实现一个BeanNameAware接口,我们可以通过BeanNameAware接口获取到当前bean在Spring容器中的名称,如下所示。 package com.meimeixia.bean; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanNameAware; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; /** * 以Red类为例来讲解ApplicationContextAware接口、BeanNameAware接口以及EmbeddedValueResolverAware接口 * @author liayun * */ public class Red implements ApplicationContextAware, BeanNameAware { private ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { System.out.println("传入的IOC:" + applicationContext); this.applicationContext = applicationContext; } /** * 参数name:IOC容器创建当前对象时,为这个对象起的名字 */ @Override public void setBeanName(String name) { System.out.println("当前bean的名字:" + name); } } 当然了,我们可以再让Red类实现一个EmbeddedValueResolverAware接口,我们通过EmbeddedValueResolverAware接口能够获取到String值解析器,如下所示。 package com.meimeixia.bean; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanNameAware; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.EmbeddedValueResolverAware; import org.springframework.util.StringValueResolver; /** * 以Red类为例来讲解ApplicationContextAware接口、BeanNameAware接口以及EmbeddedValueResolverAware接口 * @author liayun * */ public class Red implements ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware { private ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { System.out.println("传入的IOC:" + applicationContext); this.applicationContext = applicationContext; } /** * 参数name:IOC容器创建当前对象时,为这个对象起的名字 */ @Override public void setBeanName(String name) { System.out.println("当前bean的名字:" + name); } /** * 参数resolver:IOC容器启动时会自动地将这个String值的解析器传递过来给我们 */ @Override public void setEmbeddedValueResolver(StringValueResolver resolver) { String resolveStringValue = resolver.resolveStringValue("你好,${os.name},我的年龄是#{20*18}"); System.out.println("解析的字符串:" + resolveStringValue); } } IOC容器启动时会自动地将String值的解析器(即StringValueResolver)传递过来给我们用,咱们可以用它来解析一些字符串,解析哪些字符串呢?比如包含#{}这样的字符串。我们可以看一下StringValueResolver类的源码,如下所示。 接着,我们需要在Red类上标注@Component注解将该类添加到IOC容器中,如下所示。 @Component public class Red implements ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware { 最后,运行IOCTest_Autowired类中的test02()方法,输出的结果信息如下所示。 XxxAware原理 XxxAware接口的底层原理是由XxxAwareProcessor实现类实现的,也就是说每一个XxxAware接口都有它自己对应的XxxAwareProcessor实现类。 例如,我们这里以ApplicationContextAware接口为例,ApplicationContextAware接口的底层原理就是由ApplicationContextAwareProcessor类实现的。从ApplicationContextAwareProcessor类的源码可以看出,其实现了BeanPostProcessor接口,本质上是一个后置处理器。 先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦 你可能感兴趣的:(面试,学习路线,阿里巴巴,android,前端,后端) 初识操作系统 曳渔 #JavaEEjava-eejava 目录一、操作系统的认识1、常见的操作系统:2、操作系统的两个基本功能:二、进程1、什么是进程(Process):2、进程的组成:3、进程的并发和并行执行:三、总结:一、操作系统的认识操作系统是⼀组做计算机资源管理的软件的统称。1、常见的操作系统:目前常见的操作系统有Windows系列、Unix系列、Linux系列、OSX系列、Android系列、iOS系列、鸿蒙等。·Windows是常见的个人电脑 Github 2024-07-12 Java开源项目日报Top10 老孙正经胡说 githubjava开源Github趋势分析开源项目PythonGolang 根据GithubTrendings的统计,今日(2024-07-12统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下:开发语言项目数量Java项目10Android开源轻量级流媒体前端创建周期:3158天开发语言:Java协议类型:GNUGeneralPublicLicensev3.0Star数量:28641个Fork数量:2896次关注人数:28641人贡献人数:312人Open 将 Windows 11 的 WSA (Windows Subsystem for Android)移植到 Windows 10:WSAPatch 以及最简单的方法:安装兆懿安卓模拟器 skywalk8163 操作系统windowsandroid WSA(WindowsSubsystemforAndroid)是微软为Windows11引入的一项功能,允许用户在Windows上运行Android应用程序。虽然WSA本身是为Windows11设计的,但有些用户希望在Windows10上实现类似的功能。先用"winver"命令看看windows版本,要求大于Windows1010.0.19045.2311,并且是专业版其次需要在BIOS中打开虚拟 Visual Studio Code打开远程服务器项目,打开服务器Android上百G源码,SSH免密连接方式 demodashi666 vscode服务器android VisualStudioCode打开远程服务器项目1,VisualStudioCode拓展中,安装远程插件RemoteDevelopment2,SSH免密连接,A电脑免密连接B,配置B电脑.ssh/authorized_keysA电脑的.ssh/id_rsa.pub中的公钥内容,放在B电脑.ssh/authorized_keys中3,VisualStudioCode左上方,远程资源管理器,选择SS 硅谷硬核Rasa课程、Rasa培训、Rasa面试系列之: Rasa 3.x Config StarSpaceNLP 面试职场和发展 ModelConfiguration配置文件定义了模型根据用户输入进行预测的组件和策略。recipe键允许不同类型的配置和模型架构。目前,只支持“default.v1”。语言键和管道键指定模型用于进行NLU预测的组件。Policys键定义了模型用于预测下一个操作的策略。如果您不知道要选择哪些组件或策略,可以使用建议的配置功能,这将推荐合理的默认设置。SuggestedConfig您可以将管道或策略 金三银四突围战:技术面试体系化备考指南 守护海洋的猫 面试职场和发展 为什么90%的求职者陷入「背了就忘」的死循环?春招季数据显示,72%的技术岗求职者因知识体系零散在二面被淘汰。本文将以系统化方法+可复用的开源工具,帮你构建真正有效的面试知识库。一、技术人备考的三大认知误区盲目追求题量典型症状:刷完LeetCode500题仍不会变通解题数据佐证:2023年上岸者中,83%采用模块化专题突破策略忽视知识关联错误案例:能解释MySQL索引原理,却说不出B+树在Redi DevOps落地实践点滴和踩坑记录-(1) xuhss_com 计算机devops运维计算机 优质资源分享学习路线指引(点击解锁)知识定位人群定位Python实战微信订餐小程序进阶级本课程是pythonflask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。Python量化交易实战入门级手把手带你打造一个易扩展、更安全、效率更高的量化交易系统记录初衷本人一直在从事企业内DevOps落地实践的工作,走了不少弯路,也努力在想办法解决面临的问题,期间也经历过不少人和事 26届进大厂计划——小红书后端实习面经 码间烟火录 后端面经后端 作者介绍浙江大学软件工程硕士生淘天后端研发工程师秋招斩获阿里、字节、快手、京东、美团等多个大厂研发ssp/sp持续分享秋招经验分享、高频八股问题、最新大厂面经、硬核技术干货……全网同号,欢迎关注1、【实习经历】在实习过程中是否遇到过技术难题?如果有,是如何分析和解决的?技术难题在高并发场景下,系统接口响应时间变长,数据库查询效率低下。分析与解决过程定位问题:通过日志分析和性能监控工具(如Artha ListView展示图片 太空漫步11 windows packagecom.example.myapplication5;importandroid.os.Bundle;importandroid.widget.ListView;importandroidx.appcompat.app.AppCompatActivity;importcom.example.adapter.ImageAdapter;importjava.util.ArrayList; Nacos 深度解析与实战指南:构建云原生微服务的核心枢纽 小小初霁 云原生微服务架构 1.Nacos简介Nacos(DynamicNamingandConfigurationService)是阿里巴巴开源的云原生平台核心组件,集服务发现、配置管理、动态DNS和服务元数据管理于一体,支持Kubernetes、SpringCloud、Dubbo等主流生态。其核心理念是帮助开发者快速构建弹性可扩展、高可用的微服务架构。核心优势:一站式解决方案:同时管理服务与配置,降低组件维护成本。多环境 出现 defineProps is a compiler macro and no longer needs to be imported. 解决方法 码农研究僧 BUGjavascriptBugVue3宏 目录1.问题所示2.原理分析3.解决方法1.问题所示执行前端代码的时候,出现如下问题:[@vue/compiler-sfc]definePropsisacompilermacroandnolongerneedstobeimported.[@vue/compiler-sfc]defineEmitsisacompilermacroandnolongerneedstobeimported.截图如下所示: 数据库高级面试题 后端 以下是一些数据库高级面试题及其答案:一、索引设计与优化解释MySQL中的索引类型及其应用场景。答案:主键索引:唯一标识每条记录,适用于主键列。唯一索引:保证索引列的值唯一,适用于需要唯一约束的列。普通索引:加速查询的普通索引,适用于一般的查询操作。联合索引:多个列组成的索引,适用于多个列的查询条件。全文索引:用于查找文本中的关键词,适用于文本搜索。-什么是索引的“最左前缀原则”?请举例说明。答案: 前端小食堂 | Day10 - 前端路由の时空裂隙 喵爪排序 前端 ️今日穿梭指南:两种维度の路由宇宙1.Hash模式:锚点の量子隧道//手动创建路由监听器window.addEventListener('hashchange',()=>{constpath=location.hash.slice(1)||'/';console.log('进入哈希宇宙:',path);renderComponent(path);});//编程式导航functionnavigate 前端流式输出深度解析:技术原理、实战应用与性能优化 斯~内克 前端网络前端性能优化 一、流式输出的革命性意义1.1传统数据加载的痛点白屏等待:根据Google核心性能指标统计,页面加载时间超过3秒会导致53%的用户流失内存压力:单次加载10MBJSON数据会使内存占用飙升300MB+响应延迟:金融行业实时行情系统要求数据延迟{renderTableRow(data);});3.2Server-SentEvents(SSE)//客户端consteventSource=newEven springboot中Webclient对象怎么禁止缓存、保证每次数据都属来源后端 阿里嘎多学长 springboot缓存数据库 在SpringBoot中,使用WebClient对象进行HTTP请求时,可以通过配置请求头来禁止缓存,确保每次请求都能从后端获取最新的数据。以下是一些常用的方法来实现这一目的:设置Cache-Control请求头:在发起请求时,可以设置Cache-Control请求头为no-cache,这会告诉服务器和任何中间缓存,不应使用缓存的响应来满足请求。WebClientwebClient=WebClie 深入探索 Dubbo:高效的 Java RPC 框架 Kale又菜又爱玩 dubbojavarpc 深入探索Dubbo:高效的JavaRPC框架随着微服务架构的流行,分布式系统中的服务间通信变得愈加复杂。Dubbo作为阿里巴巴开源的高性能JavaRPC框架,已成为开发高可用、高性能微服务架构的核心工具之一。本文将深入探讨Dubbo的核心特性、配置方法,以及如何利用Dubbo提供的高级功能来构建一个高效、可靠的分布式系统。什么是Dubbo?Dubbo是一个轻量级、高性能的JavaRPC框架,主要用 【前端进阶】Web Worker性能优化实战:解码10万条数据不卡顿 爱上大树的小猪 前端性能优化 为什么需要WebWorker?JavaScript是单线程语言,当处理大量数据(如解析10万条JSON数据)时,主线程会被阻塞,导致页面卡顿、无法响应点击事件。WebWorker是浏览器提供的多线程解决方案,可以将耗时任务放到后台执行,解放主线程!实战目标主线程流畅渲染,10万条数据解码不卡顿!代码案例与分步解析1.模拟10万条数据//生成10万条模拟数据functiongenerateMockD 面试基础---MySQL 分布式 ID 方案深度解析 WeiLai1112 mysqlvue.js MySQL分布式ID方案深度解析:UUID、自增ID与雪花算法引言在分布式系统中,生成全局唯一的ID是一个常见的需求。MySQL作为最流行的关系型数据库之一,如何在高并发、分布式环境下生成唯一ID是一个重要的技术挑战。本文将深入探讨MySQL分布式ID的生成方案,包括UUID、自增ID和雪花算法,结合实际项目案例和源码分析,帮助读者深入理解其实现原理。1.分布式ID的需求与挑战在分布式系统中,生成 android的广播详解,Android的Service和广播的讲解 任我说车 android的广播详解 前言:我们都知道Android的四大基本组件:Activity、ContentProvider、Service以及BroadcastReceiver,前面的两个我们在前几篇已经具体讲解了,今天这一天我们就把后两者的使用具体说一下,由于Service和BroadcastReceiver常常一起使用,所以我们一起来学习。一.Service的使用Service是Android系统的后台服务组件,没有用户 android 广播给指定app,封装一个广播工具类 —— AppReceiver 乔一帆丶 android广播给指定app ###前言在日常开发过程中,用得比较多的是手动注册方式的广播,为了方便广播的使用,我封装了一个手动注册的广播工具类——AppReceiver,这节就来讲讲它的使用吧。今天涉及的内容:1.手动注册广播一般使用流程2.封装类AppReceiver的基本介绍3.AppReceiver在MainActivity中的使用4.效果图与项目结构图先来波效果图是提高开发效率、减少重复代码的重要手段。以下是BaseActivity、BaseFragment和BaseApplication的实现,涵盖了常用功能,如生命周期管理、Toast提示、权限处理、Fragment管理等。BaseApplicationBaseApplication是应用的全局基类,用于初始化全局配置、工具类等。importandr Fragment 懒加载的优化方案 tangweiguo03051987 androidandroidjava 懒加载方案:使用Lifecycle监听Fragment的生命周期,简化逻辑。结合ViewPager2和FragmentStateAdapter,兼容现代Android开发。封装通用基类,减少重复代码,提高可维护性。这种方式不仅代码简洁,而且性能更好,适合现代Android应用开发以下是完整的Fragment懒加载实现代码,包括基类封装、具体Fragment实现以及ViewPager2的集成。代码经 简介安卓广播机制 Android Broadcast 某某鹦鹉 Andriodjavaandroid 目录前言——手机的“小动作”什么是广播?有了服务为什么还需要广播?常见的系统action广播有哪些成员?广播发送者广播的发送过程广播发送过程时序图广播的两种发送方式广播接受者广播接受者的注册过程广播注册过程时序图广播的两种注册方式前言——手机的“小动作”如电量低到一定程度会有低电量提醒,插入电源线时炫酷的动画,充满电时又会显示电量已充满,以及当手机开机时显示“欢迎使用中国移动/联通/电信”提醒,关 Android四大组件系列8 Broadcast广播机制(下) Big Skipper Androidframework 概述广播(Broadcast)机制用于进程或线程间通信,广播分为广播发送和广播接收两个过程,其中广播接收者BroadcastReceiver是Android四大组件之一。BroadcastReceiver分为两类:静态广播接收者:通过AndroidManifest.xml的标签来声明的BroadcastReceiver动态广播接收者:通过AMS.registerReceiver()方式注册的Bro 微前端父子应用及兄弟应用间组件或方法共享方案 程序员 作者:京东物流刘微微背景我们的很多web应用在持续迭代中功能越来越复杂,参与的人员、团队不断增多,导致项目出现难以维护的问题,这种情况PC端尤其常见,微前端为我们提供了一种高效管理复杂应用的方案。但是在使用微前端的过程中,通常会有一些公共方法或公共组件,本文将对如何实现父子应用以及兄弟应用之间进行方法及组件共享提出几种解决方案以及其各自优缺点及适用场景模块联邦(ModuleFederation)w Android Broadcast广播封装 tangweiguo03051987 android开发语言 在Android高版本(尤其是Android8.0及以上)中,Broadcast的使用受到了一些限制,例如隐式广播的限制和后台执行限制。为了适配高版本并简化Broadcast的使用,可以封装一个工具类,支持动态注册、静态注册、权限控制等功能。以下是Broadcast工具类的封装,支持高版本适配,并提供简洁的API。Broadcast工具类封装importandroid.content.Broadc 凡人歌:平凡公司的技术面试 程序员 我们见惯了大厂刷题面试宝典,大佬们只招世界上最优秀的人新闻。我们也乐见这些金字塔顶端给大家洒下的热点鸡汤。而现实却是平凡的小公司才是主流。他们不在聚光灯下,只盘踞在各大招聘网站上。他们才是平凡人职业生涯的常住地。当你在创业初期或者长期处于中小公司,此时薪资无吸引力,平台无优势,主角无光环。作为三无公司技术面试官的你,则显得格外重要。小公司面试官,通常没有专业的培训,也少有意识去自我学习。往往是简单 【ASeeker】Android 源码捞针,服务接口扫描神器 android程序员安全 ASeeker是一个Android源码应用系统服务接口扫描工具。项目已开源:☞Github☜如果您也喜欢ASeeker,别忘了给我们点个星。说明ASeeker项目是我们在做虚拟化分身产品(『空壳』)过程中的内部开发工具,目的是为了提升Android系统各版本适配效率。由于产品需支持Android9.x~Android14.x,需在应用访问所有的系统服务接口时,将我们关心的参数进行修正和还原。这导致 再聊解除HiddenApi限制 android 炒冷饭,再聊聊大家都知晓的隐藏接口的限制解除。说明由于我们容器产品的特性,需要将应用完整的运行起来,所以必须涉及一些隐藏接口的反射调用,而突破反射限制则成为我们实现的基础。现将我们的解决方案分享给大家,一起学习。Android9.0→首次启用这个大家都知道原理了,简单巴拉巴拉下,从下往上溯源。1、找到API判断规则豁免点。//sourcecode:art/runtime/hidden_api.cc 3年常见面试题 Ulrica0 java-rabbitmqrabbitmqjava SHEIN希音一面1、简单大概自我介绍2、面试官根据您简历项目进行互动,所以可以好好复习关于财务系统(例如报销系统、财务系统、供应商订货财务等)一些理论知识点和项目、系统比较容易出现什么突发bug、如何修复等2、技术方面1)mysql中有一张表id自增name找出name重复的记录?selectemployee_name,count(*)ascfromemployeegroupbyemployee 多线程编程之join()方法 周凡杨 javaJOIN多线程编程线程 现实生活中,有些工作是需要团队中成员依次完成的,这就涉及到了一个顺序问题。现在有T1、T2、T3三个工人,如何保证T2在T1执行完后执行,T3在T2执行完后执行?问题分析:首先问题中有三个实体,T1、T2、T3, 因为是多线程编程,所以都要设计成线程类。关键是怎么保证线程能依次执行完呢? Java实现过程如下: public class T1 implements Runnabl java中switch的使用 bingyingao javaenumbreakcontinue java中的switch仅支持case条件仅支持int、enum两种类型。 用enum的时候,不能直接写下列形式。 switch (timeType) { case ProdtransTimeTypeEnum.DAILY: break; default: br hive having count 不能去重 daizj hive去重having count计数 hive在使用having count()是,不支持去重计数 hive (default)> select imei from t_test_phonenum where ds=20150701 group by imei having count(distinct phone_num)>1 limit 10; FAILED: SemanticExcep WebSphere对JSP的缓存 周凡杨 WAS JSP 缓存 对于线网上的工程,更新JSP到WebSphere后,有时会出现修改的jsp没有起作用,特别是改变了某jsp的样式后,在页面中没看到效果,这主要就是由于websphere中缓存的缘故,这就要清除WebSphere中jsp缓存。要清除WebSphere中JSP的缓存,就要找到WAS安装后的根目录。 现服务 设计模式总结 朱辉辉33 java设计模式 1.工厂模式 1.1 工厂方法模式 (由一个工厂类管理构造方法) 1.1.1普通工厂模式(一个工厂类中只有一个方法) 1.1.2多工厂模式(一个工厂类中有多个方法) 1.1.3静态工厂模式(将工厂类中的方法变成静态方法) &n 实例:供应商管理报表需求调研报告 老A不折腾 finereport报表系统报表软件信息化选型 引言 随着企业集团的生产规模扩张,为支撑全球供应链管理,对于供应商的管理和采购过程的监控已经不局限于简单的交付以及价格的管理,目前采购及供应商管理各个环节的操作分别在不同的系统下进行,而各个数据源都独立存在,无法提供统一的数据支持;因此,为了实现对于数据分析以提供采购决策,建立报表体系成为必须。 业务目标 1、通过报表为采购决策提供数据分析与支撑 2、对供应商进行综合评估以及管理,合理管理和 mysql 林鹤霄 转载源:http://blog.sina.com.cn/s/blog_4f925fc30100rx5l.html mysql -uroot -p ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES) [root@centos var]# service mysql Linux下多线程堆栈查看工具(pstree、ps、pstack) aigo linux 原文:http://blog.csdn.net/yfkiss/article/details/6729364 1. pstree pstree以树结构显示进程$ pstree -p work | grep adsshd(22669)---bash(22670)---ad_preprocess(4551)-+-{ad_preprocess}(4552) &n html input与textarea 值改变事件 alxw4616 JavaScript // 文本输入框(input) 文本域(textarea)值改变事件 // onpropertychange(IE) oninput(w3c) $('input,textarea').on('propertychange input', function(event) { console.log($(this).val()) }); String类的基本用法 百合不是茶 String 字符串的用法; // 根据字节数组创建字符串 byte[] by = { 'a', 'b', 'c', 'd' }; String newByteString = new String(by); 1,length() 获取字符串的长度 &nbs JDK1.5 Semaphore实例 bijian1013 javathreadjava多线程Semaphore Semaphore类 一个计数信号量。从概念上讲,信号量维护了一个许可集合。如有必要,在许可可用前会阻塞每一个 acquire(),然后再获取该许可。每个 release() 添加一个许可,从而可能释放一个正在阻塞的获取者。但是,不使用实际的许可对象,Semaphore 只对可用许可的号码进行计数,并采取相应的行动。 S 使用GZip来压缩传输量 bijian1013 javaGZip 启动GZip压缩要用到一个开源的Filter:PJL Compressing Filter。这个Filter自1.5.0开始该工程开始构建于JDK5.0,因此在JDK1.4环境下只能使用1.4.6。 PJL Compressi 【Java范型三】Java范型详解之范型类型通配符 bit1129 java 定义如下一个简单的范型类, package com.tom.lang.generics; public class Generics<T> { private T value; public Generics(T value) { this.value = value; } } 【Hadoop十二】HDFS常用命令 bit1129 hadoop 1. 修改日志文件查看器 hdfs oev -i edits_0000000000000000081-0000000000000000089 -o edits.xml cat edits.xml 修改日志文件转储为xml格式的edits.xml文件,其中每条RECORD就是一个操作事务日志 2. fsimage查看HDFS中的块信息等 &nb 怎样区别nginx中rewrite时break和last ronin47 在使用nginx配置rewrite中经常会遇到有的地方用last并不能工作,换成break就可以,其中的原理是对于根目录的理解有所区别,按我的测试结果大致是这样的。 location / { proxy_pass http://test; java-21.中兴面试题 输入两个整数 n 和 m ,从数列 1 , 2 , 3.......n 中随意取几个数 , 使其和等于 m bylijinnan java import java.util.ArrayList; import java.util.List; import java.util.Stack; public class CombinationToSum { /* 第21 题 2010 年中兴面试题 编程求解: 输入两个整数 n 和 m ,从数列 1 , 2 , 3.......n 中随意取几个数 , 使其和等 eclipse svn 帐号密码修改问题 开窍的石头 eclipseSVNsvn帐号密码修改 问题描述: Eclipse的SVN插件Subclipse做得很好,在svn操作方面提供了很强大丰富的功能。但到目前为止,该插件对svn用户的概念极为淡薄,不但不能方便地切换用户,而且一旦用户的帐号、密码保存之后,就无法再变更了。 解决思路: 删除subclipse记录的帐号、密码信息,重新输入 [电子商务]传统商务活动与互联网的结合 comsci 电子商务 某一个传统名牌产品,过去销售的地点就在某些特定的地区和阶层,现在进入互联网之后,用户的数量群突然扩大了无数倍,但是,这种产品潜在的劣势也被放大了无数倍,这种销售利润与经营风险同步放大的效应,在最近几年将会频繁出现。。。。 如何避免销售量和利润率增加的 java 解析 properties-使用 Properties-可以指定配置文件路径 cuityang javaproperties #mq xdr.mq.url=tcp://192.168.100.15:61618; import java.io.IOException; import java.util.Properties; public class Test { String conf = "log4j.properties"; private static final Java核心问题集锦 darrenzhu java基础核心难点 注意,这里的参考文章基本来自Effective Java和jdk源码 1)ConcurrentModificationException 当你用for each遍历一个list时,如果你在循环主体代码中修改list中的元素,将会得到这个Exception,解决的办法是: 1)用listIterator, 它支持在遍历的过程中修改元素, 2)不用listIterator, new一个 1分钟学会Markdown语法 dcj3sjt126com markdown markdown 简明语法 基本符号 *,-,+ 3个符号效果都一样,这3个符号被称为 Markdown符号 空白行表示另起一个段落 `是表示inline代码,tab是用来标记 代码段,分别对应html的code,pre标签 换行 单一段落( <p>) 用一个空白行 连续两个空格 会变成一个 <br> 连续3个符号,然后是空行 Gson使用二(GsonBuilder) eksliang jsongsonGsonBuilder 转载请出自出处:http://eksliang.iteye.com/blog/2175473 一.概述 GsonBuilder用来定制java跟json之间的转换格式 二.基本使用 实体测试类: 温馨提示:默认情况下@Expose注解是不起作用的,除非你用GsonBuilder创建Gson的时候调用了GsonBuilder.excludeField 报ClassNotFoundException: Didn't find class "...Activity" on path: DexPathList gundumw100 android 有一个工程,本来运行是正常的,我想把它移植到另一台PC上,结果报: java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.mobovip.bgr/com.mobovip.bgr.MainActivity}: java.lang.ClassNotFoundException: Didn't f JavaWeb之JSP指令 ihuning javaweb 要点 JSP指令简介 page指令 include指令 JSP指令简介 JSP指令(directive)是为JSP引擎而设计的,它们并不直接产生任何可见输出,而只是告诉引擎如何处理JSP页面中的其余部分。 JSP指令的基本语法格式: <%@ 指令 属性名=" mac上编译FFmpeg跑ios 啸笑天 ffmpeg 1、下载文件:https://github.com/libav/gas-preprocessor, 复制gas-preprocessor.pl到/usr/local/bin/下, 修改文件权限:chmod 777 /usr/local/bin/gas-preprocessor.pl 2、安装yasm-1.2.0 curl http://www.tortall.net/projects/yasm sql mysql oracle中字符串连接 macroli oraclesqlmysqlSQL Server 有的时候,我们有需要将由不同栏位获得的资料串连在一起。每一种资料库都有提供方法来达到这个目的: MySQL: CONCAT() Oracle: CONCAT(), || SQL Server: + CONCAT() 的语法如下: Mysql 中 CONCAT(字串1, 字串2, 字串3, ...): 将字串1、字串2、字串3,等字串连在一起。 请注意,Oracle的CON Git fatal: unab SSL certificate problem: unable to get local issuer ce rtificate qiaolevip 学习永无止境每天进步一点点git纵观千象 // 报错如下: $ git pull origin master fatal: unable to access 'https://git.xxx.com/': SSL certificate problem: unable to get local issuer ce rtificate // 原因: 由于git最新版默认使用ssl安全验证,但是我们是使用的git未设 windows命令行设置wifi surfingll windowswifi笔记本wifi 还没有讨厌无线wifi的无尽广告么,还在耐心等待它慢慢启动么 教你命令行设置 笔记本电脑wifi: 1、开启wifi命令 netsh wlan set hostednetwork mode=allow ssid=surf8 key=bb123456 netsh wlan start hostednetwork pause 其中pause是等待输入,可以去掉 2、 Linux(Ubuntu)下安装sysv-rc-conf wmlJava linuxubuntusysv-rc-conf 安装:sudo apt-get install sysv-rc-conf 使用:sudo sysv-rc-conf 操作界面十分简洁,你可以用鼠标点击,也可以用键盘方向键定位,用空格键选择,用Ctrl+N翻下一页,用Ctrl+P翻上一页,用Q退出。 背景知识 sysv-rc-conf是一个强大的服务管理程序,群众的意见是sysv-rc-conf比chkconf svn切换环境,重发布应用多了javaee标签前缀 zengshaotao javaee 更换了开发环境,从杭州,改变到了上海。svn的地址肯定要切换的,切换之前需要将原svn自带的.svn文件信息删除,可手动删除,也可通过废弃原来的svn位置提示删除.svn时删除。 然后就是按照最新的svn地址和规范建立相关的目录信息,再将原来的纯代码信息上传到新的环境。然后再重新检出,这样每次修改后就可以看到哪些文件被修改过,这对于增量发布的规范特别有用。 检出 按字母分类: ABCDEFGHIJKLMNOPQRSTUVWXYZ其他
分析上述代码后,我们可以初步得出如下信息:
1、Spring为bean提供了两种初始化的方式,实现InitializingBean接口(也就是要实现该接口中的afterPropertiesSet方法),或者在配置文件或@Bean注解中通过init-method来指定,两种方式可以同时使用。
2、实现InitializingBean接口是直接调用afterPropertiesSet()方法,与通过反射调用init-method指定的方法相比,效率相对来说要高点。但是init-method方式消除了对Spring的依赖。
3、如果调用afterPropertiesSet方法时出错,那么就不会调用init-method指定的方法了。
也就是说Spring为bean提供了两种初始化的方式,第一种方式是实现InitializingBean接口(也就是要实现该接口中的afterPropertiesSet方法),第二种方式是在配置文件或@Bean注解中通过init-method来指定,这两种方式可以同时使用,同时使用先调用afterPropertiesSet方法,后执行init-method指定的方法。
* 在Spring容器创建完成时,会自动调用单实例bean的构造方法,对单实例bean进行了实例化操作。 * * 多实例的bean在容器关闭的时候是不进行销毁的,也就是说你每次获取时,IOC容器帮你创建出对象交还给你, * 至于要什么时候销毁这是你自己的事,Spring容器压根就不会再管理这些多实例的bean了。 * * 单实例:在容器启动的时候创建对象; * 多实例:在每次获取的时候创建对象; * * 初始化: * 对象创建好,并赋值好,调用初始化方法; * * 销毁: * 单实例:容器关闭的时候; * 多实例:容器不会管理Bean,只是负责创建,容器不会调用销毁方法; * * 1、指定初始化和销毁的方法; * 2、通过Bean 实现InitializingBean和DisposableBean * InitializingBean(定义初始化逻辑) * DisposableBean(定义销毁逻辑)
2、@PostConstruct和@PreDestroy这俩注解
@PostConstruct:在bean创建完成并且属性赋值完成之后,来执行初始化方法
@PreDestroy:在容器销毁bean之前通知我们进行清理工作
//@Component public class Dog {
private Cat cat; public Dog(){ System.out.println("dog...constructor..构造器"); } public Cat getCat() { return cat; } public void setCat(Cat cat) { this.cat = cat; } //对象创建赋值之后调用 @PostConstruct public void init(){ System.out.println("dog...@PostConstruct..."); } //容器移除对象之前 @PreDestroy public void destory(){ System.out.println("dog...@PreDestroy..."); }
}
3、通过让bean实现BeanPostProcessor接口
@Component public class MyBeanPostProcessor implements BeanPostProcessor, Ordered { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessBeforeInitialization--->"+beanName+"--->"+bean); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessAfterInitialization--->"+beanName+"--->"+bean); return bean; } @Override public int getOrder() { return 3; } }
通过以上这四种方式,我们就可以对bean的整个生命周期进行控制:
bean的实例化:调用bean的构造方法,我们可以在bean的无参构造方法中执行相应的逻辑。 bean的初始化:在初始化时,可以通过BeanPostProcessor的postProcessBeforeInitialization()方法和postProcessAfterInitialization()方法进行拦截,执行自定义的逻辑;通过@PostConstruct注解、InitializingBean和init-method来指定bean初始化前后执行的方法,在该方法中咱们可以执行自定义的逻辑。 bean的销毁:可以通过@PreDestroy注解、DisposableBean和destroy-method来指定bean在销毁前执行的方法,在该方法中咱们可以执行自定义的逻辑。
所以,通过上述四种方式,我们可以控制Spring中bean的整个生命周期。
后置处理器可用于bean对象初始化前后进行逻辑增强。 Spring提供了BeanPostProcessor接口的很多实现类,例如AutowiredAnnotationBeanPostProcessor用于@Autowired注解的实现,AnnotationAwareAspectJAutoProxyCreator用于Spring AOP的动态代理等等。
除此之外,我们还可以自定义BeanPostProcessor接口的实现类,在其中写入咱们需要的逻辑。下面我会以AnnotationAwareAspectJAutoProxyCreator为例,简单说明一下后置处理器是怎样工作的。
我们都知道spring AOP的实现原理是动态代理,最终放入容器的是代理类的对象,而不是bean本身的对象,那么Spring是什么时候做到这一步的呢?就是在AnnotationAwareAspectJAutoProxyCreator后置处理器的postProcessAfterInitialization方法中,即bean对象初始化完成之后,后置处理器会判断该bean是否注册了切面,若是,则生成代理对象注入到容器中。这一部分的关键代码是在哪儿呢?我们定位到AbstractAutoProxyCreator抽象类中的postProcessAfterInitialization方法处便能看到了,如下所示。
这里请看:https://liayun.blog.csdn.net/article/details/110442093 这里是源码讲解。我这里直接拿过来结果吧。
在applyBeanPostProcessorsBeforeInitialization()方法中,会遍历所有BeanPostProcessor对象,然后依次执行所有BeanPostProcessor对象的postProcessBeforeInitialization()方法,一旦BeanPostProcessor对象的postProcessBeforeInitialization()方法返回null以后,则后面的BeanPostProcessor对象便不再执行了,而是直接退出for循环。这些都是我们看源码看到的。
看Spring源码,我们还看到了一个细节,在Spring中调用initializeBean()方法之前,还调用了populateBean()方法来为bean的属性赋值, 这在上面我也已经说过了。
这里数属性填充工作:那么是怎样工作的那? 就是调用populateBean()方法
经过上面的一系列的跟踪源码分析,我们可以将关键代码的调用过程使用如下伪代码表述出来。
populateBean(beanName, mbd, instanceWrapper); // 给bean进行属性赋值 initializeBean(beanName, exposedObject, mbd) { applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); invokeInitMethods(beanName, wrappedBean, mbd); // 执行自定义初始化 applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); }
也就是说,在Spring中,调用initializeBean()方法之前,调用了populateBean()方法为bean的属性赋值,为bean的属性赋好值之后,再调用initializeBean()方法进行初始化。
在initializeBean()中,调用自定义的初始化方法(即invokeInitMethods())之前,调用了applyBeanPostProcessorsBeforeInitialization()方法,而在调用自定义的初始化方法之后,又调用了applyBeanPostProcessorsAfterInitialization()方法。至此,整个bean的初始化过程就这样结束了。
如果我们现在自定义的组件中需要用到Spring底层的一些组件,比如ApplicationContext(IOC容器)、底层的BeanFactory等等,那么该怎么办呢?先说说自定义的组件中能不能用Spring底层的一些组件吧?既然都这样说了,那么肯定是能够的。
回到主题,自定义的组件要想使用Spring容器底层的一些组件,比如ApplicationContext(IOC容器)、底层的BeanFactory等等,那么只需要让自定义组件实现XxxAware接口即可。此时,Spring在创建对象的时候,会调用XxxAware接口中定义的方法注入相关的组件。
其实,我们之前使用过XxxAware接口,例如,我们之前创建的Dog类,就实现了ApplicationContextAware接口,Dog类的源码如下所示。
package com.meimeixia.bean; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; /** * ApplicationContextAwareProcessor这个类的作用是可以帮我们在组件里面注入IOC容器, * 怎么注入呢?我们想要IOC容器的话,比如我们这个Dog组件,只需要实现ApplicationContextAware接口就行 * * @author liayun * */ @Component public class Dog implements ApplicationContextAware { private ApplicationContext applicationContext; public Dog() { System.out.println("dog constructor..."); } // 在对象创建完成并且属性赋值完成之后调用 @PostConstruct public void init() { // 在这儿打个断点调试一下 System.out.println("dog...@PostConstruct..."); } // 在容器销毁(移除)对象之前调用 @PreDestroy public void destory() { System.out.println("dog...@PreDestroy..."); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { // 在这儿打个断点调试一下 // TODO Auto-generated method stub this.applicationContext = applicationContext; } }
从以上Dog类的源码中可以看出,实现ApplicationContextAware接口的话,需要实现setApplicationContext()方法。在IOC容器启动并创建Dog对象时,Spring会调用setApplicationContext()方法,并且会将ApplicationContext对象传入到setApplicationContext()方法中,我们只需要在Dog类中定义一个ApplicationContext类型的成员变量来接收setApplicationContext()方法中的参数,那么便可以在Dog类的其他方法中使用ApplicationContext对象了。
其实,在Spring中,类似于ApplicationContextAware接口的设计有很多,本质上,Spring中形如XxxAware这样的接口都继承了Aware接口,我们来看下Aware接口的源码,如下所示。 接下来,我们看看都有哪些接口继承了Aware接口,如下所示。
接下来,我们就挑选几个常用的XxxAware接口来简单的说明一下。
ApplicationContextAware接口使用的比较多,我们先来说说这个接口,通过ApplicationContextAware接口我们可以获取到IOC容器。
首先,我们创建一个Red类,它得实现ApplicationContextAware接口,并在实现的setApplicationContext()方法中将ApplicationContext输出,如下所示。
package com.meimeixia.bean; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; /** * 以Red类为例来讲解ApplicationContextAware接口、BeanNameAware接口以及EmbeddedValueResolverAware接口 * @author liayun * */ public class Red implements ApplicationContextAware { private ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { System.out.println("传入的IOC:" + applicationContext); this.applicationContext = applicationContext; } }
其实,我们也可以让Red类同时实现几个XxxAware接口,例如,使Red类再实现一个BeanNameAware接口,我们可以通过BeanNameAware接口获取到当前bean在Spring容器中的名称,如下所示。
package com.meimeixia.bean; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanNameAware; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; /** * 以Red类为例来讲解ApplicationContextAware接口、BeanNameAware接口以及EmbeddedValueResolverAware接口 * @author liayun * */ public class Red implements ApplicationContextAware, BeanNameAware { private ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { System.out.println("传入的IOC:" + applicationContext); this.applicationContext = applicationContext; } /** * 参数name:IOC容器创建当前对象时,为这个对象起的名字 */ @Override public void setBeanName(String name) { System.out.println("当前bean的名字:" + name); } }
当然了,我们可以再让Red类实现一个EmbeddedValueResolverAware接口,我们通过EmbeddedValueResolverAware接口能够获取到String值解析器,如下所示。
package com.meimeixia.bean; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanNameAware; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.EmbeddedValueResolverAware; import org.springframework.util.StringValueResolver; /** * 以Red类为例来讲解ApplicationContextAware接口、BeanNameAware接口以及EmbeddedValueResolverAware接口 * @author liayun * */ public class Red implements ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware { private ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { System.out.println("传入的IOC:" + applicationContext); this.applicationContext = applicationContext; } /** * 参数name:IOC容器创建当前对象时,为这个对象起的名字 */ @Override public void setBeanName(String name) { System.out.println("当前bean的名字:" + name); } /** * 参数resolver:IOC容器启动时会自动地将这个String值的解析器传递过来给我们 */ @Override public void setEmbeddedValueResolver(StringValueResolver resolver) { String resolveStringValue = resolver.resolveStringValue("你好,${os.name},我的年龄是#{20*18}"); System.out.println("解析的字符串:" + resolveStringValue); } }
IOC容器启动时会自动地将String值的解析器(即StringValueResolver)传递过来给我们用,咱们可以用它来解析一些字符串,解析哪些字符串呢?比如包含#{}这样的字符串。我们可以看一下StringValueResolver类的源码,如下所示。
接着,我们需要在Red类上标注@Component注解将该类添加到IOC容器中,如下所示。
@Component public class Red implements ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware {
最后,运行IOCTest_Autowired类中的test02()方法,输出的结果信息如下所示。
XxxAware接口的底层原理是由XxxAwareProcessor实现类实现的,也就是说每一个XxxAware接口都有它自己对应的XxxAwareProcessor实现类。 例如,我们这里以ApplicationContextAware接口为例,ApplicationContextAware接口的底层原理就是由ApplicationContextAwareProcessor类实现的。从ApplicationContextAwareProcessor类的源码可以看出,其实现了BeanPostProcessor接口,本质上是一个后置处理器。
先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦