联通数科面试准备

Spring中Bean的生命周期

Spring Bean的生命周期全过程分为5个阶段,创建前准备阶段、创建实例阶段、依赖注入阶段和容器缓存阶段以及销毁实例阶段。
阶段1:创建前准备阶段这个阶段主要是在开始Bean加载之前,从Spring上下文中去获取相关的配置并且解析,然后找到Bean有关的配置内容,比如说"init-method"容器在初始化Bean的时候去调用‍这个方法。‍"destory-method"容器在销毁Bean的时候去调用这个方法以及BeanFactoryPostProcessor这个类的Bean加载过程中的前置和后置的处理,这些类或者配置是Spring提供给开发者用来实现Bean加载过程中的一个扩展的机制。在很多和Spring集成的中间件中也经常‍‍使用到,比如Dubbo。

阶段2:创建实例阶段这个阶段主要是通过反射来创建Bean的实际对象,并且扫描和解析Bean的声明的一些属性。‍

阶段3:依赖注入阶段在这个阶段会检测被实例化的Bean是否存在其他依赖,如果存在其他依赖的话,‍‍就需要将这些依赖注入到Bean里面,比如说通过读取"@Autowired", “@Setter” 等注解去完成依赖注入的配置,‍‍这个阶段会触发一些扩展的调用,如常见的扩展类BeanPostProcessors它用来实现Bean初始化‍前后的一个回调。如InitializingBean的afterPropertiesSet()方法,它可以给属性赋值。还有BeanFactoryAware等等。‍

‍阶段4:容器缓存阶段容器缓存阶段主要是把Bean保存到IoC容器中缓存起来,‍‍到了这个阶段Bean就可以去被开发者使用了,这个阶段涉及到的操作有常见的“init-method”属性配置的方法会在这个阶段被调用,比如BeanPostProcessors它的后续处理方法postProcessAfterInitialization也会在这个阶段被触发。
步骤一:执行前置处理方法,当正在初始化的Bean对象被传递进来,postProcessBeforeInitialization()会吸纳与执行初始化调用方法执行,所有xxxAware接口的注入,即对引用的容器级别对象的属性的赋值/依赖注入操作,就是在这一步完成的。
步骤二:执行初始化调用方法–invokeInitMethods:
如果在Spring配置文件中配置了init-method 属性,会自动对该Bean进行增强实现步骤中的初始化步骤。“执行初始化调用方法”这一个步骤在Java 语言里边其实是没有多大实际意义的。 因为在其他编程语言里边比如说Python 里边,会在这一个步骤中进行属性赋值工作,但是在Java里边,刚才已经刚刚完成了属性赋值的工作了。
步骤三:该后置处理器的执行是在 “执行初始化调用方法” 后面进行执行,主要是判断该bean是否需要被AOP代理增强,如果需要的话,则会在该步骤返回一个代理对象。这个函数会在 “执行初始化调用方法” 完成后执行,因此称为后置处理方法。
这一步完成以后,就可以正常使用这个 Bean 了。

(5)销毁 Destruction

详解:
(1)通过xml配置或者注解配置的类,得到BeanDefinition;
(2)通过BeanDefinition反射创建Bean对象
(3)对Bean对象的属性进行填充。
(4)回调实现了Aware接口的方法,如BeanNameAware;
(5)调用BeanPostProcessor的初始化前方法。
(6)调用inti初始化方法。
(7)调用BeanPostProcessor的初始化方法,此处会进行AOP;
(8)将创建的Bean对象放入一个Map。
(9)业务使用Bean对象。
(10)Spring 容器关闭时调用DisposableBean的destory()方法。

Spring如何解决循环依赖问题

一级缓存:singletonObjects存储的是所有创建好了的单例Bean(实例化、依赖注入、初始化完成的bean实例)。
二级缓存:earlySingletonObjects保存的是完成实例化,但是还未进行属性注入以及初始化的对象。
三级缓存:singletonFactories提前暴露的一个单例工厂,二级缓存中存储的就是从这个工厂中获取到的对象。

