spring是什么?
spring是一个轻量级的ioc和aop容器框架
常见的配置方式:基于XML配置,基于注解的配置,基于java的配置
spring的优点?
1)spring属于低侵入式设计,对代码的污染极低
2)spring的DI机制将对象之间的依赖关系交由框架处理,降低组件的耦合性
3)spring提供了AOP技术,支持将一些通用任务集中管理,从而得到更好的复用
4)spring对主流的应用框架提供了集成支持
对spring AOP的理解?
AOP一般称为面向切面,是面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块。能够减少系统中的重复代码,降低模块间的耦合度,同时提高了系统的可维护性
AOP实现的关键在于代理模式,AOP代理主要分为静态代理和动态代理。 静态代理的代表为:AspectJ 动态代理则以Spring Aop为代表
1)AspectJ是静态代理的增强(静态代理是Aop框架会在编译阶段生成AOP代理类,因此也成为编译时增强),他会在编译阶段将切面织入java字节码中,运行的时候就是增强之后的AOP对象
2)Spring AOP使用的动态代理(动态代理就是说AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法)
Spring AOP中的动态代理分为jdk动态代理和CGLIB动态代理
jdk动态代理:只提供接口的代理,不支持类的代理,核心是InvocationHandler接口和Proxy类,InvocationHandler通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编制在一起,接着,Proxy利用InvocationHandler动态创建一个符合某一接口的示例,生成目标类的代理对象
CGLIB动态代理:如果代理类没有实现InvocationHandler接口,那么Spring AOP会选择CGLIB来动态代理目标类。CGLIB是一个代码生成的类库,可以在运行时动态的生成类的一个子类对象,并且覆盖其中特定方法并添加增强代码,从而实现AOP,CGLIB通过继承的方式做动态代理,如果某个类被标记为final,那么无法使用CGLIB做动态代理
静态代理和动态代理的区别:生成Aop代理对象的时机不同,相对来说AspectJ的静态代理方式性能更好,但是AspectJ需要特定的编译器进行处理,而Spring Aop不需要特定的编译器
哪些类不能被动态代理?
1.final类
2.只有有参构造器的类,因为通过继承方式的动态代理必须要显示地指定无参构造器
Spring IOc的理解?
1. IOC就是控制反转,是指创建对象的控制权的转移,以前创建对象的主动权和时机是由自己把控的,而现在把这种权利转移到Spring容器中,并由容器根据配置文件去创建实例和管理各个实例之间的依赖关系,对象与对象之间松散耦合,有利于复用。DI依赖注入和控制反转是同一个概念的不同角度的描述
2. 最直观的表达就是,IOC让对象的创建不用去new,可以由spring自动产生,使用java的反射机制,根据配置文件在运行时动态的去创建对象以及管理对象,并调用对象的方法的
3. Spring IOC的三种注入方式:构造器注入,setter注入,注解注入
4.IOC负责创建对象,管理对象,装配对象,配置对象,并且管理对象的整个生命周期
作用:管理对象的创建和依赖关系的维护,由容器去维护具体对象,实现解耦,托管了类是产生过程
好处:ioc把应用的代码量降到最低,使程序易于测试,用最小的代价和最小的侵入性使松散耦合得意实现,支持加载服务时的饿汉式初始化和懒加载
工作过程:
1:初始化ioc容器
2:读取配置文件
3:将配置文件转换为容器识别的数据结构
4:利用数据结构一次实例化相应的对象
5:注入对象的依赖关系
spring加载bean的过程?
1.获取配置文件资源:通过ResourceLoader来完成资源文件位置的定位
2.对bean定义信息进行解析:通过BeanDefinitionReader来完成bean定义信息的解析
3.加载提取bean并注册:ioc容器解析得到BeanDefinition后,会把它在ioc容器中注册
4.通过DefaultListableBeanFactory方法来完成初始化
实现机制:工厂模式+反射+xml文件
BeanFactory和ApplicationContext有什么区别?
BeanFactory和ApplicationContext是Spring的两大核心接口,都可以当做Spring的容器。其中ApplicationContext是BeanFactory的子接口。
(1)BeanFactory:是Spring里面最底层的接口,包含了各种Bean的定义,读取bean配置文档,管理bean的加载、实例化,控制bean的生命周期,维护bean之间的依赖关系。ApplicationContext接口作为BeanFactory的派生,除了提供BeanFactory所具有的功能外,还提供了更完整的框架功能:
①继承MessageSource,因此支持国际化。
②统一的资源文件访问方式。
③提供在监听器中注册bean的事件。
④同时加载多个配置文件。
⑤载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层。
(2)①BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化。这样,我们就不能发现一些存在的Spring的配置问题。如果Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次使用调用getBean方法才会抛出异常。
②ApplicationContext,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误,这样有利于检查所依赖属性是否注入。 ApplicationContext启动后预载入所有的单实例Bean,通过预载入单实例bean ,确保当你需要的时候,你就不用等待,因为它们已经创建好了。
③相对于基本的BeanFactory,ApplicationContext 唯一的不足是占用内存空间。当应用程序配置Bean较多时,程序启动较慢。
(3)BeanFactory通常以编程的方式被创建,ApplicationContext还能以声明的方式创建,如使用ContextLoader。
(4)BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册。
请解释Spring Bean的生命周期?
首先说一下Servlet的生命周期:实例化,初始init,接收请求service,销毁destroy;
Spring上下文中的Bean生命周期也类似,如下:
(1)实例化Bean:
对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化。对于ApplicationContext容器,当容器启动结束后,通过获取BeanDefinition对象中的信息,实例化所有的bean。
(2)设置对象属性(依赖注入):
实例化后的对象被封装在BeanWrapper对象中,紧接着,Spring根据BeanDefinition中的信息 以及 通过BeanWrapper提供的设置属性的接口完成依赖注入。
(3)处理Aware接口:
接着,Spring会检测该对象是否实现了xxxAware接口,并将相关的xxxAware实例注入给Bean:
①如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String beanId)方法,此处传递的就是Spring配置文件中Bean的id值;
②如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory()方法,传递的是Spring工厂自身。
③如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文;
(4)BeanPostProcessor:
如果想对Bean进行一些自定义的处理,那么可以让Bean实现了BeanPostProcessor接口,那将会调用postProcessBeforeInitialization(Object obj, String s)方法。
(5)InitializingBean 与 init-method:
如果Bean在Spring配置文件中配置了 init-method 属性,则会自动调用其配置的初始化方法。
(6)如果这个Bean实现了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法;由于这个方法是在Bean初始化结束时调用的,所以可以被应用于内存或缓存技术;
以上几个步骤完成后,Bean就已经被正确创建了,之后就可以使用这个Bean了。
(7)DisposableBean:
当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用其实现的destroy()方法;
(8)destroy-method:
最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。
解释Spring支持的几种bean的作用域。
Spring容器中的bean可以分为5个范围:
(1)singleton:默认,每个容器中只有一个bean的实例,单例的模式由BeanFactory自身来维护。
(2)prototype:为每一个bean请求提供一个实例。
(3)request:为每一个网络请求创建一个实例,在请求完成以后,bean会失效并被垃圾回收器回收。
(4)session:与request范围类似,确保每个session中有一个bean的实例,在session过期后,bean会随之失效。
(5)global-session:全局作用域,global-session和Portlet应用相关。当你的应用部署在Portlet容器中工作时,它包含很多portlet。如果你想要声明让所有的portlet共用全局的存储变量的话,那么这全局变量需要存储在global-session中。全局作用域与Servlet中的session作用域效果相同。
Spring框架中的单例Beans是线程安全的么?
Spring框架并没有对单例bean进行任何多线程的封装处理。关于单例bean的线程安全和并发问题需要开发者自行去搞定。但实际上,大部分的Spring bean并没有可变的状态(比如Serview类和DAO类),所以在某种程度上说Spring的单例bean是线程安全的。如果你的bean有多种状态的话(比如 View Model 对象),就需要自行保证线程安全。最浅显的解决办法就是将多态bean的作用域由“singleton”变更为“prototype”。
Spring如何处理线程并发问题?
在一般情况下,只有无状态的Bean才可以在多线程环境下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域,因为Spring对一些Bean中非线程安全状态采用ThreadLocal进行处理,解决线程安全问题。
ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。同步机制采用了“时间换空间”的方式,仅提供一份变量,不同的线程在访问前需要获取锁,没获得锁的线程则需要排队。而ThreadLocal采用了“空间换时间”的方式。
ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。
Spring Bean的三种注入方式?
1.基于xml注入:提供了setter注入和构造器注入。其中setter注入要求bean必须提供无参构造方法,还有提供注入对应属性的setter方法。而构造器注入需要使用元素的子元素来定义构造方法的参数
2.基于java配置类的注入:该方式解决了xml配置的臃肿问题,通过@Configuration和@Bean注解
3.基于注解的注入
Spring的自动装配:
在spring中,对象无需自己查找或创建与其关联的其他对象,由容器负责把需要相互协作的对象引用赋予各个对象,使用autowire来配置自动装载模式。
在Spring框架xml配置中共有5种自动装配:
(1)no:默认的方式是不进行自动装配的,通过手工设置ref属性来进行装配bean。
(2)byName:通过bean的名称进行自动装配,如果一个bean的 property 与另一bean 的name 相同,就进行自动装配。
(3)byType:通过参数的数据类型进行自动装配。
(4)constructor:利用构造函数进行装配,并且构造函数的参数通过byType进行装配。
(5)autodetect:自动探测,如果有构造方法,通过 construct的方式自动装配,否则使用 byType的方式自动装配。
基于注解的方式:
使用@Autowired注解来自动装配指定的bean。在使用@Autowired注解之前需要在Spring配置文件进行配置,<context:annotation-config />。在启动spring IoC时,容器自动装载了一个AutowiredAnnotationBeanPostProcessor后置处理器,当容器扫描到@Autowied、@Resource或@Inject时,就会在IoC容器自动查找需要的bean,并装配给该对象的属性。在使用@Autowired时,首先在容器中查询对应类型的bean:
如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据;
如果查询的结果不止一个,那么@Autowired会根据名称来查找;
如果上述查找的结果为空,那么会抛出异常。解决方法时,使用required=false
Spring 框架中都用到了哪些设计模式?
(1)工厂模式:BeanFactory就是简单工厂模式的体现,用来创建对象的实例;
(2)单例模式:Bean默认为单例模式。
(3)代理模式:Spring的AOP功能用到了JDK的动态代理和CGLIB字节码生成技术;
(4)模板方法:用来解决代码重复的问题。比如. RestTemplate, JmsTemplate, JpaTemplate。
(5)观察者模式:定义对象键一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知被制动更新,如Spring中listener的实现--ApplicationListener。
Spring事务的实现方式和实现原理:
Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。真正的数据库层的事务提交和回滚是通过binlog或者redo log实现的。
(1)Spring事务的种类:
spring支持编程式事务管理和声明式事务管理两种方式:
①编程式事务管理使用TransactionTemplate。
②声明式事务管理建立在AOP之上的。其本质是通过AOP功能,对方法前后进行拦截,将事务处理的功能编织到拦截的方法中,也就是在目标方法开始之前加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务
@Transactional?
基于spring AOP的事务管理即声明式事务管理,默认针对RuntimeException回滚主要有三种回滚方式:
1.利用硬编码的方式,借助spring api对事务进行显示的回滚
2.在spring配置文件中对rollback-for属性赋值
3.针对业务代码进行封装,二次抛出RuntimeException类型的异常
@Component,@Controller,@Repository,@Service的区别?
@Component:将java类标记为bean,它是任何spring管理组件的通用构件型
@Controller:标记一个类成为控制器
@Service:是组件注解的特化,可以在服务层使用@Service
@Repository:它为DAO提供了额外的好处,将DAO倒入ioc容器
@Autowired有什么作用?
可以更准确地控制应该在何处以及如何进行自动装配
@RequestMapping注解?
用于将特定的http请求方法映射到将处理相应请求的控制器中的特定类/方法
SPringMVC的工作流程?
1.想服务器发送http请求,请求被控制器DispatcherServlet捕获
2.DispatchServlet根据server.xml中的配置对请求的url进行解析,等到uri,跟后根据uri调用handleMapping获得该handler配置的所有相关的对象
3.dispatchServlet根据获得的handler选择合适的handlerAdapter
4.提取request中的模型数据,填充handler,开始执行handler
5.处理请求后返回ModelAndView对象,dispatchServlet通过ViewResolver将逻辑视图转换为真正的视图
6.dispatchServlet通过model解析出ModelAndView()中的参数进行解析最终展现出完整的view给客户端
注解的原理?
它本质上是继承了一个Annotation接口,具体实现类是java运行时生成的动态代理类。我们通过反射获取注解时,返回的是java
运行时生成的动态代理对象。通过代理对象调用自定义注解的方法,会最终调用annotationInvocationHandler的invoke方法得到对应的值
ioc的好处?
对象的构建假如果依赖非常多的对象,并且层次很深的话,外层在构造对象时会很麻烦,而ioc帮我们管理对象的创建,只需要在配置文件里指定如何构建就行,最外层的对象不需要关心深层次对象是如何创建的。也就是假如我们修改深层次的对象的话,那么上层的所有类几乎都要去进行修改,这样的维护成本太高,而假如用ioc,我们只需要修改你要修改的那个类就行了,不用去修改其他上层楼,并且我们在创建实例时不需要了解他的细节。
为什么要有jdk动态代理和CGLIB动态代理?
jdk动态代理(默认代理):由于子类要继承Proxy类,而java是单继承的,所以不能再继承了,这个时候就使用了接口,那么为什么要继承proxy类呢?因为proxy内部维护了一个invocationHandler对象进行invoke aop操作
CGLIB动态代理:它是通过直接修改字节码进行增强子类,所以被代理的类不能是final的,那么为什么不继承Proxy呢?目的是调用父类的构造函数并使用子类传递给父类的invocationHandler来调用invoke
总结:jdk代理只能基于接口代理(因为他已经继承了Proxy),CGLIB无论有没有实现接口都可以代理,因为它是通过继承的方式进行代理的,并没有去继承Proxy类,但是却无法继承final类
spring的事务传播机制?
1.propagation_required:假如当前正要执行的事务不在另外一个事务里,那么就另起一个新的事务
2.propagation_supports:如果当前在事务中,就以事务形式运行,不在一个事务中,就以非事务的形式运行
3.propagation_mandatory:必须在一个事务中运行,只能被一个父事务调用,否则抛出异常
4.propagation_requires_new:新建事务完成以后,上下文事务在恢复运行
5.propagation_not_supported:当前不支持事务
6.propagation_never;不能再事务中运行
7.propagation_nested:该事务和它的父事务是相互依赖的,要和父事务一起提交,一起回滚
Servlet的生命周期,执行过程?
生命周期:加载对应的Servlet类,实例化Servlet(构造函数运行),调用init方法,调用service方法,执行destroy方法
执行过程:浏览器向服务器发出一个url请求,根据url找到对应的servlet执行init方法,然后创建servletRequest对象和servletResponse对象,调用service方法,执行goGet或者doPost,也就是自己重写的方法,最后得到结果响应给浏览器
servlet,filter,listener,interceptor的区别?
servlet:创建并返回一个包含基于客户请求性质的动态内容的完整html页面
filter:能够在一个请求到达servlet之前预处理用户请求,也可以在离开servlet时处理http响应
listener:主要就是用于监听servletContext,httpsession,servletRequest的
interceptor:与过滤器相似,处理用户的请求和响应
springboot与spring?
springboot是spring框架的扩展,它消除了设置spring应用程序所需的复杂例行配置
特征(区别):1.通过提供的starters简化构建配置
2.嵌入式的tomcat
3.尽可能的自动配置spring
4.可以直接通过main函数启动,嵌入式web服务器,避免了应用程序部署的复杂性
5.无需再像spring那样有一堆xml文件配置
6.提供了pom可以简化maven的配置
springboot中的@Bean?
@Bean标注在方法上(返回某个实例的方法),等价于spring的xml配置文件中的<bean>,作用就是注册bean对象
1)@Bean注解在返回实例的方法上,如果未通过@bean指定的名称,则默认与标注的方法名相同
2)@Bean注解默认作用域为singleton作用域,可以通过@Scope来设置其他作用域
使用xml注册bean和使用注解@Bean注册对象之间有什么明显的区别?
加载对象存在一定的先后顺序时会出现循环加载bean的问题(@Bean)
spring启动执行流程?
1.web.xml中提供了ContextLoaderListener
2.web容器启动时会进行初始化执行ContextLoaderListener中的contextInitialized方法
3.调用父类的initWebApplicationContext方法(在initWebApplicationContextinitlized中会执行三个任务:
1.创建WebApplicationContext容器
2.加载spring配置文件
3.初始化配置文件以及配置文件里面的bean)
4.结束调用ContextLoaderListener里面的ContextDistroyed方法,销毁Context容器
springmvc中的controller的返回值有哪些?
1.ModelAndView
2.String
3.void
4.自定义返回类型
Servlet和Jsp的区别?
1.jsp的本质就是Servlet,jvm只能识别java类,不能识别jsp的代码,web容器会将jsp的代码编译成jvm能够识别的java类
jsp的工作原理:jsp页面在执行的时候会被服务端的jsp引擎转换为Servlet,然后又由jsp引擎调用java编译器,将servlet编译成class文件,并有jvm解释执行
2.servlet的应用逻辑是在java文件中,从java代码中动态输出html,并且完全从表示层的html里分离开来,而jsp则是java和html组合成一个扩展名为.jsp的文件。jsp侧重于视图,servlet侧重于控制逻辑
Servlet中的filter?
在Servlet中,我们有时候需要filter来进行对信息的过滤
优点:1.过滤器是可插拔的,不需要某个过滤器时,直接删掉不会影响程序的运行
2.一个过滤器不依赖于另一个资源
3.维护少,容易维护
过滤器的创建:实现Filter接口,该接口有如下方法
然后Filter需要进行配置,比如在web.xml里配置filter和filter-mapping
循环引用的解决方法?
1.使用@Autowired注解,由spring来决定对象属性的注入时机
2.基于setter方法注入属性