1。面试题先说说这篇文章可以延伸出来的面试题。一、说说SpringFramework/说说你了解的SpringFramework是一个可配置的一站式企业级Java开发框架。它的核心是IOC和AOP。它可以更轻松地构建企业级的Java应用程序,并且可以根据应用程序开发组件的需要集成相应的技术。松耦合:为了描述IOC和AOP,可能扩展IOC松耦合相关内容。Configurable:为后面的SpringBoot做铺垫(契约大于配置)IOC和AOP:InverseofControl控制反转,AspectOrientedProgramming面向切面编程2.为什么使用SpringFramework可以通过以下几点来描述:IOC实现解耦组件之间AOP切面编程统一或增强了应用业务的具体功能,可以实现应用业务的解耦和增强的逻辑容器管理应用Bean使用,托管Bean的生命周期,事件驱动机制和监控Web,事务控制,测试,与其他技术的集成3.SpringFramework包括哪些模块?beans,core,context,expression[核心包]aop[切面编程]]jdbc[整合jdbc]orm[整合ORM框架]tx[事务控制]web[Web层技术]test[集成测试]......4.依赖查找和依赖注入的比较5.BeanFactory和ApplicationContext的比较BeanFactory接口提供了一种抽象的配置和对象管理机制。ApplicationContext是BeanFactory的一个子接口,简化了与AOP、消息机制、事件机制、Web环境扩展(WebApplicationContext等)的集成。ApplicationContext主要扩展了以下功能:AOP支持(AnnotationAwareAspectJAutoProxyCreator作用于Bean初始化之后)配置元信息(BeanDefinition、Environment、annotations等)资源管理(Resourceabstraction)事件驱动机制(ApplicationEvent、ApplicationListener)消息和国际化(LocaleResolver)环境抽象(SpringFramework3.1及以后版本)二、Spring技术中的SpringFramework发展史在J2EE兴起之前,当时J2EE的学习成本极高,开发速度缓慢,开发的程序性能消耗也很高,跟不上当时应用程序的需求时间。2002年,RodJohnson写了一本书《Expert One-on-One J2EE design and development》,该书质疑了现有的J2EE应用架构和当时EJB框架的臃肿和低效,并积极寻找和探索解决方案。基于普通Java类和依赖注入的思想,提出了一种更简单的方案。这就是Spring框架核心思想的萌芽。时隔2年,2004年SpringFramework1.0.0诞生,随后RodJohnson又写了一本书**《Expert one-on-one J2EE Development without EJB》**在当时的J2EE开发圈引起了巨大的轰动。本书直接告诉开发者,不使用EJB也可以开发J2EE应用,而是可以转用更轻、更简单的A框架来代替,那就是SpringFramework。那时候开发界有各种各样的质疑声,大概是这样吧,纳尼?质疑IBM众多大佬的设计本质,这是谁?它比EJB更易于使用,不那么臃肿,并且其性能得到了改进。提供的一些特性也比EJB要好,所以慢慢转用了SpringFramework。SpringFramework重要版本的更新时间和主要特性如下所示。1.创建Maven模块,这里以ioc-learning为例2.引入依赖org.springframeworkspring-context5.2.8.RELEASE版本>3.创建配置文件ioc-learning-dl.xml4.声明公共类Person.javapublicclassPerson{}5.将Person语句添加到ioc-learning-dl.xml配置文件6.创建启动类publicclassDlAapplication{publicstaticvoidmain(String[]args){//读取配置文件,使用接口BeanFactory接收BeanFactoryfactory=newClassPathXmlApplicationContext("dl/ioc-learning-dl.xml");//通过声明的id获取对象在配置文件中Personperson=(Person)factory.getBean("person");System.out.println(person);}}7.运行并打印com.huodd.bean.Person@57baeedf成功打印全限定类名+Person的内存地址,证明写入成功3.1byName名称查找Step6核心代码Personperson=(Person)factory.getBean("person");3.2byType类型查找1.普通类1.修改配置文件ioc-learning-dl.xml语句中去掉id属性2.修改启动类publicstaticvoidmain(String[]args){BeanFactoryfactory=newClassPathXmlApplicationContext("dl/ioc-learning-dl.xml");//Personperson=(Person)factory.getBean("person");Personperson=factory.getBean(Person.class);System.out.println(person);}getBean方法参数直接传入Class类型返回值没有需要再次强制转账3.运行main方法打印如下com.huodd.bean.Person@61862a7f2。接口1.创建接口demoDao和实现类DemoDaoImplpublicinterfaceDemoDao{ListfindAll();}publicclassDemoDaoImplimplementsDemoDao{@OverridepublicListfindAll(){returnArrays.asList("user1","user2","user3");}}2.修改配置文件ioc-learning-dl.xml,增加DemoDaoImpl的声明3.修改启动类publicstaticvoidmain(String[]args){BeanFactoryfactory=newClassPathXmlApplicationContext("dl/ioc-learning-dl.xml");DemoDaodemoDao=factory.getBean(DemoDaoImpl.class);System.out.println(demoDao);System.out.println(demoDao.findAll()));}4.运行main方法打印结果如下com.huodd.dao.DemoDaoImpl@7334aada[user1,user2,user3]可以看出DemoDaoImpl注入成功,BeanFactory可以根据找到对应的实现类totheinterfacetype3.3AdvancedsearchofType根据Multipletypelookup如果一个接口有多个实现类,如何一次把所有的实现类都找出来?上面使用的getBean方法显然不能满足使用ofType方法的需要1.按照上面的代码创建2DemoDao的实现类如下,"mysql_user2","mysql_user3");}}publicclassDemoOracleDaoImplimplementsDemoDao{@OverridepublicListfindAll(){return"oracle_user1","oracle_user2","oracle_user3");}}2。修改配置文件ioc-learning-dl.xml,增加两个新实现类的声明3.修改启动类publicstaticvoidmain(String[]args){ApplicationContextctx=newClassPathXmlApplicationContext("dl/ioc-learning-dl.xml");Mapbeans=ctx.getBeansOfType(DemoDao.class);beans.forEach((beanName,bean)->{System.out.println(beanName+":"+bean.toString());});}运行主要方法打印结果如下com.huodd.dao.impl.DemoMysqlDaoImpl#0:[mysql_user1,mysql_user2,mysql_user3]com.huodd.dao.impl.DemoOracleDaoImpl#0:[oracle_user1,oracle_user2,oracle_user3]细心的朋友可能会发现原因看这里配置文件的返回值使用了ApplicationContext而不是BeanFactoryApplicationContext也是一个接口,通过IDEA的图查看类的继承链,可以看到接口继承了BeanFactory,官方文章中有这样的解释:org.springframework.beans和org.springframework.context包是SpringFramework的IO基础C容器。BeanFactory接口提供了一种高级配置机制,可以管理任何类型的对象。ApplicationContext是BeanFactory的子接口。它增加了:与SpringFramework的AOP功能轻松集成消息资源处理(用于国际化)事件发布应用程序级特定上下文,例如Web应用程序中使用的WebApplicationContext所以ApplicationContext包含了**BeanFactory的所有功能,**并且它扩展了更多功能。其实我们目前的主要原因是BeanFactory中没有getBeansOfType()方法~~~withAnnotation根据注解找到IOC容器。也可以根据类上标注的注解找到对应的Bean1。创建注解类@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public@interfaceanimal{}2.创建几个bean对象@AnimalpublicclassDog{}@AnimalpublicclassCat{}publicclassXiaoming{}其中只有类Xiaoming没有被添加了@Animal注解3.修改xml配置文件,添加如下三个声明4.修改启动类publicclassDlApplication{publicstaticvoidmain(String[]args){ApplicationContextctx=newClassPathXmlApplicationContext("dl/ioc-learning-dl.xml");Mapbeans=ctx.getBeansWithAnnotation(Animal.class);beans.forEach((beanName,bean)->{System.out.println(beanName+":"+bean);});}}5.运行main方法打印结果如下狗:com。huodd.bean.Dog@313ac989cat:com.huodd.bean.Cat@4562e04d延迟查找对于一些特殊的场景,需要依赖容器中的一些特定的bean,但是如何使用default/ordefaultstrategy来处理逻辑当它们不存在时什么?这里我们暂时删除了xml配置文件中的Dog声明,这样当我们获取到dog时,ctx.getBean(Dog.class)会报错NoSuchBeanDefinitionException1。现有方案启用默认策略Dogdog;try{dog=ctx.getBean(Dog.class);}catch(NoSuchBeanDefinitionExceptione){//找不到Dog时手动创建dog=newDog();}System.out.println(dog);这里我们写业务代码在catchcode块中,不够优雅,性能有待提升,而且如果后期每个bean都这样处理,代码量会很大2.checkDogdog=ctx.containsBean("dog")?(Dog)ctx.getBean("dog"):newDog();这里使用了ApplicationContext中的containsBean方法来检测容器中是否存在指定的bean。这个方法貌似没问题,但是要考虑到这个方法传递的参数只能传递beanid不能根据bean的类型来查找。如果bean的名字是其他的,工作量还是很大的。当我们真正使用的时候,去“拆包”查看里面有没有Bean对象。使用方法如下:ObjectProviderdogProvider=ctx。以上想法处理完毕,返回给我们一个“包裹”。我们使用的时候直接调用getObject方法,但是如果容器中没有这个Bean,还是会报NoSuchBeanDefinitionException。下面介绍ObjectProvidergetIfAvailable()提供的其他方法。当在不抛出异常的情况下找不到Bean时,该方法可以返回null。下面的方法可以用来实现Dogdog=dogProvider.getIfAvailable(Dog::new);ifAvailable()这个方法是获取到Bean后立即或者间歇使用代码下面的dogProvider.ifAvailable(dog->System.out.println(dog));//或者使用方法参考上面关于SpringFramework以及IoC依赖搜索相关的内容,小伙伴们可以去置顶查看下面的面试题,是不是都看懂了,掌握了?