三级缓存解决循环依赖流程:‘
(1)获取A时首先会尝试从一级缓存sigletonOjects中获取,有就返回,没有就找“二级缓存”;
(2)获取不到就从二级缓存中获取,有就返回,没有就找“三级缓存”;
(3)若还没有则从三级缓存singletonFactories中获取,找到了,就获取对象,放到“二级缓存”,从“三级缓存”移除。
(4)还有没有则再次创建该对象。
(5)会依次执行doGetBean->createBean->createBeanInstance并使用构造器实例化。
(6)在尝试给A进行初始化时,由于B不存在无法完成初始化,则将A的代理工厂放入三级缓存中,进行创建B的创建流程。
(7)与之前的过程相似,在第三级缓存中放入beanName和表达式sharedInstance,进入B的初始化过程。
(8)由于在第三级缓存中可以找到A的代理工厂,直接从“三级缓存”中拿到 A 的代理工厂,获取 A 的代理对象,放入“二级缓存”,并清除“三级缓存”;
(9)则B可以完成初始化,完成A对象的属性注入,将B放入一级缓存,然后再填充A的其他属性,以及A的其他步骤(包括AOP),完成A的初始化功能(包括AOP),完成对A的初始化功能。
(9)同时完成A的初始化,并删除二级缓存中的半成品A,将A放入一级缓存。

总结:
Spring通过三级缓存解决了循环依赖,其中一级缓存是单例池,二级缓存是早期曝光对象earlySingletonObjects,三级缓存为早期曝光对象工厂(singletonFactories)。当A、B两个类发生循环依赖时,在A完成实例化后,就使用实例化后的对象去创建一个对象工厂,添加到三级缓存中,如果A被AOP代理,那么通过这个工厂获取到的就是A代理后的对象,如果A没有被AOP代理,那么这个工厂获取到的就是A实例化后的对象。当A进行属性注入时,回去创建B,同时B有依赖了A,所以创建B的同时又去调用getBean(a)来获取所需要的依赖,此时的getBean(a)会从缓存中获取:
(1)先获取到三级缓存中的工厂。
(2)调用对象工厂的getObject方法来获取到对应的对象,得到这个对象后将其注入到B中,紧接着B就会走完它的声明周期流程,包括初始化、后置处理器。
(3)当B创建完成后,会将B再次注入到A中,此时A再完成它的整个生命周期,至此,循环依赖结束。
在这里插入图片描述

Spring AOP的实现原理

Spring的AOP是通过动态代理实现的,如果我们为Spring的某个bean配置了切面,那么Spring在创建这个bean的时候,实际上创建的就是这个bean的一个代理对象,我们后续对bean中的方法的调用,实际上调用的就是代理类重写的代理方法。而Spring的AOP使用了两种动态代理,分别是JDK的动态代理,以及CGLib的动态代理。

JDK动态代理:
如果目标类实现了接口,Spring AOP会选择使用JDK动态代理目标类。JDK动态代理的代理类根据根据目标类实现的接口动态生成,不需要自己编写。生成的动态代理类和目标类都实现相同的接口。JDK动态代理的核心是InvocationHandler接口和Proxy类。JDK动态代理的缺点是目标类必须有实现的接口。如果这个类没有实现接口,那么这个类就不能使用JDK动态代理。

CGLIB动态代理:
如果目标类没有实现接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB英文全称是Code Generation Library,可以再运行时动态生成类的字节码,动态创建目标类的子类对象,在子类对象中增强目标类。CDLIB是通过继承的方式实现的动态代理,因此如果某个类被标记为final,那么它无法使用CGLIB做动态代理。相对于JDK动态代理,CGLIB动态代理的优点是:目标类不需要实现特定的几口,更加灵活。

如果目标对象实现了接口,默认情况下会使用JDK动态代理实现AOP,但是也可以强制使用CGLIB实现AOP。如果目标对象没有实现接口,必须采用CGLIB做动态代理。

动态代理的作用

