Spring框架详解

文章目录

  • Spring是什么?
  • Spring的优点是什么?
  • Spring IoC
    • 什么是IoC?
    • 什么是DI?
  • Spring AOP
  • Spring容器的启动流程
  • Spring Bean
  • Spring循环依赖问题
  • Spring的自动装配
  • Spring事务
    • Spring管理事务的方式
    • 事务的传播机制
    • 事务的隔离级别
    • Transactional自动事务管理会在以下情况中失效(声明式事务失效场景)
  • Spring框架中用到的设计模式
  • Spring注解
    • @Autowired和@Resource的区别
  • Spring整体解析
    • BeanFactory和ApplicationContext
  • Spring Framework
  • BeanFactory和ApplicationContext
    • BeanFactory和ApplicationContext的关系
    • SpringBean的配置
  • Spring实例化的方式
    • 通过构造方法实例化Bean
    • 通过工厂方式实例化Bean
    • Spring中标签的用法
    • Spring中获取bean的方式
    • 配置自定义和非自定义Bean—Connection
    • Bean实例化的基本流程
    • Spring Bean的后处理器
  • Spring Bean的生命周期
    • Bean的实例化阶段
    • Bean的初始化阶段
    • Bean的实例属性填充
    • Bean的完成阶段
  • Spring的注解的使用与开发
    • 使用@Component替换bean标签
  • AOP思想

Spring是什么?

Spring是一个轻量级(核心jar包比较小,但是数量多),非侵入式(框架代码不会侵入业务代码,业务代码也不会实现或继承框架中接口或类)的IoC和AOP容器框架。是为Java应用程序提供基础性服务的一套框架,目的是用于简化企业级应用程序的开发,它使得开发者只需关心业务需求。

Spring的优点是什么?

  1. 轻量级:Spring 是轻量级的,基础版本只有2MB
  2. 非侵入式: 框架代码不会侵入业务代码,业务代码也不会实现或继承框架中接口或类
  3. 控制反转(IoC):Spring 使用 IoC 容器管理对象的生命周期和依赖关系,降低了组件间的耦合性
  4. 面向切面编程(AOP):Spring 支持 AOP,可以方便地实现如日志记录、事务管理等功能
  5. 声明式事务管理:Spring 提供声明式事务管理,可以将事务管理代码从业务逻辑代码中分离出来
  6. 集成:Spring 提供了与各种 ORM 框架(如 Hibernate、JPA 等)的集成,以及与 JEE 和 JMS 的集成
  7. 测试:Spring 提供了强大的测试框架,可以轻松地进行单元测试和集成测试
  8. 灵活性:Spring 的模块化设计使得用户可以根据需要选择使用哪些模块,而不是必须全部使用

Spring IoC

Spring框架就相当于创建了一个Bean对象,然后使用这个对象去操控和实现一系列功能的框架,然后SpringIoC的话就是将你手动new Bean的这个过程,这个权力,反转给了第三方,也就是Spirng容器,当你需要使用Bean对象或者需要去创建,那么直接去第三方那里去找

什么是IoC?

IoC(Inversion of Control:控制反转) 是一种设计思想,而不是一个具体的技术实现。IoC的思想就是将原本在程序中手动创建对象的控制权交给Spring框架来管理。不过IoC不是Spring特有的,在其他语言中也有应用。

Spring框架详解_第1张图片

以前创建对象的时机和主动权都是由自己把控的,如果在一个对象中使用另外的对象,就必须主动通过new指令去创建依赖对象,使用完后还需要销毁(比如Connection等)。而 IOC 则是由专门的容器来帮忙创建对象,将所有的类都在 Spring 容器中登记,当需要某个对象时,不再需要自己主动去 new 了,只需告诉 Spring 容器,然后 Spring 就会在系统运行到适当的时机,把你想要的对象主动给你。

对于某个具体的对象而言,以前是由自己控制它所引用对象的生命周期,而在IOC中,所有的对象都被 Spring 控制,控制对象生命周期的不再是引用它的对象,而是Spring容器,由 Spring 容器帮我们创建、查找及注入依赖对象,而引用对象只是被动的接受依赖对象,所以这叫控制反转。

