一、spring 是什么?
spring 是轻量级的IOC和AOP框架,主要由以下几个模块组成:
(1)Test:支持使用JUnit或TestNG对Spring组件进行单元测试和集成测试。
(2)spring core :核心模块,提供IOC基本功能,包含以下几个子模块:
- core:包含了spring核心的工具类(比如注解相关的工具类AnnotationUtils, 容器操作相关的工具类 CollectionUtils 等等),包括了IOC/DI功能,是其他组件的基础。
- Beans: 提供了BeanFactory。
- Context: 上下文模块,建立在核心和中心 Beans 模块的基础之上,是访问定义和配置任何对象的媒介。以一种类似于 JNDI 注册的方式访问对象。添加了国际化(比如,使用资源束)、事件传播、资源加载等功能。核心类为ApplicationContext。
- SpEL:提供了强大的语言表达式,用于在运行时查询和操作对象图。
(3)spring aop:提供aop功能支持,这个也是spring 框架比较重要的功能。
(4)Aspects: 提供了和AspectJ的集成。
(5)Messaging: 集成messagingapi和消息协议提供支持。
(6)Data Access/Integration:数据访问和集成模块,开发过程中经常用到的功能。
- JDBC:模块提供了 JDBC 抽象层,它消除了冗长的 JDBC 编码(封装了大量的样板代码)和对数据库提供应商特定错误代码(不同数据代码可能不同)的解析对外暴露统一的异常。
- ORM:Object Relational Mapping,提供了对流行的对象关系映射 API (包括JPA,Hibernate、mybatis)的集成层。
- OXM: 提供了一个抽象层,该抽象层支持Object/XML映射实现。
- JMS:模块包含生产(produce)和消费(consume)消息的功能。
- Transcations:事务模块,支持对实现特殊接口的类以及所有POJO(普通Java对象)进行编程和声明式事务管理。
(7)spring web: 提供了面向web的综合特性。
二、 简单介绍一下spring IOC/DI原理
IOC和DI(依赖注入)本质上是一个意思,IOC(Inversion of control)就是控制反转,这是一种设计思想,解决了java开发领域对象的创建和管理的问题,传统的开发方式A依赖B,在A类中需要主动创建B类,在IOC的开发模式中,不需要手动去创建,IOC容器会帮我们创建好对象,我们在需要的时候只要去IOC容器中去取就好了,不用再考虑对象的创建和属性的组装问题。IOC是spring基础功能也是最核心的功能之一。
spring IOC 解决的主要问题: 对象之间的耦合问题。
对于IOC掌握两个关键点:
- 控制:控制的啥?对象的创建和管理权限。
- 反转:怎么个反转?对象的创建和管理的权利交给spring IOC容器管理。
spring底层是如何解决IOC这个问题:
- spring 容器启动的时候通过扫描配置文件或者注解扫描的方式加载到所有Bean的定义(BeanDefition放到容器中的Map数据结构中)。
- 对于单例的非Lizy bean(我们用的大多数bean都是单例bean),容器直接初始化 ,并放到单例池中。
- 通过构造器注入或者注解的方式声明一个bean中依赖的其他bean 解决IOC问题(具体的解决思路就是通过bean的后处理器来实现的)。
三、简单介绍一下spring AOP
AOP:面向切面编程(Aspect-Oriented Programming),是OOP(特点:封装、集成、多态)延续和补充,AOP要达到的目标是在不改变原有业务逻辑的情况下,把横切逻辑应用到原有的业务逻辑中,达到和原来一样的效果,spring apo 是spring 重要的功能。
AOP解决了什么问题: 主要是解决系统层面的一些问题。
AOP的使用场景:权限、日志、缓存、事务等等
AOP可以增强的点: 字段的访问、方法的访问,在sping的实现中仅仅是限制在了对方法的访问上。
AOP相关的一些概念:
- JointPoint:连接点,程序执行的过程中明确的点,一般是方法的调用。
- Advice :通知,AOP在特定的切入点上执行增强处理,常用的有before(前置通知)、After(后置通知),AfterReturning(最终通知),AfterThrowing(异常通知),around(环绕通知)。
- Pointcut:切入点:就是带有通知的连接点,Pointcut=jointpoint+advice
- Aspect:切面,通常是一个类,里面可以定义切入点和通知。
- weave:织入,将切面应用到目标对象并导致代理对象生成的过程。
- introduction:引入,在不改代码的前提下,引入可以在运行期可以为类动态地添加一些方法或者字段
如果理解切面:
- 切:指的是横切逻辑,原有业务逻辑不能动,只能操作横切逻辑代码,所以面向横切逻辑。
- 面:横切逻辑代码往往影响的是多个方法,每个方法是一个点,由点组成面。
Spring AOP底层的实现方法:
- jdk动态代理
- cjlib 动态代理
spring bean aop增强处理的时机: BeanPostProcessor的 postProcessAfterInitialization方法。
四、 spring bean依赖的注入方式
- Field的依赖注入: 一般在字段上@Autowired 或者 @Resource。
- set 方法注入,一个在方法上加上@Autowired。
- 构造器的注入。
五、 @Autowired 和@Resource的区别
1.Autowired是spring 提供的注解,只能用在spring的框架中,Resource是JSR-250提供的,是java标准,可以用在其他的框架中。
2.Autowired默认是按照类型装配,如果需要按照byName装配,需要配合@Qualifier注解配合。Resource默认是按照name自动装配,指定了name则按照name自动装配,指定了type则按照type自动装配。
3.Autowired有required属性,默认是true,可以设置为false这样的话如果没有对应的bean也不会报错。Resource注解标注的如果找不到则报错
4.应用的地方不同:
- Autowired 可以用在构造器、方法、参数、字段、注解上。
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
boolean required() default true;
}
- Resoure 可以用在类(实测放在类上没啥卵用)、成员变量和方法上。
@Target({TYPE, FIELD, METHOD})
@Retention(RUNTIME)
public @interface Resource {
String name() default "";
String lookup() default "";
Class<?> type() default java.lang.Object.class;
enum AuthenticationType {
CONTAINER,
APPLICATION
}
AuthenticationType authenticationType() default AuthenticationType.CONTAINER;
boolean shareable() default true;
String mappedName() default "";
String description() default "";
}
六、 spring bean的生命周期(简单来说)
- 实例化bean
- 设置对象属性(依赖注入)
- 处理aware接口
- 执行初始化方法
- 使用bean
- 销毁bean
七、 spring支持的几种bean的作用域
- singleton : 单例,我们最常用的方式。
- prototype:原型,每次请求创建一个新的bean。
- request: 为每次网络请求创建一个实例,在请求完成之后bean失效,被垃圾回收。
- session :与request 类似,确保每个session中有一个bean的实例,session过期之后bean失效。
- global-session:全局作用域,global-session和Portlet应用相关(这个实际工作中没有用到过)。
八、 spring中的单例bean是否是线程安全的
spring 框架本身并没有对单例的bean进行任何多线程的封装处理。关于单例bean的线程安全和并发问题,需要开发者自行去搞定,实际上大部分的spring bean并没有可变的状态(比如dao类和service类),所以在某种程度上来说spring的单例bean是线程安全的,如果你定义的bean有多种状态的话就需要自行保证线程安全,最简单的办法就是将bean的作用域由singleton 变更为prototype。
九、 spring如何处理线程并发问题
通常情况下定义的bean是无状态的。是可以在多线程的情况下共享的,所以大多数bean都是singleton的。
对于prototype 每次获取bean都重新创建一个,一定程度上避免了并发问题,但是使用的场景是否安全很大程度上还是取决于你咋用。
对于request和session等作用域范围的,对象创建之后存在于session或者request的atribute中,针对的作用域是request或者session,很大程度上也能可以避免并发问题,但和prototype一样也取决于开发者。
spring 也提供了ThreadScope范围的bean作用域,这个实现是基于ThreadLocal, ThreadLocal为每一个线程对象提供变量副本,从而实现线程级别的隔离。
spring 官方提供的一些bean,一般也是通过ThreadLocal来解决线程安全问题的,比如RequestContextHolder等。
十、spring框架的自动装配方式
- no: 需要手工,需要手工指定bean属性来装配bean。
- by_name: 通过bean的名称自动装配。
- by_type:通过类型自动装配。
- constructor: 通过构造器自动注入。
- autodetect:自动探测,如果有构造方法,通过构造方法注入,否则使用by_type的方式自动装配。
public interface AutowireCapableBeanFactory extends BeanFactory {
/**
* Constant that indicates no externally defined autowiring. Note that
* BeanFactoryAware etc and annotation-driven injection will still be applied.
* @see #createBean
* @see #autowire
* @see #autowireBeanProperties
*/
int AUTOWIRE_NO = 0;
/**
* Constant that indicates autowiring bean properties by name
* (applying to all bean property setters).
* @see #createBean
* @see #autowire
* @see #autowireBeanProperties
*/
int AUTOWIRE_BY_NAME = 1;
/**
* Constant that indicates autowiring bean properties by type
* (applying to all bean property setters).
* @see #createBean
* @see #autowire
* @see #autowireBeanProperties
*/
int AUTOWIRE_BY_TYPE = 2;
/**
* Constant that indicates autowiring the greediest constructor that
* can be satisfied (involves resolving the appropriate constructor).
* @see #createBean
* @see #autowire
*/
int AUTOWIRE_CONSTRUCTOR = 3;
/**
* Constant that indicates determining an appropriate autowire strategy
* through introspection of the bean class.
* @see #createBean
* @see #autowire
* @deprecated as of Spring 3.0: If you are using mixed autowiring strategies,
* prefer annotation-based autowiring for clearer demarcation of autowiring needs.
*/
@Deprecated
int AUTOWIRE_AUTODETECT = 4;