动态代理是设计模式的一种:
(1)调用方不用知道具体目标类是什么(安全、解耦),只需要知道统一的代理类。
(2)可以对目标类做增强(在方法运行:前、后、成功、异常时,做额外处理,并且代码相对独立,也是为了解耦)

java如何删除list中的元素

(1)正序删除
使用正序删除,如果只删除至多一个元素,那只需要在删除这个元素后使用break语句跳出循环即可,如果要删除多个元素,若不注意控制当前列表的size和下一个元素的index,容易报java.lang.IndexOutOfBoundsException异常。

public static void remove(List<String> list, String target) {    
for(int i = 0, length = list.size(); i < length; i++){String item = list.get(i);        if(target.equals(item)){list.remove(item);length--;i--;}}
}

(2)倒序删除
倒序删除可以客服正序删需要额外管理列表size和下一个元素index的问题。

public static void remove(List<String> list, String target) {    
for(int i = list.size() - 1; i >= 0; i--){String item = list.get(i);if(target.equals(item)){list.remove(item);}}
}

(3)迭代器remove()方法删除

public static void remove(List<String> list, String target) {Iterator<String> iter = list.iterator();while (iter.hasNext()) {String item = iter.next();if (item.equals(target)) {iter.remove();}}
}

(4)CopyOnWriteArrayList线程安全删除
利用CopyOnWrite容器。CopyOnWrite容器就是写时复制容器。通俗的理解就是当我们往一个容器添加元素的时候,不直接往当前元素添加,而是先将当前容器进行cooy,复制出一个新的容器,然后往新的容器里面添加元素,添加完元素后,再讲原来的容器的引用指向新的容器。这样做的好处是我们可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读与写不同的容器。

public static List<String> remove(ArrayList<String> list, String target) {CopyOnWriteArrayList<String> cowList = new CopyOnWriteArrayList<String>(list);for (String item : cowList) {if (item.equals(target)) {cowList.remove(item);}}return cowList;
}

(5)增强for循环删除
增强for循环中删除元素后继续循环会报java.util.ConcurrentModification异常,因为元素在使用的时候发生了并发的修改,导致异常抛出,但是删除完毕马上使用break语句跳出循环,则不会触发报错,所以它只适合删除一个元素。

public static void remove(List<String> list, String target) {for (String item : list) {if (item.equals(target)) {list.remove(item);break;}}
}

(6)stream API filter
java8引入的stream API带来了新的比较简洁的删除List元素的方法filter,该方法不会改变原List对象,会返回新的对象。

HashMap与HashTable的区别

(1)线程安全:HashMap是非线程安全的,HashTable是线程安全的。
(2)效率: 因为线程安全的问题,HashMap 要比 HashTable 效率高一点。另外,HashTable 基本被淘汰,不要在代码中使用它;
(3) 对Null key 和Null value的支持: HashMap 中,null 可以作为键,这样的键只有一个,可以有一个或多个键所对应的值为 null。但是在HashTable 中 put 进的键值只要有一个 null,直接抛NullPointerException。
(4)4. 初始容量大小和每次扩充容量大小的不同 : ①创建时如果不指定容量初始值,Hashtable 默认的初始大小为11,之后每次扩充,容量变为原来的2n+1。HashMap 默认的初始化大小为16。之后每次扩充,容量变为原来的2倍。②创建时如果给定了容量初始值,那么 Hashtable 会直接使用你
给定的大小,而 HashMap 会将其扩充为2的幂次方大小。也就是说 HashMap 总是使用2的幂作为哈希表的大小。
5. 底层数据结构: JDK1.8 以后的 HashMap 在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间。Hashtable 没有这样的机制。

说一下HashMap的实现原理

