Spring-基本知识
Spring框架的7个模块
- Spring Context:提供框架式的Bean访问方式,以及企业级功能(JNDI、定时任务等);
- Spring Core:核心类库,所有功能都依赖于该类库,提供IOC和DI服务;
- Spring AOP:AOP服务;
- Spring Web:提供了基本的面向Web的综合特性,提供对常见框架如Struts2的支持,Spring能够管理这些框架,将Spring的资源注入给框架,也能在这些框架的前后插入拦截器;
- Spring MVC:提供面向Web应用的Model-View-Controller,即MVC实现。
- Spring DAO:对JDBC的抽象封装,简化了数据访问异常的处理,并能统一管理JDBC事务;
- Spring ORM:对现有的ORM框架的支持
Spring的优点
- spring属于低侵入式设计,代码的污染极低
- spring的DI机制将对象之间的依赖关系交由框架处理,减低组件的耦合性
- Spring提供了AOP技术,支持将一些通用任务,如安全、事务、日志、权限等进行集中式管理,从而提供更好的复用
- spring对于主流的应用框架提供了集成支持
Spring的缺点
spring发展了太久以后,违背了原来的理念,配置变得非常繁琐,即"配置地狱"
Spring启动流程
- ⾸先会进⾏扫描,扫描得到所有的BeanDefinition对象,并存在⼀个Map中
- 然后筛选出⾮懒加载的单例BeanDefinition进⾏创建Bean,对于多例Bean不需要在启动过程中去 进⾏创建,对于多例Bean会在每次获取Bean时利⽤BeanDefinition去创建
- 利⽤BeanDefinition创建Bean就是Bean的创建⽣命周期,这期间包括了合并BeanDefinition、推 断构造⽅法、实例化、属性填充、初始化前、初始化、初始化后等步骤,其中AOP就是发⽣在初始 化后这⼀步骤中
- 单例Bean创建完了之后,Spring会发布⼀个容器启动事件
Javabean
* 概念:
* JavaBean是一种Java语言写成的可重用组件(类)
* JavaBean是指符合JavaBean规范的Java类
* 规范:
1. 类必须使用public修饰
2. 必须保证有公共无参数构造器(无参构造)
3. 包含属性的操作手段(getter,setter)
Spring-ioc
对IOC的理解
- IOC就是控制反转,指创建对象的控制权转移给Spring框架进行管理,并由Spring根据配置文件去创建实例和管理各个实例之间的依赖关系,对象与对象之间松散耦合,也利于功能的复用。DI依赖注入,和控制反转是同一个概念的不同角度的描述,即 应用程序在运行时依赖IoC容器来动态注入对象需要的外部依赖
- 最直观的表达就是,以前创建对象的主动权和时机都是由自己把控的,IOC让对象的创建不用去new了,可以由spring自动生产,使用java的反射机制,根据配置文件在运行时动态的去创建对象以及管理对象,并调用对象的方法的
- Spring的IOC有三种注入方式 :构造器注入、setter方法注入、根据注解注入
- IOC本质是一种设计思想,控制反转指获得依赖对象的方式反转了。控制反转是一种通过配置(xml配置/注解配置/自动装配)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IOC容器,其实现方法是依赖注入(DI)
- 控制反转是指将对象的创建权交给 Spring 去创建。使用 Spring 之前,对象的创建都是由我们自己在代码中new创建。而使用 Spring 之后。对象的创建都是给了 Spring 框架
依赖注入
* 概念:IOC的作用是减少程序间的耦合,所以依赖关系的管理都交给spring来管理。在当前类需要用到其他类的对象,由spring为我们提供,我们只需要在配置文件中说明。依赖关系的维护就称为依赖注入。
* 注入的数据类型
1. 基本类型和String
2. 其他bean类型(在配置文件中或注解配置过的bean)
3. 复杂类型/集合类型
* 用于给List结构集合注入的标签:list array set
* 用于给Map结构集合注入的标签:map props
* 结构相同,标签可以互换
* 注入的方式
1. 构造器注入(构造函数)
* 使用的标签:<constructor-arg>(在bean标签内使用)
* <constructor-arg>标签的属性
1. type:用于指定要注入的数据的数据类型,该数据类型也是构造函数中某个或某些参数的类型
2. index:用于指定要注入的数据给构造函数中指定索引位置的参数赋值,索引的位置从0开始
3. name:用于指定给构造函数中指定名称的参数赋值(常用)
4. value:用于提供基本类型和String类型的数据
5. ref:用于指定其他的bean类型数据,它指的就是在spring的Ioc核心容器中出现过的bean对象
* 优势:在获取bean对象时,注入数据是必须的操作,否则对象无法创建成功
* 弊端:改变了bean对象的实例化方式,使我们在创建对象时,即使用不到这些数据,也必须提供
2. set方式注入(重点)
* 依赖:bean对象的创建依赖于容器
* 注入:bean对象中的所有属性都由容器来注入
* 使用的标签:<property>(在bean标签内使用)
* <property>标签的属性
1. name:用于指定注入时所调用的set方法名称
2. value:用于提供基本类型和String类型的数据
3. ref:用于指定其他的bean类型数据,它指的就是在spring的Ioc核心容器中出现过的bean对象
* 优势:创建对象时没有明确的限制,可以直接使用默认构造函数
* 弊端:如果有某个属性必须有值,则获取对象时可能set方法没有执行
3. 拓展方式注入(注解)
* 可以使用p命名空间(property)和c命名空间(constructor-arg)进行注入。
* 使用前需要导入xml约束。
* xmlns:c="http://www.springframework.org/schema/c"
* xmlns:p="http://www.springframework.org/schema/p
Spring-aop
对AOP的理解
- AOP,一般称为面向切面,作为面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),减少系统中的重复代码,降低了模块间的耦合度,提高系统的可维护性。可用于权限认证、日志、事务处理
- AOP实现的关键在于 代理模式,AOP代理主要分为静态代理和动态代理。静态代理的代表为AspectJ;动态代理则以Spring AOP为代表
* AspectJ是静态代理,也称为编译时增强,AOP框架会在编译阶段生成AOP代理类,并将AspectJ(切面)织入到Java字节码中,运行的时候就是增强之后的AOP对象
* Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法 - Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理
* JDK动态代理只提供接口的代理,不支持类的代理,要求被代理类实现接口。JDK动态代理的核心是InvocationHandler接口和Proxy类,在获取代理对象时,使用Proxy类来动态创建目标类的代理类(即最终真正的代理类,这个类继承自Proxy并实现了我们定义的接口),当代理对象调用真实对象的方法时, InvocationHandler 通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起
* 如果被代理类没有实现接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP。CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的
* 静态代理与动态代理区别在于生成AOP代理对象的时机不同,相对来说AspectJ的静态代理方式具有更好的性能,但是AspectJ需要特定的编译器进行处理,而Spring AOP则无需特定的编译器处理
什么是AOP?
- 概念:AOP:Aspect Oriented Programming,面向切面编程。可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理和透明的持续性也是如此。这种散布在各处的无关的代码被称为横切(cross-cutting)代码,在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。而AOP技术则恰恰相反,它利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即切面。所谓“切面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。AOP代表的是一个横向的关系,如果说“对象”是一个空心的圆柱体,其中封装的是对象的属性和行为;那么面向方面编程的方法,就仿佛一把利刃,将这些空心圆柱体剖开,以获得其内部的消息。而剖开的切面,也就是所谓的“方面”了。然后它又以巧夺天功的妙手将这些剖开的切面复原,不留痕迹。使用“横切”技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。
AOP相关概念
1. 切面:Aspect,横切关注点的模块化(跨越应用程序多个模块的功能,比如日志功能),这个关注点实现可能另外横切多个对象
2. 连接点:Join point,连接点是在应用执行过程中能够插入切面的一个点。这个点可以是类的某个方法调用前、调用后、方法抛出异常后等。切面代码可以利用这些点插入到应用的正常流程之中,并添加行为
3. 通知:Advice,在特定的连接点,AOP框架执行的动作,Spring AOP 提供了5种类型的通知。
1. 前置通知(Before):在目标方法被调用之前调用通知功能
2. 后置通知(After):在目标方法完成之后调用通知,无论该方法是否发生异常
3. 后置返回通知(After-returning):在目标方法成功执行之后调用通知
4. 后置异常通知(After-throwing):在目标方法抛出异常后调用通知
5. 环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为
4. 切点:Pointcu通过切点定位到特定的连接点t,指定一个通知将被引发的一系列连接点的集合。AOP 。切点和连接点不是一对一的关系,一个切点匹配多个连接点,切点通过 org.springframework.aop.Pointcut 接口进行描述,它使用类和方法作为连接点的查询条件。每个类都拥有多个连接点,例如 ArithmethicCalculator类的所有方法实际上都是连接点
5. 引入:Introduction,添加方法或字段到被通知的类。 Spring允许引入新的接口到任何被通知的对象。例如,你可以使用一个引入使任何对象实现 IsModified接口,来简化缓存。Spring中要使用Introduction, 可有通过DelegatingIntroductionInterceptor来实现通知,通过DefaultIntroductionAdvisor来配置Advice和代理类要实现的接口
6. 目标对象:Target Object,包含连接点的对象。也被称作被通知或被代理对象
7. AOP代理:AOP Proxy,AOP框架创建的对象,包含通知。 在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理
8. 织入:Weaving,织入描述的是把切面应用到目标对象来创建新的代理对象的过程。 Spring AOP 的切面是在运行时被织入,原理是使用了动态代理技术。Spring支持两种方式生成代理对象:JDK动态代理和CGLib,默认的策略是如果目标类是接口,则使用JDK动态代理技术,否则使用Cglib来生成代理
四种常用的通知类型
1. 前置通知:在切入点方法(业务层方法)执行之前执行
2. 后置通知:在切入点方法正常执行之后执行
3. 异常通知:在切入点方法产生异常时执行
4. 最终通知:无论切入点方法是否正常执行,都会在最后执行
* <aop:pointcut>标签:用于配置切入点表达式
环绕通知
1. 问题:配置了环绕通知之后,切入点方法没有执行,而通知方法执行了
2. 原因:没有明确的切入点方法调用
3. 解决:使用Spring框架提供的ProceedingJoinPoint接口的方法proceed(),此方法相当于明确调用切入点方法
4. 作用:是spring框架提供的一种可以让我们手动控制增强方法何时执行的方式(该通知是什么类型取决于它出现的位置)
5. 注意:使用基于注解的AOP配置时推荐使用环绕通知
Spring-事务
Spring的事务机制
- Spring事务底层是基于数据库事务和AOP机制的
- 对于使⽤了@Transactional注解的Bean,Spring会创建⼀个代理对象作为Bean
- 当调⽤代理对象的⽅法时,会先判断该⽅法上是否加了@Transactional注解
- 如果加了,那么则利⽤事务管理器创建⼀个数据库连接,并且修改数据库连接的autocommit属性为false,禁⽌此连接的⾃动提交,这是实现Spring事务⾮常重 要的⼀步。然后执⾏当前⽅法,⽅法中会执⾏sql
- 执⾏完当前⽅法后,如果没有出现异常就直接提交事务;如果出现了异常,并且这个异常是需要回滚的就会回滚事务,否则仍然提交事务
Spring的事务什么时候失效(什么时候@Transactional失效)
因为Spring事务是基于代理来实现的,所以某个加了@Transactional的⽅法只有是被代理对象调⽤时,那 么这个注解才会⽣效,所以如果是被代理对象来调⽤这个⽅法,那么@Transactional是不会⽣效的。同时如果某个⽅法是private的,那么@Transactional也会失效,因为底层cglib是基于⽗⼦类来实现的, ⼦类是不能重载⽗类的private⽅法的,所以⽆法很好的利⽤代理,也会导致@Transactianal失效
Spring事务传播机制
概念:事务传播机制就是多个事务方法相互调用时,事务如何在这些方法间传播
举例说明:方法A是一个事务的方法,方法A执行过程中调用了方法B,那么方法B有无事务以及方法B对事务的要求不同都会对方法A的事务具体执行造成影响,同时方法A的事务对方法B的事务执行也有影响,这种影响具体是什么就由两个方法所定义的事务传播类型所决定。
spring中的7种事务传播机制:
- REQUIRED:支持当前事务,如果没有事务会创建一个新的事务
- SUPPORTS:支持当前事务,如果没有事务的话以非事务方式执行
- MANDATORY:支持当前事务,如果没有事务抛出异常
- REQUIRES_NEW:创建一个新的事务并挂起当前事务
- NOT_SUPPORTED:以非事务方式执行,如果当前存在事务则将当前事务挂起
- NEVER:以非事务方式进行,如果存在事务则抛出异常
- NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作
Spring事务什么时候会失效
spring事务实现的原理是AOP,事务失效的本质就是AOP失效,AOP失效的原因有以下这些:
- 发生自调用。类里使用this调用本类的方法。当this对象不是代理类,而是被代理对象本身时,就会发生自调用。解决方法是将this变为代理类。
- 方法不是public的。@Transactional只能用于public的方法,否则事务会失效。要用在非public的方法上,需要开启AspectJ代理模式
- 数据库不支持事务
- 没有被spring管理
- 异常没有正常抛出,导致事务不会回滚
Spring事务的种类,实现方式、原理及隔离级别
种类:
- Spring 支持编程式事务管理和声明式事务管理两种方式
- 编程式事务管理使用 TransactionTemplate
- 声明式事务管理建立在 AOP 之上的
- 声明式事务最大的优点就是不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明或通过@Transactional 注解的方式,便可以将事务规则应用到业务逻辑中
- 声明式事务管理要优于编程式事务管理,这正是 spring 倡导的非侵入式的开发方式,使业务代码不受污染,只要加上注解就可以获得完全的事务支持。唯一不足地方是,最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别
- 声明式事务本质是通过 AOP 功能,对方法前后进行拦截,将事务处理的功能编织到拦截的方法中,也就是在目标方法开始之前加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务
实现方式及原理:
Spring 事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring 是无法提供事务功能的。真正的数据库层的事务提交和回滚是通过binlog 或者 redo log 实现的。
隔离级别:
- ISOLATION_DEFAULT:这是个 PlatfromTransactionManager 默认的隔离级别,使用数据库默认的事务隔离级别
- ISOLATION_READ_UNCOMMITTED:读未提交,允许另外一个事务可以看到这个事务未提交的数据
- ISOLATION_READ_COMMITTED:读已提交,保证一个事务修改的数据提交后才能被另一事务读取,而且能看到该事务对已有记录的更新
- ISOLATION_REPEATABLE_READ:可重复读,保证一个事务修改的数据提交后才能被另一事务读取,但是不能看到该事务对已有记录的更新
- ISOLATION_SERIALIZABLE:一个事务在执行的过程中完全看不到其他事务对数据库所做的更新
Spring-bean
spring创建bean的三种方式
- 在spring的配置文件(bean.xml)中使用bean标签(),配置其id和class属性(用唯一标识名id来取全限定名class所反射出来的对象),在bean对象没有其他属性且默认构造函数存在时,可以用此方法,根据默认构造函数创建bean对象
<bean id="唯一标识" class="全限定类名" ></bean>
- 代码解释:读取全限定类名,反射创建一个对象,把该对象存入spring的核心容器,使用时,通过唯一标识取出该对象
- 使用普通工厂中的方法创建对象(或使用某个类中的方法创建对象,并存入spring容器)
- 使用工厂类中的静态方法创建对象(或使用某个类中的静态方法创建对象,并存入spring容器)
Spring中Bean是线程安全的吗
- Spring本身并没有针对Bean做线程安全的处理,是否是线程安全的取决于Bean对象本身
- 如果Bean是⽆状态的,那么Bean则是线程安全的
- 如果Bean是有状态的,那么Bean则不是线程安全的
bean的生命周期
* 单例对象
* 出生:当容器创建时对象出生
* 活着:只要容器还在,对象就一直活着
* 死亡:当容器销毁时对象死亡
* 总结:单例对象的生命周期和容器相同
* 多例对象
* 出生:当我们使用对象时spring框架就为我们创建
* 活着:对象只要是在使用过程中就一直活着
* 死亡:当对象长时间不用,且没有别的对象引用时,由Java的垃圾回收器回收
具体说明
1. 实例化:创建一个Bean对象
2. 填充属性:为属性赋值
3. 初始化
* 如果实现了xxxAware接口,通过不同类型的Aware接口拿到Spring容器的资源
* 如果实现了BeanPostProcessor接口,则会回调该接口的postProcessBeforeInitialzation和postProcessAfterInitialization方法
* 如果配置了init-method方法,则会执行init-method配置的方法
4. 销毁
* 容器关闭后,如果Bean实现了DisposableBean接口,则会回调该接口的destroy方法
* 如果配置了destroy-method方法,则会执行destroy-method配置的方法
bean的作用域
* bean标签的scope属性
1. 作用:指定bean的作用范围
2. 取值
1. singleton:单例的(默认值)
* `<bean id="asuka" class="example.Person" c:age="18" c:sex="female" scope="singleton"/> `
* 其中,scope="singleton"表示是单例模式
* 从容器中get时,是同一个对象(只创建了一个对象)
2. prototype:多例的
* `<bean id="asuka" class="example.Person" c:age="18" c:sex="female" scope="prototype"/> `
* 每次从容器中get时,都会产生一个新对象
3. request:作用于web应用的请求范围
4. session:作用于web应用的会话范围
5. global-session:作用于集群环境的会话范围(全局会话范围),当不是集群环境时,相当于session
什么是Bean的自动装配?有哪些方式?
- 概念:自动装配是Spring满足bean依赖的一种方式,Spring会在上下文中自动寻找,并自动给bean装配属性
- 开启:在xml配置文件的标签中的autowire属性配置开启自动装配
- 在Spring中三种装配的方式:
- 在xml中显式配置
- 在java中显式配置
- 隐式地自动装配(autowire属性)
- autowire属性的五种装配方式
- 缺省:通过ref属性手动装配
- byName:根据bean的属性名称自动装配
- byType:根据bean的类型自动装配
- constructor:如果一个bean与构造器参数的类型形同,则进行自动装配,否则导致异常
- autodetect:如果有默认的构造器,则通过constructor方式进行自动装配,否则使用byType方式进行自动装配
Spring-细节知识
Spring核心容器相关接口
* ApplicationContext
1. 它在构建核心容器时,创建对象采用的策略是立即加载的方式,即一读取完配置文件就创建配置文件中配置的对象
2. 适用于单例模式的对象
3. 实际开发中更常使用
* BeanFactory
1. 它在构建核心容器时,创建对象采用的策略是延迟加载的方式,即什么时候根据id获取对象了,什么时候才真正地创建对象(即使用时才创建)
2. 适用于多例模式的对象
ApplicationContext
* 概念:是spring继BeanFactory之外的另一个核心接口或容器,允许容器通过应用程序上下文环境创建、获取、管理bean。为应用程序提供配置的中央接口。在应用程序运行时这是只读的,但如果实现支持这一点,则可以重新加载
* 常用实现类
1. ClassPathXmlApplicationContext:加载类路径下的配置文件,要求配置文件必须在类路径下
2. FileSystemXmlApplicationContext:加载磁盘任意路径下的配置文件,要求必须有访问权限
3. AnnotationConfigApplicationContext:用于读取注解,创建容器
Spring中后置处理器的作用
Spring中的后置处理器分为BeanFactory后置处理器和Bean后置处理器,它们是Spring底层源码架构设计 中⾮常重要的⼀种机制,同时开发者也可以利⽤这两种后置处理器来进⾏扩展。BeanFactory后置处理器 表示针对BeanFactory的处理器,Spring启动过程中,会先创建出BeanFactory实例,然后利⽤ BeanFactory处理器来加⼯BeanFactory,⽐如Spring的扫描就是基于BeanFactory后置处理器来实现 的,⽽Bean后置处理器也类似,Spring在创建⼀个Bean的过程中,⾸先会实例化得到⼀个对象,然后再 利⽤Bean后置处理器来对该实例对象进⾏加⼯,⽐如我们常说的依赖注⼊就是基于⼀个Bean后置处理器 来实现的,通过该Bean后置处理器来给实例对象中加了@Autowired注解的属性⾃动赋值,还⽐如我们常 说的AOP,也是利⽤⼀个Bean后置处理器来实现的,基于原实例对象,判断是否需要进⾏AOP,如果需 要,那么就基于原实例对象进⾏动态代理,⽣成⼀个代理对象。
Spring中用到了哪些设计模式
BeanFactory和ApplicationContext的区别
相同点:BeanFactory和ApplicationContext是Spring的两大核心接口,都可以当做Spring的容器。
区别:
(1)BeanFactory是Spring里面最底层的接口,是IoC的核心,定义了IoC的基本功能,包含了各种Bean的定义、加载、实例化,依赖注入和生命周期管理。ApplicationContext接口作为BeanFactory的子类,除了提供BeanFactory所具有的功能外,还提供了更完整的框架功能:
继承MessageSource,因此支持国际化。
资源文件访问,如URL和文件(ResourceLoader)。
载入多个(有继承关系)上下文(即同时加载多个配置文件) ,使得每一个上下文都专注于一个特定的层次,比如应用的web层。
提供在监听器中注册bean的事件。
(2)
①BeanFactroy采用的是延迟加载形式来注入Bean的,只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化。这样,我们就不能提前发现一些存在的Spring的配置问题。如果Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次使用调用getBean方法才会抛出异常。
②ApplicationContext,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误,这样有利于检查所依赖属性是否注入。
③ApplicationContext启动后预载入所有的单实例Bean,所以在运行的时候速度比较快,因为它们已经创建好了。相对于BeanFactory,ApplicationContext 唯一的不足是占用内存空间,当应用程序配置Bean较多时,程序启动较慢。
(3)BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册。
(4)BeanFactory通常以编程的方式被创建,ApplicationContext还能以声明的方式创建,如使用ContextLoader。
循环依赖
详情:https://zhuanlan.zhihu.com/p/62382615
注解
* 用于创建对象的注解:作用和在xml配置文件中编写一个<bean>标签实现的功能是一样的
1. Component
* 作用:用于把当前类对象存入spring容器中(注册)
* 属性:
1. value:用于指定bean的id。不写时,默认值是当前类名,且首字母小写
* 由Component衍生出来的三个注解,其作用和属性与Component相同,只是是spring框架为我们提供的明确的三层所使用的注释(即在不同层注解的名字不同)
1. Controller:一般用在表现层
2. Service:一般用在业务层
3. Repository:一般用在持久层
* 用于注入数据的注解:作用和在xml配置文件中的<bean>标签中写一个<property>标签的功能是一样的
1. Autowired
* 作用:自动按照类型注入。只要容器中有唯一的一个bean对象类型和要注入的变量类型匹配,就可以注入成功。如果ioc容器中没有任何bean的类型和要注入的变量类型匹配,则报错。如果ioc容器中有多个bean类型和要注入的变量类型相匹配,则要使用Qualifier注解。
* 出现位置:可以是变量上,也可以是方法上
* 注意事项:在使用注解注入时,set方法就不是必须的了
2. Qualifier
* 作用:在按照类中注入的基础之上再按照名称注入。它在给类成员注入时不能单独使用,但是在给方法参数注入时可以
* 属性:
1. value:用于指定要注入的bean的id
3. Resource
* 作用:直接按照bean的id注入,可以独立使用
* 属性:
1. name:用于指定bean的id
* 注意事项:以上三个注解都只能注入其他bean类型的数据,基本类型和String类型无法使用上述注解实现。而集合类型的注入只能通过XML实现
4. Value
* 作用:用于注入基本类型和String类型的数据
* 属性:
1. value:用于指定数据的值。可以使用spring的el表达式(SpEL):${表达式}
* 用于改变作用范围的注解:作用和在<bean>标签使用scope属性实现的功能是一样的
1. Scope
* 作用:用于指定bean的作用范围
* 属性:
1. value:指定范围的取值(常用:singleton、prototype)
* 和生命周期相关的注解:作用和在<bean>标签中使用init-method和destroy-method的功能是一样的
1. PreDestroy
* 作用:用于指定销毁方法
2. PostConstruct
* 作用:用于指定初始化方法
使用@Autowired的原理是什么
- 答:在启动spring IoC时,容器自动装载了一个AutowiredAnnotationBeanPostProcessor后置处理器,当容器扫描到@Autowied、@Resource(是CommonAnnotationBeanPostProcessor后置处理器处理的)或@Inject时,就会在IoC容器自动查找需要的bean,并装配给该对象的属性
- 注意事项:
- 在使用@Autowired时,首先在容器中查询对应类型的bean
- 如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据
- 如果查询的结果不止一个,那么@Autowired会根据名称来查找(也可以使用@Qualifier)
- 如果查询的结果为空,那么会抛出异常。解决方法时,使用required=false
- 在使用@Autowired时,首先在容器中查询对应类型的bean