什么是DI?

DI就是依赖注入,就是强调Bean之间的关系,如果创建一个Bean需要和另一个Bean之间需要创建某种关联,这时候他们的这种关系就是由第三发去设置

IoC的一个重点就是在程序运行时,动态的向某个对象提供它所需要的对象,这一点是通过DI(Dependency Injection:依赖注入)来实现的,即程序在运行时依赖IoC容器来动态注入对象所需要的外部依赖。而Spring的DI具体就是通过反射实现注入的,反射允许程序在运行时动态的生成对象、执行对象的方法、修改对象的属性。

Spring AOP

OOP面向对象,允许开发者定义纵向的关系,但不适用于定义横向的关系,会导致大量代码重复,不利于各个模块的重用,而AOP就是OOP的扩展

Spring框架详解_第2张图片

AOP(Aspect-Oriented Programming:面向切面编程) 能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。主要作用是分离功能性需求和非功能性需求,使开发人员可以集中处理某一个关注点或者横切逻辑,减少对业务代码的侵入,增强代码的可读性和可维护性。

简单的说,AOP 的作用就是保证开发者在不修改源代码的前提下,为系统中的业务组件添加某种通用功能。

AOP 切面编程设计到的一些专业术语:

术语 含义
目标(Target) 被通知的对象
代理(Proxy) 向目标对象应用通知之后创建的代理对象
连接点(JoinPoint) 目标对象的所属类中,定义的所有方法均为连接点
切入点(Pointcut) 被切面拦截 / 增强的连接点(切入点一定是连接点,连接点不一定是切入点)
通知(Advice) 增强的逻辑 / 代码,也即拦截到目标对象的连接点之后要做的事情
切面(Aspect) 切入点(Pointcut)+通知(Advice)
Weaving(织入) 将通知应用到目标对象,进而生成代理对象的过程动作

Spring容器的启动流程

1、初始化Spring容器,注册内置的BeanPostProcessor的BeanDefinition到容器中

2、将配置类的BeanDefinition注册到容器中

3、调用refresh()方法刷新容器

Spring Bean

在Spring框架中,Bean是指由Spring容器管理的对象。它是Spring框架的核心概念之一,用于解耦应用程序中的组件,并提供了依赖注入和面向切面编程等功能。

Spring循环依赖问题

Spring的自动装配

Spring事务

一次对数据库操作,其中可能会有多条SQL语句,数据库要保证多条sql要一起执行成功,要么都不执行,数据库要对整个过程进行控制,成为数据库事务管理。

Spring管理事务的方式

  • 编程式事务(不推荐使用): 通过 TransactionTemplate或者 TransactionManager 手动管理事务,实际应用中很少使用
  • 声明式事务: 在XML配置文件中配置或者直接基于注解(推荐使用):实际是通过AOP实现(基于@Transactional 的全注解方式使用最多)

事务的传播机制

Spring事务的传播机制说的是,当多个事务同时存在的时候,Spring如何处理这些事务的行为。事务传播机制实际上是使用简单的ThreadLocal实现的,所以,如果调用的方法是在新线程调用的,事务传播实际上是会失效的

  • PROPAGATION_REQUIRED:(默认传播行为)如果当前没有事务,就创建一个新事务;如果当前存在事务,就加入该事务。
  • PROPAGATION_REQUIRES_NEW:无论当前存不存在事务,都创建新事务进行执行。
  • PROPAGATION_SUPPORTS:如果当前存在事务,就加入该事务;如果当前不存在事务,就以非事务执行。
  • PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
  • PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行;如果当前没有事务,则按REQUIRED属性执行。
  • PROPAGATION_MANDATORY:如果当前存在事务,就加入该事务;如果当前不存在事务,就抛出异常。
  • PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。