HashMap概述:HashMap是基于哈希表的Map接口的非同步实现。此实现提供所有可选地映射操作,并且允许使用null值和null键。此类并不保证映射的顺序,特别是它不保证顺序恒久不变。
HashMap的数据结构:在java编程语言中,基本的数据结构就是两种,一个是数组,另一个是模拟指针(引用),所有数据结构都可以用这两种基本结构来进行构造,Hashmap也不例外。HashMap实际上是一个链表散列的数据结构,即数组和链表的集合。
HashMAP是基于Hash算法实现的:
(1)当我们向Hashmap中put元素的时候,利用key的hashcode重新hash出当前对象的元素在数组中的下标。
(2)存储时,如果出现hash值相同的key,此时有两种情况。如果key相同,此时覆盖原值。如果key不相同,也就是出现hash冲突,则将key-value放入链表中。
(3)获取时,之际找到hash值对应的下标,再进一步判断key是否相同,从而找到对象的值。
(4) 理解了以上过程就不难明白HashMap是如何解决hash冲突的问题,核心就是使用了数组的存储方式,然后将冲突的key的对象放入链表中,一旦发现冲突就在链表中做进一步的对比。

jdk1.8中对HashMap实现了优化,当链表中的节点超过8个之后,该联保转化为红黑树来提高查询效率,由曾经的O(N)转化为O(logn)

简单总结下HashMap是使用了哪些方法来有效解决哈希冲突的:

(1)使用链地址法(散列表)来链接具有相同哈希值的数据。
(2)使用二次扰动函数(hash函数)来降低哈希冲突的概率,使得数据分布更加均匀。
(3)当链表长度超过八个节点时,使用红黑树来降低时间复杂度,使得遍历更快。

ConcurrentHashMap

Segment段:
整个ConcurrentHashMap是由一个个的Segment组成,Segment代表部分或者一段的意思,很多地方会将其描述非分段锁。
线程安全:
JDK1.7版本:ReentrantLock+Segment+HashEntry
JDK1.8版本:synchronized+CAS+HashEntry+红黑树
1.JDK1.8降低锁的粒度,JDK1.7锁的粒度是基于Segment的,包含多个HashEntry,而JDK1.8锁的粒度就是HashEntry
2.JDK1.8使用红黑树来优化链表
3.JDK1.8为什么使用内置锁synchronized来代替重入锁ReentrantLock(synchronized支持锁升级,偏向锁->CAS轻量级锁
->自旋锁->重量级锁)

HashMap为什么线程不安全

jdk1.7:

因为hashMap在jdk1.7中的扩容使用的是头插法,当发生哈希冲突时存储结构为链表,当多线程调用同一个hashmap时,A线程B线程同时使用,都需要扩容,此时A线程获取cpu时间片,扩容完毕后,B线程认为当前链表为扩容前的结构,但实际已经是扩容后的存储结构,从而导致链表中两个节点发生死循环。
解决办法:多线程下建议使用ConcurrentHashMap替代。在JDK1.8中,HashMap扩容改为尾插法,解决了链表死循环的问题。

jdk1.8

JDK1.8 中,由于多线程对HashMap进行put操作,调用了HashMap#putVal(),具体原因:假设两个线程A、B都在进行put操作,并且hash函数计算出的插入下标是相同的,当线程A执行完第六行代码后由于时间片耗尽导致被挂起,而线程B得到时间片后在该下标处插入了元素,完成了正常的插入,然后线程A获得时间片,由于之前已经进行了hash碰撞的判断,所有此时不会再进行判断,而是直接进行插入,这就导致了线程B插入的数据被线程A覆盖了,从而线程不安全。

Collection接口继承树

在这里插入图片描述

Map接口继承树

在这里插入图片描述

Vector,ArrayList,LinkedList的区别是什么?

(1)Vector、ArrayList都是以类似数组的形式存储在内存之中,LinkedList则以链表的形式存储。
(2)List中的元素有序,允许重复,Set中无序、不允许重复。
(3)Vector线程同步,ArrayList、LinkedList线程不同步。
(4)LinkedList适合指定位置插入、删除,不适合查找。ArrayList、Vector适合查找,不适合指定位置的插入、删除操作。
(5)ArrayList在元素填满容器时会自动扩充50%,而Vector则是百分之百,因此ArrayList更节省空间。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/62503.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

360数科华丽财报下的增长困局

