1 Spring 框架有哪些主要模块?
Spring核心容器:Spring bean的创建、配置和管理
AOP模块: 提供了面向切面的编程
数据访问与集成:提供了ORM框架,封装了JDBC大量重复的代码
web模块: MVC框架,使web层实现了松耦合
Instrumentation: 为JVM 添加了代理功能
2 什么是控制反转(IOC)?什么是依赖注入?
通过容器来管理对象之间的依赖, 把对象之间的耦合依赖,上升到容器来维护,控制权交给了容器,称为控制反转。
依赖注入是一种模式,来管理bean之间的依赖关系。有set方法、构造方法两种注入方式。@Autowired自动注入使用的是反射原理实现的。
3 BeanFactory 和 ApplicationContext 有什么区别?
BeanFactory 最基础的
ApplicationContext 基于BeanFactory实现,可以实现更多功能
两者区别:
ApplicationContext 初始化时会实例化所有bean, 只实例化一次,后面调用可以直接引用同一份;
BeanFactory 初始化时不会实例化bean, 只是在第一次使用bean时才会实例化;
ApplicationContext 启动时会慢些,但是使用的时候比BeanFactory快,不需要在实例化。
4 Spring 有几种配置方式?
xml配置: 使用applicationContext.xml来配置bean
java注解: 使用@compoment @Controller @Service 来声明bean, 通过@CompomentScan扫描到来实例化
javaConfig:使用@Configuration和@Bean 配置类来实例化
5 请解释 Spring Bean 的生命周期?
通过这张图能大致看懂spring的生命周期,详解:
instantiate bean对象实例化
populate properties 封装属性
如果Bean实现BeanNameAware执行setBeanName
如果Bean实现BeanFactoryAwar或ApplicationContextAwar设置工厂setBeanFactory或上下文对象setApplicationContext,
如果存在类实现BeanPostProcessor(处理Bean),执行postProcessBeforeInitialization
如果Bean实现InitializingBean执行afterPropertiesSet
调用自定义的init-method方法
如果存在类实现BeanPostProcessor(处理Bean),执行postProcessAfterInitialization
执行业务处理
如果Bean实现DisposableBean执行destroy
调用自定义的destroy-method
第一步就是对实例化bean,调用构造函数来创建实例,第二步是根据配置,进行相应属性的设置,依赖注入就是在这一步完成的。
第三步和第四步是让spring去了解咱们的spring容器,实现对应的Aware接口可以获取容器的一些资源,第五步和第八步可以针对指定的Bean进行功能增强,这时一般是采用的动态代理,(两种动态代理方式:jdk动态代理和cglib动态代理)。第六步和第十步是通过实现指定的接口来完成init(初始化)和destory(销毁)操作。
总结:
对于springbean的生命周期,我们需要关注的主要有两个方法:
1.增强bean的功能可以使用后处理Bean,BeanPostProcessor
2.如果需要初始化或销毁操作,我们可以使用init-method方法和destory-method这两个自定义的方法,一般不用自带的初始化和销毁方法。
6 Spring Bean 的作用域之间有什么区别?
有4种作用域:
single 单例作用域,默认作用域,使用单例设计模式,只为bean创建一次实例,之后注入获取的都是同一个bean实例
prototype 原型作用域,每次从容器或者上下文中获取的都是重新实例化的bean
session 会话作用域,每次会话都会重新实例化bean
request 请求作用域,每次请求都会重新实例化bean
7 Spring 框架中的单例 Beans 是线程安全的么?
spring并没有维护线程安全和并发处理, 需要开发者自己去维护。 一般的规避方式,service dao中不要带有状态的变量。
8 Spring 中如何解决线程安全问题
默认情况下,大多数成员变量都是无状态的,不存在线程安全, 但是对某些有状态的成员变量, Spring采用ThreadLocal进行处理,
为每个线程分配一个线程变量副本,解决线程安全问题
9 请举例说明如何在 Spring 中注入一个 Java Collection?
Spring提供了以下四种集合类的配置元素:
·< list > : 该标签用来装配可重复的list值。
< set > : 该标签用来装配没有重复的set值。
·< map >: 该标签可用来注入键和值可以为任何类型的键值对。
< props > : 该标签支持注入键和值都是字符串类型的键值对
10 如何向 Spring Bean 中注入一个 Java.util.Properties?
可以使用· < props > 标签为 Properties配置需要的key-value值,就可以实现属性注入
11 请解释 Spring Bean 的自动装配?
自动装配的步骤为:
1) 先为要声明的bean,添加@Compoment 注解, 也可以是@Controller @Service @repository
2) 配置@CompomentScan 扫描所有带@Compoment 注解的bean 为其实例化
12 请解释自动装配模式的区别?
Spring容器可以在不使用和元素的情况下自动装配相互协作的bean之间的关系,助于减少编写一个大的
基于Spring的应用程序的XML配置的数量使用元素的autowire属性为一个bean定义指定自动装配模式。
在Spring中,我们有4种方式可以装配Bean的属性。
1,byName
通过byName方式自动装配属性时,是在定义Bean的时候,在property标签中设置autowire属性为byName,那么Spring会自动寻找一个与该属性名称相同或id相同的Bean,注入进来。
2,byType
通过byType方式自动注入属性时,是在定义Bean的时候,在property标签中设置autowire属性为byType,那么Spring会自动寻找一个与该属性类型相同的Bean,注入进来。
3,constructor
通过构造器自动注入。在定义Bean时,在bean标签中,设置autowire属性为constructor,那么,Spring会寻找与该Bean的构造函数各个参数类型相匹配的Bean,通过构造函数注入进来。
4,autodetect
自动装配。如果想进行自动装配,但不知道使用哪种类型的自动装配,那么就可以使用autodetect,让容器自己决定。这是通过在定义Bean时,
设置bean标签的autowire属性为autodetect来实现的。设置为autodetect时,Spring容器会首先尝试构造器注入,然后尝试按类型注入。
默认情况下,Spring是不进行自动装配的。我们可以在xml中,设置beans标签的default-autowire属性为byName,byType等,来设置所有bean都进行自动装配
13 如何开启基于注解的自动装配?
要使用 @Autowired,需要注册 AutowiredAnnotationBeanPostProcessor,可以有以下两种方式来实现:
1)引入配置文件中的下引入 < context:annotation-config >
<beans>
<context:annotation-config />
</beans>
2)在bean配置文件中直接引入AutowiredAnnotationBeanPostProcessor
<beans>
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
</beans>
14 请举例解释@Required 注解?
@Required注解适用于bean属性setter方法,并表示受影响的bean属性必须在XML配置文件在配置时进行填充。否则,容器会抛出一个BeanInitializationException异常。
15 请举例解释@Autowired 注解?
使用byType 自动装配方式,找到类型一致的bean进行装配,如果类型相同的bean不存在或者有多个都会报错;
如果类型相同的bean有多个,@Autowired 可以和@Qualifier 一起使用,来实现byName 的目的
16 @Resource和@Autowired的区别?
相同点:
@Resource和@Autowired都是做bean的注入时使用,
区别点:
1)@Resource并不是Spring的注解,它的包是javax.annotation.Resource,需要导入,但是Spring支持该注解的注入;@Autowired 是spring 自带的自动装配的注解。
2)@Autowired 是使用byType的方式自动装配的, @Resource name type属性没有值的时候,使用byName去自动装配,name和type取值的不同,自动装配方式
也会不同:
①如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常。
②如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常。
③如果指定了type,则从上下文中找到类似匹配的唯一bean进行装配,找不到或是找到多个,都会抛出异常。
④如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配。
17 请举例说明@Qualifier 注解?
bean使用默认的beanId命名,@Qualifier 直接在bean注入的地方引入@Qualifier(“bean Id”)即可
如果自定义bean的id, @Qualifier 需要在bean声明的地方和bean注入的地方都引入。
18 构造方法注入和设值注入有什么区别?
设置注入使用 标签来实现
构造方法注入使用 标签来实现, 使用index 属性来区分构造函数参数的顺序
19 Spring 框架中都用到了哪些设计模式?
(1)工厂模式:BeanFactory就是简单工厂模式的体现,用来创建对象的实例;
(2)单例模式:Bean默认为单例模式。
(3)代理模式:Spring的AOP功能用到了JDK的动态代理和CGLIB字节码生成技术;
(4)模板方法:用来解决代码重复的问题。比如.JdbcTemplate。
(5)观察者模式:定义对象键一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知被制动更新,如Spring中listener的实现–ApplicationListener。
20 Spring事务的实现方式和实现原理
Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。真正的数据库层的事务提交和回滚是通过binlog或者redo log实现的。
(1)Spring事务的种类:
spring支持编程式事务管理和声明式事务管理两种方式:
①编程式事务管理使用TransactionTemplate。需要在代码中调用使用。
②声明式事务管理建立在AOP之上的。可以使用@Transaction 注解来实现
(2)spring的事务传播行为:
spring事务的传播行为说的是,当多个事务同时存在的时候,spring如何处理这些事务的行为。
① PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置。
② PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。‘
③ PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。
④ PROPAGATION_REQUIRES_NEW:创建新事务,无论当前存不存在事务,都创建新事务。
⑤ PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
⑥ PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
⑦ PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按REQUIRED属性执行。
(3)Spring中的隔离级别:
① ISOLATION_DEFAULT:这是个 PlatfromTransactionManager 默认的隔离级别,使用数据库默认的事务隔离级别。
② ISOLATION_READ_UNCOMMITTED:读未提交,允许另外一个事务可以看到这个事务未提交的数据。
③ ISOLATION_READ_COMMITTED:读已提交,保证一个事务修改的数据提交后才能被另一事务读取,而且能看到该事务对已有记录的更新。
④ ISOLATION_REPEATABLE_READ:可重复读,保证一个事务修改的数据提交后才能被另一事务读取,但是不能看到该事务对已有记录的更新。
⑤ ISOLATION_SERIALIZABLE:一个事务在执行的过程中完全看不到其他事务对数据库所做的更新。
21 Spring 框架中有哪些不同类型的事件?
https://www.cnblogs.com/xinde123/p/8918714.html
ApplicationEvent事件类分成2类:
(1)ApplicationContextEvent:容器事件,也就是说事件源是ApplicationContext,框架提供了四个子类,分别代表容器启动,刷新,停止和关闭事件。
(2)RequestHandleEvent: 这是一个与Web应用相关的事件,当一个请求被处理后,才会产生该事件。
细分为5种标准的事件:
(1)上下文更新事件(ContextRefreshedEvent):在调用ConfigurableApplicationContext 接口中的refresh()方法时被触发。
(2)上下文开始事件(ContextStartedEvent):当容器调用ConfigurableApplicationContext的Start()方法开始/重新开始容器时触发该事件。
(3)上下文停止事件(ContextStoppedEvent):当容器调用ConfigurableApplicationContext的Stop()方法停止容器时触发该事件。
(4)上下文关闭事件(ContextClosedEvent):当ApplicationContext被关闭时触发该事件。容器被关闭时,其管理的所有单例Bean都被销毁。
(5)请求处理事件(RequestHandledEvent):在Web应用中,当一个http请求(request)结束触发该事件。
如果一个bean实现了ApplicationListener接口,当一个ApplicationEvent 被发布以后,bean会自动被通知。
22 ApplicationEvent来自定义事件步骤
1) 自定义事件类需要实现ApplicationEvent
2) 增加自定义事件的监听器类,实现ApplicationListener接口
3)使用事件发布类或者ApplicationContext 发布自定义事件, 这样监听器就能监听到执行对应业务
23 ApplicationEvent的应用场景
类似于消息队列, 一般用于核心业务和非核心业务解耦,例如: 支付后生成物流信息
24 FileSystemResource 和 ClassPathResource 有何区别?
1)ClassPathResource 从系统的类路径中加载
2)FileSystemResource 从文件系统加载,比如说自己指定配置文件的全路径
25 aop的静态代理和动态代理的理解?两种动态代理方式:jdk动态代理和cglib动态代理的理解和区分?
静态代理:程序运行前就已经生成了代理类
动态代理:程序运行期间通过JVM反射等机制动态生成,代理类和委托类的关系是运行时才确定的
两种动态代理的区别:
jdk动态代理 : 目标类必须实现接口,在生成 jdk代理类时也会动态的实现接口,并对目标类的方法进行代理
cglib动态代理: 目标类没有实现接口,cglib代理类是基于继承目标类来实现的,对目标类的方法进行代理
spring aop的代理使用的就是动态代理,在方法执行的前后、抛出异常时生成动态代理类。
参考:https://blog.csdn.net/yinni11/article/details/80217241
26 spring aop动态代理的原理?
1)创建容器对象的时候,根据切入点表达式拦截的类,生成代理对象。
2)如果目标对象有实现接口,使用jdk代理。如果目标对象没有实现接口,则使用cglib代理。然后从容器获取代理后的对象,在运行期植入"切面"类的方法。
通过查看spring源码,我们在DefaultAopProxyFactory类中,找到这样一段话。
27 aop和aspectj的区别?
AOP主要的的实现技术主要有Spring AOP和AspectJ。
1)AspectJ的底层技术。
AspectJ的底层技术是静态代理,即用一种AspectJ支持的特定语言编写切面,通过一个命令来编译,生成一个新的代理类,该代理类增强了业务类,这是在编译时增强,相对于下面说的运行时增强,编译时增强的性能更好。
2)Spring AOP
Spring AOP采用的是动态代理,在运行期间对业务方法进行增强,所以不会生成新类,对于动态代理技术,Spring AOP提供了对JDK动态代理的支持以及CGLib的支持。
JDK动态代理只能为接口创建动态代理实例,而不能对类创建动态代理。需要获得被目标类的接口信息(应用Java的反射技术),生成一个实现了代理接口的动态代理类(字节码),再通过反射机制获得动态代理类的构造函数,利用构造函数生成动态代理类的实例对象,在调用具体方法前调用invokeHandler方法来处理。
CGLib动态代理需要依赖asm包,把被代理对象类的class文件加载进来,修改其字节码生成子类