事务的隔离级别

  • ISOLATION_DEFAULT:这是个 PlatfromTransactionManager 默认的隔离级别,使用数据库默认的事务隔离级别。
  • ISOLATION_READ_UNCOMMITTED:读未提交,允许事务在执行过程中,读取其他事务未提交的数据。
  • ISOLATION_READ_COMMITTED:读已提交,允许事务在执行过程中,读取其他事务已经提交的数据。
  • ISOLATION_REPEATABLE_READ:可重复读,在同一个事务内,任意时刻的查询结果都是一致的。
  • ISOLATION_SERIALIZABLE:所有事务逐个依次执行。

Transactional自动事务管理会在以下情况中失效(声明式事务失效场景)

① 修饰一个非public的方法回导致事务失效
②方法中出现异常被try catch捕获,认为方法没有出现异常事务正常提交
③ 默认情况下出现编译期异常,会导致事务失效,rollbackFor=Exception.class(任何异常都不会提交事务)
④ 事务传播行为设置错误
⑤ 数据库引擎不支持事务,mysql中只有InnoDB引擎支持事务
⑥ 必须是Spring框架创建的类
⑦ 在同一个类的一个非事务方法中(一个调用一个,被调用的头上有),通过this调用事务方法,此时是通过非代理对象调用的,导致事务失效。

Spring框架中用到的设计模式

工厂设计模式 : Spring 使用工厂模式通过 BeanFactoryApplicationContext 创建 bean 对象。

代理设计模式 : Spring AOP 功能的实现。

单例设计模式 : Spring 中的 Bean 默认都是单例的。

模板方法模式 : Spring 中 jdbcTemplatehibernateTemplate 等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式。

包装器设计模式 : 我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。

观察者模式: Spring 事件驱动模型就是观察者模式很经典的一个应用。

适配器模式 : Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式适配Controller

Spring注解

  1. @Component:用于将类标识为Spring管理的组件。通常与@Autowired@Resource一起使用,用于自动装配依赖。
  2. @Autowired:用于自动装配依赖注入。可以用于字段、构造方法或Setter方法上,让Spring自动完成依赖对象的注入。
  3. @Service@Repository@Controller:分别标记服务层、数据访问层、控制层的组件,它们都是@Component的特化。
  4. @Configuration:用于标识配置类,指示Spring使用该类来进行配置,等效于XML配置文件。
  5. @Bean:在配置类中,标记一个方法为Bean的定义方法。
  6. @Value:注入属性值。
  7. @Scope:指定Bean的作用域。
  8. @Transactional:声明式事务管理,标记一个方法或类需要在事务中执行。
  9. @Qualifier:当有多个同类型的Bean时,用于指定需要注入哪一个。
  10. @RequestMapping:处理请求的映射。
  11. @Aspect:用于定义切面,结合其他注解实现面向切面编程(AOP)。

@Autowired和@Resource的区别

@Autowired 是 Spring 提供的注解,@Resource 是 JDK 提供的注解。

Autowired 默认的注入方式为byType(根据类型进行匹配),@Resource默认注入方式为 byName(根据名称进行匹配)。

当一个接口存在多个实现类的情况下,@Autowired@Resource都需要通过名称才能正确匹配到对应的 Bean。Autowired 可以通过 @Qualifier 注解来显式指定名称,@Resource可以通过 name 属性来显式指定名称

Spring整体解析

BeanFactory和ApplicationContext

BeanFactory是ApplicationContext的父接口,是Spring中的核心容器,使用时是组合使用,ApplicationContext是实现了BeanFactory接口,重写了其中的方法,方法的使用上都组合了它的功能

BeanFactory中的接口主要是getBean

但是控制反转、依赖注入、Bean的生命周期的各种功能,都是由它的实现类提供

Spring框架详解_第3张图片

DefaultListableBeanFactory:这个类可以管理所有的Bean,最主要的是它可以管理单例对象,在DefaultSingletonBeanRegistry这个类中他管理了所有的单例对象

Spring Framework

Spring框架详解_第4张图片