配图来自Canva 8月24日&#xff0c;360数科发布了2020年第二季度财报&#xff0c;这也是自8月7日360金融升级为360数科之后的第一份财报。 财报数据显示&#xff0c;360数科本季度财报营收、利润均实现了大幅度上涨&#xff0c;综合科技服务收入增长尤其明显&#xff0c;成为…

京东数科统一接入网关JDDLB性能优化之QAT加速卡

京东数科JDDLB作为京东数科最重要的公网流量入口&#xff0c;承接了很多重要业务的公网流量。目前&#xff0c;已成功接替商业设备F5所承载的流量&#xff0c;并在数次618、双十一大促中体现出优越的功能、性能优势。 本文作为京东数科七层负载 | HTTPS硬件加速 (Freescale加速…

ITest:京东数科接口自动化测试实践

导读&#xff1a;你是否为每天“点点点”的工作而感到索然无味&#xff1f;你是否苦于没有合适的工具而对复杂的测试任务望而却步&#xff1f;频繁变动的接口&#xff0c;重复的功能测试&#xff0c;你&#xff0c;疲惫么&#xff1f;京东数科平台开发团队基于日常接口测试经验…

Thinkphp5 使用Paypal 支付

1&#xff0c;首先前往官网https://www.paypal.com 创建一个账户&#xff0c;我创建的是一个企业账户 2&#xff0c;前往paypal开发者平台https://developer.paypal.com/ 进行创建应用&#xff08;使用谷歌自带的翻译&#xff0c;把网页翻译过来....&#xff09; 3&#xff0c…

OpenCart中PayPal Payments Standard(Paypal 标准支付方式)设置

当你安装Install (Paypal 标准支付方式)PayPal Payments Standard这个支付方式后&#xff0c;编辑Edit它&#xff0c;需要填写许多参数。 本教程<< OpenCart中PayPal Payments Standard(Paypal 标准支付方式)设置 >>由 OpenCart中国网站 制作&#xff0c;转…

paypal国际支付的对接,使用tp5开发paypal

前言 paypal是一种国际支付&#xff0c;并且是一个免费的产品&#xff0c;用户支付并不需要扣除用户消费的手续费&#xff0c;只在商家端扣除的&#xff0c;是一个不错的国际支付 2.下载 直接到github下载php-sdk包&#xff0c;我下载完直接在extend中使用 使用 <?p…

Stripe国际支付平台接入

Stripe 是一家科技公司&#xff0c;致力于为互联网经济打造基础设施。所有公司&#xff0c;无论规模大小&#xff0c;从初创公司到上市企业&#xff0c;都可以用我们的软件来收款和管理他们的线上业务。 引用stripe 公司介绍的一段话&#xff1a;“我们的使命是&#xff1a;增…

TP5集成PayPal支付

项目需要使用到PayPal支付,在网上找了一圈大多写的太过简陋不易看懂,在这里详细记录集成过程方便后期使用. 第一步:下载PayPal-PHP-SDK集成到项目中 最新SDK下载地址: https://github.com/paypal/PayPal-PHP-SDK/releases 官方英文文档:点击打开链接 下载sdk解压,我们需要使用…

Android PayPal支付

最近集成完PayPal支付&#xff0c;记录一下集成注意事项。 一、PayPal版本选择 由于官方不再支持旧版的"PayPal-Android-SDK"&#xff0c;所以决定直接集成"Native Checkout SDK"。 二、集成环境 我是在Macos上开发&#xff0c;之前一直用的Android St…

如何在网站集成Payssion的国外支付方式?

如果你的用户来自海外&#xff0c;那你可能已经接入paypal ,信用卡&#xff0c;西联来收款。 今天我们再介绍另一种收款方式&#xff0c;既能极大的提高你网站的转化率&#xff0c;且在很多国家使用率高于paypal和信用卡。 这就是海外本地支付方式&#xff08;如中国的本地支…

仿牌独立站如何通过PayPal.Me亲友付进行收款

