生存不会依照你想要的形式进行,它会给你一段时间,让你孤单又怅惘,等你度过高潮,那些独处的时光必然能照亮你的路。走得最急的,都是最美的风光;伤得最深的,也总是那些最真的感情。拾掇起情绪,持续向前走,就会发现:错过花,你将播种雨,错过雨,你会遇到彩虹。
  1. 面试题

先说下该篇文章可延长出的面试题.

1. 谈谈SpringFramework / 说说你了解的SpringFramework

SpringFramework 是一个开源的、松耦合的、分层的、可配置的一站式企业级 Java 开发框架,它的外围是 IOC 与 AOP ,它能够更容易的构建出企业级 Java 利用,并且它能够依据利用开发的组件须要,整合对应的技术。

松耦合的: 为了形容IOC和AOP, 可能会延长出IOC松耦合相干内容 可配置: 给前面的SpringBoot(约定大于配置)做铺垫 IOC 与 AOP: Inverse of Control 管制反转、Aspect Oriented Programming 面向切面编程


2. 为何应用SpringFramework

可通过如下几点进行形容:

  1. IOC 实现了组件之间的解耦
  2. AOP 切面编程将利用业务做对立或特定的性能加强, 可实现利用业务与加强逻辑的解耦
  3. 容器治理利用中应用的Bean、托管Bean的生命周期、事件与监听的驱动机制
  4. Web、事务管制、测试、与其余技术的整合
    • *

3. SpringFramework蕴含哪些模块?

  • beans、core、context、expression 【外围包】
  • aop 【切面编程】
  • jdbc 【整合 jdbc 】
  • orm 【整合 ORM 框架】
  • tx 【事务管制】
  • web 【 Web 层技术】
  • test 【整合测试】
  • ......
    • *

4. 依赖查找与依赖注入的比照

作用指标

实现形式

依赖查找(DL)

通常是类成员

应用上下文(容器)被动获取

依赖注入(DI)

能够是办法体内也能够是办法体外

借助上下文被动的接管


5. BeanFactory与ApplicationContext的比照

BeanFactory 接口提供了一个形象的配置和对象的管理机制,

ApplicationContext 是 BeanFactory 的子接口,它简化了与 AOP 的整合、音讯机制、事件机制,以及对 Web 环境的扩大( WebApplicationContext 等)