Spring是从下往上,第一部分核心容器,包括四部分,也就是开发时会引入四个jar包,在引入Context的时候,内部会自动引入其他三个,Beans就是我们常用的Bean,Core就是核心容器,Context就是上下文,SpEL代表Spring的一种表达式就是EL表达式,再往上一层就是AOP,在往上就是数据访问层,和Web层,也就是说他们都是核心容器和AOP之上构建的,所以属于上层直接使用的东西

BeanFactory和ApplicationContext

在之前说的第三方就是BeanFactory去通过工厂模式产生Bean的,在执行Spring的时候,会有一个配置文件XML,一般将配置的文件执行的代码放在XML文件中,然后第三方去执行相应的操作,产生相应的Bean。首先BeanFactory这个是Spring提供的,我们需要通过坐标导入相应的依赖,然后定义一个UserService接口将他实现,并且创建一个UserServermpl实现类,创建一个xml文件,将这个实现类的信息配置到xml文件中,最后测试,创建BeanFactory,通过Bean工厂去加载配置文件,获取UserService实例对象



beans.xml配置文件中配置bean


		// 创建工厂对象
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        // 创建读取器(XML文件)
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
        // 读取配置文件给工厂
        reader.loadBeanDefinitions("beans.xml");
        // 根据id获取Bean实例对象
        UserService userService = (UserService) beanFactory.getBean("userService");
        System.out.println(userService);

当我们将需要创建的bean对象配置在beans.xml配置文件中,Bean工厂会自动识别帮我们创建相应的Bean对象

创建其他对象,先去编写对应的类,再去配置文件,再去最终修改,然后使用客户端代码去获取对应的Bean


    
        
    

    

在userService这个Bean对象的内部定义一个名为userDao的属性,也就是这个userDao引用与userDao的Bean对象,也就是说在Spring运行时将userDao的Bean注入到userService的Bean中,这个userDao对应的就是UserService中的方法setUserDao,在执行Spring的时候默认就配置执行。这个就是DI,依赖注入,就是在配置文件中将Dao直接注入给Service,依赖注入就是说允许程序运行过程中,可以动态的向一个对象中提供他所需要的另一个对象,也就是说程序可以通过IoC动态的为对象注入他所需要的依赖,Spring中的依赖注入是由反射实现的,反射可以获取一个类中的对象和属性,然后动态的将对象创建和注入。注入的话需要两部,在需要注入的bean对象下property配置注入,然后在需要注入的类中创建set方法接收注入的对象。

简单说说IoC就是,控制反转,就是将原本自己手动new Bean对象的能力反转给了BeanFactory,当Spring运行的时候就回去配置文件中找配置的bean,然后创建相应的bean。


		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = (UserService) applicationContext.getBean("userService");
        System.out.println(userService);

上面说到使用BeanFactory可以控制IoC实现控制反转创建相应的Bean对象,但是有一个类ApplicationContext,称为Spring容器,它内部封装了BeanFactory,并且比BeanFactory的功能更加强大,可以直接省去创建工厂和创建读取类,直接加载配置文件,实例化容器,并根据beanName获取容器相应的Bean实例

BeanFactory和ApplicationContext的关系

Spring框架详解_第5张图片

BeanFactory是Spring早期的接口,是Bean工厂,主要是管理Bean,而ApplicationContext是后期更高级的接口,称为Spring容器。ApplicationContext是对BeanFactory基础的功能上进行了扩展,BeanFactory的API更偏向于底层,而ApplicationContext的API更像是将底层API进行封装;Bean的创建的主要逻辑和功能都被封装在BeanFactory中,所以ApplicationContext继承BeanFactory,又维护着BeanFactory的引用,就说说BeanFactory是ApplicationContext中的一个属性。最后就是两者的对于Bean的初始化的时机不同,原始BeanFactory是在首次调用getBean是才进行创建,而ApplicationContext是在配置文件加载,容器一创建就将Bean都实例化并初始化好的。


Spring框架详解_第6张图片

多出来的这些国际化,资源访问,事件监听等功能是由于Application不仅继承了BeanFactory这一个方法,还继承了像MessageSource(国际化),FunctionalInterface(事件监听),ResourceLoader(资源访问)这些接口。


ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");