14 5月 先来看一段PP官方对于paypal me的介绍: PayPal.Me是什么 PayPal.Me是一种与您的企业账户相联的个性化链接。您仅需为自己或您的企业创建独特的自定义链接&#xff0c;分享出去即可轻松收款。这意味着&#xff0c;您无需再进行繁琐的银行转账&#xff0c;可轻松享受Pa…

stripe国际支付(对接支付宝、微信)

前言&#xff1a;stripe国际支付现在网上资料很少&#xff0c;且不支持中国&#xff0c;所以如果要用需要去支持的国家注册商户&#xff0c;官网的java demo是用的spark框架&#xff0c;我这里用的spring&#xff0c;验签需要手动验签&#xff0c;且不能用官网的方法 正文&…

再度盈利,搜狐稳了?

2016年在宣布要用3年时间回归互联网舞台中心之后&#xff0c;很长一段时间内张朝阳积极活跃在各种社交媒体上&#xff0c;完全是一派“积极出山”的姿态。而后畅游从美股退市&#xff0c;搜狗“卖身”腾讯&#xff0c;一系列的收缩动作又似乎是在逐渐远离喧嚣。 而在最近三年&a…

宝宝入托,爸妈要避开这5种心态

孩子入托&#xff0c;父母也要做好心理准备&#xff0c;尤其需要避免以下5种常见的、不良心理状态&#xff0c;否则会加重孩子入托的困难度。 01.“生离死别式”的入托状态 即每次送孩子入园&#xff0c;就像一场生离死别。宝宝屋里哭&#xff0c;家长屋外哭&#xff0c;最后多…

小孩从小就学习编程,真的有必要吗?

现今&#xff0c;许多面向儿童的计算机教程和编程语言十分风行&#xff0c;那么是否人人都应该从小学计算机呢&#xff1f; 美国前总统奥巴马曾表示&#xff0c;应该“向每个学生提供动手式的计算机科学和数学课程&#xff0c;从一开始就让他们为将来的工作做好准备。”不久&am…

你喜欢读书,还是听书?

前段时间在我的星球里做了一个小调研&#xff0c;我看一些知识付费的课程素材&#xff0c;我发现我的阅读速度&#xff0c;是播放语音效率的5倍以上&#xff0c;十几分钟的语音课程&#xff0c;我看文字可能两分钟就看完了。但我知道&#xff0c;很多人还是更喜欢聆听。 实际上…

小孩厌学,与其说教,不如和他写个游戏

表弟又闹着不去幼儿园了,我得想个办法让他体会到学习的快乐和意义…… 带娃真难 玩了一个周末,玩舒服了,周一起床后,一听要去学校,就不干了,死活不去,对我们各种撒(威)泼(逼)打(利)滚(诱),实在招架不住,只能妥协了,虽然我可以扛起他,塞进校车里,但受过良好…

20本父母必读的亲子教育书籍

作者注&#xff1a;有位好朋友成为母亲没多久&#xff0c;向我提出一个要求&#xff0c;说不知道怎么教孩子&#xff0c;看我是否能帮助推荐一些这方面的书籍。经过一段时间的搜索和整理&#xff0c;给她整理出一套书单&#xff0c;朋友看了后&#xff0c;说受益匪浅。现在她的…

读懂婴幼儿心理学,不要随便责怪孩子

读懂婴幼儿心理学&#xff0c;不要随便责怪孩子 一、不知道孩子在0-6岁时存在各种敏感期&#xff0c;把孩子在敏感期的表现当成不乖的行为斥责孩子&#xff0c;违背了孩子的天性&#xff0c;造成他的痛苦&#xff0c;留下心理隐患。 孩子在0-6岁时存在各种各样的敏感期&a…

和孩子读书学习的一点心得

这是学习笔记的第 2386篇文章 最近带着孩子做了一些实验和游戏&#xff0c;也总结了几个经验和技巧。 #1 小步迭代&#xff0c;做电路实验 最近带着孩子做电路实验&#xff0c;和上一次玩电路实验已经隔了好一段时间&#xff0c; 孩子应该都基本忘了那种感觉了&#xff0c;所以…