ApplicationContext 次要扩大了以下性能:

  • AOP 的反对( AnnotationAwareAspectJAutoProxyCreator 作用于 Bean 的初始化之后 )
  • 配置元信息( BeanDefinitionEnvironment 、注解等 )
  • 资源管理( Resource 形象 )
  • 事件驱动机制( ApplicationEventApplicationListener
  • 音讯与国际化( LocaleResolver
  • Environment 形象( SpringFramework 3.1 当前)
    • *
  1. SpringFramework发展史

在Spring技术之前,J2EE衰亡,过后的J2EE学习老本极高,开发速度慢,开发进去的程序性能耗费也高,曾经跟不上过后应用程序的须要。 在2002 年,Rod Johnson写了一本书名为《Expert One-on-One J2EE design and development》 ,书中对过后现有的 J2EE 利用的架构和EJB框架存在的臃肿、低效等问题提出了质疑,并且踊跃寻找和摸索解决方案。

基于一般Java类和依赖注入的思维提出了更为简略的解决方案,这便是Spring框架核心思想的萌芽

过了 2 年,2004 年 SpringFramework 1.0.0 横空出世,随后 Rod Johnson 又写了一本书《Expert one-on-one J2EE Development without EJB》,过后在 J2EE 开发界引起了微小轰动,这本书中间接通知开发者齐全能够不应用 EJB 开发 J2EE 利用,而是能够换用一种更轻量级、更简略的框架来代替,那就是 SpringFramework

那时在开发界是种种的质疑,大略是这样的,纳尼? 质疑IBM诸多大佬的设计精髓,这个是什么人?为何如此嚣张? 而后 还是被一些开发者尝试应用了,应用后发现的确要比EJB好用,不那么臃肿,性能也有所改善,提供的一些个性也优于EJB,于是就缓缓转投SpringFramework

上面展现下SpringFramework重要版本的更新工夫及次要个性

SpringFramework版本

对应jdk版本

重要个性

SpringFramework 1.x

jdk 1.3

基于 xml 的配置

SpringFramework 2.x

jdk 1.4

改进 xml 文件、初步反对注解式配置

SpringFramework 3.x

Java 5

注解式配置、JavaConfig 编程式配置、Environment 形象

SpringFramework 4.x

Java 6

SpringBoot 1.x、外围容器加强、条件拆卸、WebMvc 基于 Servlet3.0

SpringFramework 5.x

Java 8

SpringBoot 2.x、响应式编程、SpringWebFlux、反对 Kotlin

  1. IOC依赖查找

根底框架搭建

  1. 创立Maven模块,这里以ioc-learning为例
  2. 引入依赖
<dependency>    <groupId>org.springframework</groupId>    <artifactId>spring-context</artifactId>    <version>5.2.8.RELEASE</version></dependency>复制代码
  1. 创立配置文件 ioc-learning-dl.xml
<?xml version="1.0" encoding="UTF-8"?>   <beans xmlns="http://www.springframework.org/schema/beans"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xsi:schemaLocation="http://www.springframework.org/schema/beans           https://www.springframework.org/schema/beans/spring-beans.xsd">      </beans>复制代码
  1. 申明一般类Person.java
public class Person {}复制代码
  1. ioc-learning-dl.xml配置文件退出Persion的申明
<bean id="person" class="com.huodd.bean.Person"></bean>复制代码
  1. 创立启动类
public class DlApplication {    public static void main(String[] args) {        // 读取配置文件  应用接口 BeanFactory 接管         BeanFactory factory = new ClassPathXmlApplicationContext("dl/ioc-learning-dl.xml");        // 通过配置文件中申明的 id 进行对象的获取        Person person = (Person) factory.getBean("person");        System.out.println(person);    }}复制代码
  1. 运行打印
com.huodd.bean.Person@57baeedf复制代码

胜利打印出 Person 的全限定类名 + 内存地址,证实编写胜利。

3.1 byName 名称查找

上述根底框架中的步骤6

外围代码

Person person = (Person) factory.getBean("person");复制代码

3.2 byType 类型查找

1. 一般类

  1. 批改配置文件 ioc-learning-dl.xmlperson的申明中id属性去掉
<bean class="com.huodd.bean.Person"></bean>复制代码
  1. 批改启动类
public static void main(String[] args) {        BeanFactory factory = new ClassPathXmlApplicationContext("dl/ioc-learning-dl.xml");//        Person person = (Person) factory.getBean("person");        Person person = factory.getBean(Person.class);        System.out.println(person);    }复制代码

getBean办法参数中间接传入Class类型 返回值也无需再进行强转

  1. 运行main办法 打印如下
com.huodd.bean.Person@61862a7f复制代码

2. 接口

  1. 创立接口demoDao 以及 实现类 DemoDaoImpl
public interface DemoDao {    List<String> findAll();}public class DemoDaoImpl implements DemoDao{    @Override    public List<String> findAll() {        return Arrays.asList("user1", "user2", "user3");    }}复制代码
  1. 批改配置文件 ioc-learning-dl.xml 退出 DemoDaoImpl的申明
<bean class="com.huodd.dao.DemoDaoImpl"></bean>复制代码
  1. 批改启动类
 public static void main(String[] args) {        BeanFactory factory = new ClassPathXmlApplicationContext("dl/ioc-learning-dl.xml");        DemoDao demoDao = factory.getBean(DemoDaoImpl.class);        System.out.println(demoDao);        System.out.println(demoDao.findAll());    }复制代码
  1. 运行main办法 打印后果如下
com.huodd.dao.DemoDaoImpl@7334aada[user1, user2, user3]复制代码

由此可见 DemoDaoImpl 注入胜利 并且BeanFactory能够依据接口类型找到对应的实现类

3.3 高级查找

ofType 依据类型查找多个

如果一个接口有多个实现类,如何一次性的把所有的实现类都取出来呢? 后面用到的getBean办法显然无奈满足 需应用到ofType办法

  1. 继下面的代码 创立2个DemoDao的实现类 如下
public class DemoMysqlDaoImpl implements DemoDao {    @Override    public List<String> findAll() {        return Arrays.asList("mysql_user1", "mysql_user2", "mysql_user3");    }}public class DemoOracleDaoImpl implements DemoDao {    @Override    public List<String> findAll() {        return Arrays.asList("oracle_user1", "oracle_user2", "oracle_user3");    }}复制代码
  1. 批改配置文件 ioc-learning-dl.xml 退出新建的两个实现类的申明
 <bean class="com.huodd.dao.impl.DemoMysqlDaoImpl"></bean> <bean class="com.huodd.dao.impl.DemoOracleDaoImpl"></bean>复制代码
  1. 批改启动类
public static void main(String[] args) {        ApplicationContext ctx = new ClassPathXmlApplicationContext("dl/ioc-learning-dl.xml");        Map<String, DemoDao> beans = ctx.getBeansOfType(DemoDao.class);        beans.forEach((beanName, bean) -> {            System.out.println(beanName + " : " + bean.toString());        });    }复制代码

运行main办法 打印后果如下

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 而不应用BeanFactory

ApplicationContext 也是一个接口,通过IDEA的diagram查看类的继承链,能够看到该接口继承了BeanFactory

官网文章中有这样的解释:

org.springframework.beansorg.springframework.context 包是 SpringFramework 的 IOC 容器的根底。BeanFactory 接口提供了一种高级配置机制,可能治理任何类型的对象。ApplicationContextBeanFactory 的子接口。它减少了:

  • 与 SpringFramework 的 AOP 性能轻松集成
  • 音讯资源解决(用于国际化)
  • 事件公布
  • 应用层特定的上下文,例如 Web 应用程序中应用的 WebApplicationContext

如此说来 ApplicationContext 蕴含了 BeanFactory 的所有性能,并且还扩大了更多的个性

其实对于咱们目前的最次要起因是BeanFactory 中木有getBeansOfType()这个办法~~~

withAnnotation 依据注解查找

IOC 容器还能够依据类上标注的注解来查找对应的 Bean

  1. 创立一个注解类
@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public @interface animal {}复制代码
  1. 创立几个bean对象
@Animalpublic class Dog {}@Animalpublic class Cat {}public class Xiaoming {}复制代码

其中只有Xiaoming这个类没有增加@Animal注解

  1. 批改XML配置文件,增加如下三个申明
<bean id="dog" class="com.huodd.bean.Dog"></bean><bean id="cat" class="com.huodd.bean.Cat"></bean><bean id="xiaoming" class="com.huodd.bean.Xiaoming"></bean>复制代码
  1. 批改启动类
public class DlApplication {    public static void main(String[] args) {        ApplicationContext ctx = new ClassPathXmlApplicationContext("dl/ioc-learning-dl.xml");        Map<String, Object> beans = ctx.getBeansWithAnnotation(Animal.class);        beans.forEach((beanName, bean) -> {            System.out.println(beanName + " : " + bean);        });    }}复制代码
  1. 运行main办法 打印后果如下
dog : com.huodd.bean.Dog@313ac989cat : com.huodd.bean.Cat@4562e04d复制代码

提早查找

对于一些非凡场景,须要依赖容器中某些特定的bean 然而当他们不存在时如何应用默认/或者缺省策略来解决逻辑呢?

这里咱们先把xml配置文件中的 Dog 的申明临时删掉

这样咱们在获取dog的时候ctx.getBean(Dog.class) 就会报错 NoSuchBeanDefinitionException

  1. 现有计划启用缺省策略
Dog dog;try {    dog = ctx.getBean(Dog.class);} catch (NoSuchBeanDefinitionException e) {    // 找不到Dog时手动创立    dog = new Dog();}System.out.println(dog);复制代码

这里咱们把业务代码写在了catch代码块中,不够优雅,性能也有待改善,而且如果前期每个bean都这样解决,代码量微小

  1. 革新下 获取之前查看
 Dog dog = ctx.containsBean("dog") ? (Dog) ctx.getBean("dog") : new Dog();复制代码

这里应用到了ApplicationContext中的办法 containsBean 用于查看容器中是否有指定的bean

该办法看似曾经没有问题了,然而要思考到该办法传递的参数只能传递bean的id 不能依照bean的类型去查找 如果bean的名字是其余的呢,工作量还是微小的

  1. 应用提早查找

该机制的大略思路为 当咱们想要获取一个Bean的时候,先返回给咱们一个包装类,等到咱们真正去应用的时候再去“拆包”查看外面到底有没有该Bean对象

应用办法如下

ObjectProvider<Dog> dogProvider = ctx.getBeanProvider(Dog.class);复制代码

下面代码能够看到 就是依照后面的思路进行解决的,返回了一个“包装”给咱们,当咱们应用的时候间接调用getObject办法

但如果 容器中没有该Bean 还是会报 NoSuchBeanDefinitionException ,上面会介绍下ObjectProvider提供的其余办法

  • getIfAvailable()该办法能够在找不到Bean的时候返回null 而不抛出异样

    能够应用如下办法实现

    Dog dog = dogProvider.getIfAvailable(Dog::new);复制代码
  • ifAvailable()该办法是在取到Bean后马上或者间歇的应用

    代码如下

    dogProvider.ifAvailable(dog -> System.out.println(dog)); // 或者应用办法援用复制代码

以上就是对于SpringFramework以及IoC的依赖查找相干内容,小伙伴能够再去顶部查看上面试题,是否都能够了解了并且把握了呢.