在这个加载配置文件中,经常还会调用的除了这个还有两个,其中File那个是用来加载本地磁盘中的配置文件,Ann那个是用来加载注解类配置文件的

Spring框架详解_第7张图片


当导入web依赖之后,在ApplicationContext下会多出两个类,是基于web环境下的配置加载

Spring框架详解_第8张图片

SpringBean的配置

Spring框架详解_第9张图片

如果不设置id,在启动过程中id默认转化为那么,那么在启动过程中会创建这个对象,然后默认id是它本身的权限名,也就是类地址。它的底层是一个HashMap的结构,key存储的是这个id,value存储的是创建的这个bean对象。


Spring框架详解_第10张图片

使用name设置别名,存储在一个单独的集合中,如果没有设置id,那么默认的是第一个name,scope的话是用来设置Bean的作用范围,主要有singleton和prototype,singleton是单例的,默认值,在Spring容器创建的时候,就会对Bean进行实例化,并存储到容器内部,每次getBean获取的都是相同的Bean,而使用prototype,这个是原型的,Spring容器初始化时不会创建Bean实例,当调用getBean时才会实例化Bean,每次getBean都会创建一个新的Bean实例,设置lazy-init,也就是Bean的延迟加载,也就是当Spring创建容器的时候,不会立刻创建Bean实例,等待用到时再创建Bean实例并存储到单例池中去,后续再使用该Bean直接从单例池获取即可,本质上Bean还是单例的,init-method,Bean实例化后执行的初始化方法,method是指定方法名,destroy-method,就是Bean实例销毁前的方法,method指定的就是是方法名,初始化方法和销毁方法,销毁时要显式的去销毁调用close,然后关闭容器,bean方法就全部销毁,不然默认不会销毁


在创建Bean对象过程中,配置init-method和destroy-method可以在构造时和Bean销毁时调用方法进行操作,还有一种方式,就是实现InitializingBean接口,然后重写afterPropertiesSet(),方法在其中写入操作,一般会在init-method之后执行,这个方法是与Bean的生命周期相关的

如果对象创建完毕想要进行一些初始化工作如何完成

  1. 创建一个方法,在配置Bean的时候使用init-method进行调用
  2. 实现InitializingBean接口,然后重写afterPropertiesSet接口

Spring实例化的方式

常见创建Bean的方式是反射找构造方法的方式,但是也有工厂方式创建Bean对象

通过构造方法实例化Bean


    
    
    

通过工厂方式实例化Bean

静态工厂方法实例化Bean

方法是静态的,在配置的时候不需要创建对象,可以直接使用类调用

<bean id="userDao1" class="com.springdemo.factory.MyBeanFactory" factory-method="userDao"></bean>

创建一个类,其中定义一个静态方法,其中的返回值就是需要创建的对象,在配置bean的时候,在默认情况下会寻找这个类的构造方法,然后创建这个类的对象,但是我们要实现静态工厂的实例化,那么就在配置的时候使用factory-method,指向创建的静态方法,然后在初始化的时候就会默认调用这个静态方法,去创建这个静态方法返回的对象,并且还可以在这个Bean创建之前可以进行一些其他业务操作


实例工厂方法实例化Bean

实例工厂必须先有工厂对象,然后通过工厂对象去调用相应的实例方法

	<!--创建工厂类-->
    <bean id="beanFactory1" class="com.springdemo.factory.MyBeanFactory1"></bean>

    <bean id="userDao2" factory-bean="beanFactory1" factory-method="userDao"></bean>

只要是内部产生bean的方法,都可以使用constructor-arg来创建参数


实现FactoryBean规范延迟实例化Bean

public class MyBeanFactory2 implements FactoryBean<UserDao> {


    public UserDao getObject() throws Exception {
        return new UserDaoImpl();
    }

    public Class<?> getObjectType() {
        return UserDao.class;
    }
}

实现FactoryBean接口,然后重写getObject和getObjectType方法,在创建对象的时候会发现,存储在BeanFactory里面的是MyBeanFactory2的工厂对象。

Spring中标签的用法

bean: Spring中的最基本的标签,用于定义bean,里面有id,name,class,scope,init-method,destroy-method,lazy-init

property: 用于在bean中配置属性,就是通过此标签可以直接将属性值设置到bean对象中

constructor-arg: 用于在Bean中配置构造函数参数

import: 用于导入其他Spring的配置文件

annotation: 用于启动bean的自动装配和依赖注入功能

alias: 用于为bean指定一个别名,方便使用时引用


自定义命名引用

在创建Spring容器中,一般都是先加载xml文件,我们引入的一些工具需要在xml文件头中使用链接的方式导入进来,然后用标签使用,在引入过程中,他会给引入的链接设置别名,这个时候将所有的别名进行修改,就可以修改其命名。

Spring框架详解_第11张图片

Spring中获取bean的方式

Spring框架详解_第12张图片

第一种比较常见,就是直接使用beanName获取但是需要强转,第二种使用类型获取,一般是从容器中获取,需要容器中bean是唯一的,第三种是在根据beanName获取时导入类型,这种获取不用进行强转

配置自定义和非自定义Bean—Connection

Spring框架详解_第13张图片

定义bean 其中class地址指向需要配置的类,然后配置其中的参数

Bean实例化的基本流程

在Spring容器初始化时,会加载xml配置文件中的将这些bean信息分别封装为BeanDefinition对象,并将这些对象存储在一个名为beanDefinitionMap的一个Map集合中,这个集合也是由beanFactory来进行管理的,然后Spring在初始化时,会将这个beanDefinitionMap这个集合中的bean信息遍历出来,使用拿到的信息进行反射来创建bean实例对象,将所有创建好的bean对象存储在一个名为singletonObjects的Map集合中,当调用getBean时就从这个Map集合中去查找相应的bean信息。

Spring Bean的后处理器

Bean的后处理器的作用是处理Spirng容器中Bean的生命周期事件的拦截器,通过使用后处理器我们可以对Bean的生命周期进行更细粒度的控制,并在特定的生命周期事件发生时执行相应的操作。

Spring Bean的生命周期

SpringBean的生命周期顾名思义就是Bean对象从创建到销毁的过程,Bean的销毁一般都是因为Bean容器的关闭而进行自动销毁,或者是手动直接调用销毁方法而进行销毁,在销毁时可以配置destory-method执行一个方法,因此说到Bean的生命周期一般说的较多的是Bean从实例化之后,即反射创建出对象之后,再到Bean成为一个完整的对象,最终存储在单例池(singlentonObjects)中,这个过程称为Bean的生命周期

Bean的实例化阶段

在初始化Spring容器的时候,会去加载xml文件中的配置,将其中的配置bean信息分别封装为BeanDefinition对象,然后将这些对象存储在名为beanDefinitionMap的一个Map集合中,这个集合也就是由BeanFactory管理的。

实例化的化,可以使用无参构造和有参构造,还可以使用工厂方式,静态工程,实例工厂,还有就是bean在配置完成之后不需要马上创建对象,内部会有if else进行判断,就是判断其中的的bean配置,是否是lazy-init的,如果是就不会立即进行创建,等到getBean的时候在进行创建,是否是单例singleton的,如果是prototype就不会立即创建,在调用getBean的时候再进行创建,是否是BeanFactory,如果是工厂Bean就用工厂Bean的方式进行创建

Bean的初始化阶段

在这里插入图片描述

在Bean初始化的时候,会将beanDefinitionMap这个集合进行遍历,获取到其中每一个Bean的对象信息,通过反射创建创建实例对象。也就是对这些对象进行属性注入,就是依赖注入,执行一些接口方法,比如Aware,还有执行BeanPostProcesser方法,还有一系列的接口方法等

  • Bean的实例属性填充
  • Aware接口属性注入
  • BeanPostProcesser的before()方法回调
  • InitializingBean接口的初始化回调
  • 自定义初始化init的方法回调
  • BeanPostProcesser的after()方法回调

Spring框架详解_第14张图片

bean的实例化属性填充,就是在执行bean的配置时是否,会将注入的所有属性打包到一个对象中,然后在实例化属性填充时将BeanDifinition中的propertyValueList中的属性拿出,通过反射set进去就完成了。


Bean的实例属性填充

Spring框架详解_第15张图片

不同的类型数值类型,进行属性填充的方式是不同的,如果是注入普通属性,那就是像是String,int修饰的属性,就是直接通过set方法,反射设置;如果是注入单项对象引用,如上图所示,单项对象引用就是在userService对象中引入了userDao,在userDao中没有引入userService,这种引入的话就是,userService对象在创建之后,在执行依赖注入的时候从单例池中寻找userDao对象进行注入,这时候如果没有执行到userDao对象,就会进行暂停,就去创建userDao的bean对象。还有一种情况比较复杂,就是注入双向对象引用属性,这个里面涉及到了循环依赖(循环引用)问题。


循环依赖(循环引用)问题如何解决

Spring框架详解_第16张图片

Spring框架详解_第17张图片

注入双向对象引用属性,就是两个对象相互引用,在注入过程中,当某一个Bean执行过程中另一个Bean没有执行,创建了第一个bean的对象后(内存中存在,singletonObjects中没有),然后第一个Bean需要进行属性注入,发现第二个bean没有创建,然后暂停创建第二个bean,这时候第二个bean 同样执行创建对象,然后依赖注入,发现单例池中没有第一个bean,这时候就会暂停去创建第一个bean,这时候就造成循环引用问题,这时候想要解决就需要第二个bean注入第一个bean的时候不用去单例池中去查找,需要直接将第一个bean创建对象时的地址直接引用进来,然后继续走后面的流程,两者都会解决这个循环依赖问题。这个时候就需要使用三级缓存这个是Spring提供的专门解决循环依赖问题的。


三级缓存

Spring框架详解_第18张图片

在底层的存储结构中,其中有三级缓存的方式用来存储创建的bean对象,将完全创建的对象存储在一级缓存中也就是singletonObjects中,二级缓存用来存储半成品对象earlySingletonObjects,也就说这个对象并没有彻底创建完成,就是里面的部分依赖注入没有完成而去暂停去创建需要注入属性的对象的这部分对象,三级缓存singletonFactories用来缓存的也是半成品对象,一般存储的是未被引用的对象那个。

因此初始化阶段如果遇到循环依赖问题,Spring中会使用三级缓存解决,在三级缓存中,有个类singletonFactories用来存储创建的对象,但是存储的是半成品对象,且没有被引用,二级缓存(earlySingletonObjects)存储的是新创建的对象,但是已经被引用,一级缓存存储的是已经创建完成的对象。在解决循环依赖时,当第一个bean创建对象,存储在三级缓存中,然后第一个bean进行属性注入时,去三个缓存中搜索第二个bean,发现没有,所以需要去创建,创建了第二个bean对象,存储在三级缓存中,然后第二个bean去注入第一个bean,去三个缓存中寻找,在第三个缓存中找到,然后进行注入,将第一个bean从三级缓存放入二级缓存,然后继续第二个bean的生命周期,直到完全创建成功,创建完成的第二个bean放入一级缓存,然后删除二三缓存中的第二个bean,然后继续执行第一个bean,将第二个bean注入第一个bean中,然后执行剩余的生命周期,完成第一个bean的创建,将其存入一级缓存,然后删除二三缓存中的第一个bean。

Bean的完成阶段

将创建好的对象存放到一个名为singletonObjects(单例池)这个Map集合中,当然也是BeanFactory进行管理的,当调用getBean时就会从这个Map集合中去查找相应的bean信息

Spring的注解的使用与开发

使用@Component替换bean标签

在之前的Spirng启动过程中会去加载xml文件中的bean配置,现在会优先加载@Component注解标签注解的方法,凡是被@Component注解标识的类,会在指定范围内被Spring加载并实例化。当一个注解中的方法只有value一个时,这时候value可以省略


Spring框架详解_第19张图片

使用注解标签可以替换bean上面的配置,使得Spring加载更加的便洁,在使用上,之前配置xml文件,配置bean对象的话是需要在bean的配置上配置相应的功能,比如scope,在使用注解时直接使用@Scope注解标签向需要标注的方法上标注作用范围,在bean中的lazy-init在注解标签中使用@Lazy,bean中的init-method在注解中直接向需要加载的方法上标注@PostConstruct,bean中的destroy-method在注解标签中使用@PreDestroy直接在对应的方法上标记。


@Conmponent有三个衍生注解
Spring框架详解_第20张图片
Spring框架详解_第21张图片

在这里插入图片描述

在bean中使用依赖注入(属性注入)的时候,一般会有会有属性、方法等,在bean中可以通过constructor-arg设置对应的属性,通过property进行bean对象注入。使用注解标签,其中,@Value可以注解在属性上,为属性赋值,使用@Autowired可以注解在创建的对象上,有时候也会注解在方法上,表示向这个对象中注入此方法,@Qualifier这个注解是配合@Autowired使用的,使用@Qualifier可以表示注入哪个对象,根据标识的名称去查找注入的对象。@Resource是Javajdk里面自带的注解标签,与@Autowired的作用差不多,但是有返回值,可以在后面直接查找需要注入的对象的名称。


Spring配置类

Spring框架详解_第22张图片

配置类用来替代配置文件,使用@Configuration注解标签标识,在配置类中配置相应的配置,然后使用注解方式加载Spring的核心配置类,省去了写xml配置文件,相当于将需要的配置使用相应的注解全部配置在配置类中,然后启动时直接加载配置类就行。


Spring框架详解_第23张图片

AOP思想

Spring框架详解_第24张图片

Aspect Oriented Programming,AOP面向切面编程,面向对象OOP是对一个事物的抽象,一个对象包括静态的属性信息、动态的方法信息等。而AOP是横向的,是对不同事物的抽象,属性与属性,方法与方法,对象与对象都可以组成一个切面,这种思维去设计编程就是面向切面编程,要想实现这一思想,就需要使用到动态代理,动态代理就是无侵入式的给代码增加新的功能,通过接口保证后面的对象和代理实现同一个接口,接口就是被代理的所有方法,然后代理类可以对需要代理的对象增加新的功能,代理同名方法内的同时,可以执行原有逻辑同时嵌入其他逻辑或其他对象方法。


Spring框架详解_第25张图片

之前知道动态代理,就是将一个类的需要代理的方法通过创建一个接口,然后实现代理类的方式去创建代理对象,然后向代理对象中添加新的功能或者其他对象中的方法来实现动态代理的功能。但是面向切面中有以下几点概念,有:目标对象,代理对象,连接点,切入点,同时/增强功能,还有切面,其中目标对象就是需要进行增强,进行代理的对象,连接点就是其中的方法,切入点就是其中需要进行代理的方法,代理对象就是使用Proxy对象来进行代理,将需要代理的方法传入Proxy的参数中,通知/增强部分就是需要添加的方法或事件,切面部分是对于每一个被增强的方法而言的


Spring框架详解_第26张图片

aop配置中的几个配置方式以及其运用的时机


Spring框架详解_第27张图片

在Spring中在调用getProxy方法的时候,可以选用的AopProxy接口有两个实现类,一种是基于JDK的,另一种是基于Cglib的

首选的都是jdk基于接口的,就是目标类有接口,基于接口实现动态规划,生成实现类的对象,这种是目标类有接口的情况下,默认方式。

其次是Cglib动态代理,使用Cglib的情况就是当这个目标类没有接口的时候,这个时候系统自动创建一个类去继承这个目标类,然后在创建的类中去实现增强功能,这种方式是当目标类没有接口的情况下默认实现,目标类有接口的时候,想要使用需要手动配置

你可能感兴趣的:(常用框架,spring,java,后端)