Spring面试总结

Spring是一个轻量级java开发框架,目的是为了解决企业级应用开发的业务逻辑层和其他层的耦合问题,是分层的java SE/EE一站式轻量级开源框架,为开发java应用程序提供全面的基础架构支持,以IOC和AOP为内核。

Spring优点
1)、方便解耦,简化开发:IoC,对象的创建和依赖关系交给spring管理
2)、AOP的支持:提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能
3)、声明式事务支持:通过配置就可以完成对事物的管理,而无需手动编程
4)、方便程序测试:提供JUnit4,通过注解方便的测试Spring程序
5)、方便集成各种优秀框架:内部提供了对各种优秀框架的直接支持,如Struts2、mybatis、hibernate等
6)、降低Java EE API的使用难度:对复杂的API进行了封装,降低了使用难度,如JDBC,Java Mail等

Spring缺点
1)、spring大量依赖反射,反射影响性能;
2)、整合量大,学习起来需要一定时间;
3)、配置量巨大,依赖关系复杂。

Spring采取4种关键策略 (为了降低Java开发的复杂性)
1)、基于POJO的轻量级和最小侵入性编程; 
2)、通过依赖注入和面向接口实现松耦合;
3)、基于切面和惯例进行声明式编程; 
4)、通过切面和模板减少样板式代码。 

Spring设计目标:Spring为开发者提供一个一站式轻量级应用开发平台; 
Spring设计理念:在JavaEE开发中,支持POJO和JavaBean开发方式,使应用面向接口开发,充分支持OO(面向对象)设计方法;Spring通过IoC容器实现对象耦合关系的管理,并实现依赖反转,将对象之间的依赖关系交给IoC容器, 实现解耦; 
Spring框架的核心:IoC容器和AOP模块。通过IoC容器管理POJO对象以及他们之间的耦合关系;通过AOP以动态非侵入的方式增强服务。IoC让相互协作的组件保持松散的耦合,而AOP编程允许你把遍布于应用各层的功能分离出来形成可重用的功能组件。

Spring模块组成
6大模块:
1)、核心容器(Core Container,Beans、Core、Context、SpEL)
2)、AOP(Aspect Oriented Programming)和设备支持(Instrmentaion)
3)、数据访问与集成(Data access/Integeration,JDBC、ORM、OXM、JMS、Transactions)
4)、Web
5)、消息(Messaging)
6)、Test

Spring常用组件
spring core:提供了框架的基本组成部分,包括控制反转(Inversion of Control,IoC)和依赖注入(Dependency Injection,DI)功能。
spring beans:提供了BeanFactory,是工厂模式的一个经典实现,Spring将管 理对象称为Bean。 
spring context:构建于 core 封装包基础上的 context 封装包,提供了一种框 架式的对象访问方法。 
spring jdbc:提供了一个JDBC的抽象层,消除了烦琐的JDBC编码和数据库厂 商特有的错误代码解析, 用于简化JDBC。
spring aop:提供了面向切面的编程实现,让你可以自定义拦截器、切点等。
spring Web:提供了针对 Web 开发的集成特性,例如文件上传,利用 servlet listeners 进行 IoC 容器初始化和针对 Web 的 ApplicationContext。 
spring test:主要为测试提供支持的,支持使用JUnit或TestNG对Spring组件进 行单元测试和集成测试。

Spring常用注解及作用
@Configuration:声明类为配置类
@Value:从.properties文件中读取值
@Controller:声明展示层类
@Service:声明业务层类
@Repository:声明持久层类
@Component:以上三种都可以
@Autowired:先按byType,如果发现找到多个bean,则,又按照byName方式比对,如果还有多个,则报出异常
@Qualifier(“beanName”):手动指定按byName方式注入(与@Autowired配合使用)
@Resource:默认按 byName自动注入,如果找不到再按byType找bean,如果还是找不到则抛异常,无论按byName还是byType如果找到多个,则抛异常(也可手动指定@Resource(name=”beanName”)或@Resource(type=”beanType”))
@Inject:与@Autowired相同,与spring无关,属于jsr330规范
@RequestBody:用于获得请求体内容
@RequestParam:用于将请求参数区数据映射到功能处理方法的参数上(在SpringMVC后台控制层获取参数的方式主要有两种:一种是request.getParameter("name"),另外一种是用注解@RequestParam直接获取)
        name 参数的名称,需要和url传递的参数名一致
        required 参数是否必须
        value name的别名
        defaultValue 默认值
@PathVariable:是用来获得请求url中的动态参数的(例如: someUrl/{paramId})
@RestController= @Controller + @ResponseBody:返回json格式数据给前端
@RequestMapping 指定请求路径及请求方式
        value:指定请求的实际地址,指定的地址可以是URI Template 模式;
        method:指定请求的method类型, GET、POST、PUT、DELETE等
@GetMapping(value = “page”)等价于@RequestMapping(value = “page”, method = RequestMethod.GET)
@PostMapping(value = “page”)等价于@RequestMapping(value = “page”, method = RequestMethod.POST)
@Primary:自动装配时当出现多个Bean候选者时,被注解为@Primary的Bean将作为首选者,否则将抛出异常

@Autowired和@Resource之间的区别 
@Autowired可用于:构造函数、成员变量、Setter方法 @Autowired和@Resource之间的区别 @Autowired默认是按照类型装配注入的,默认情况下它要求依赖对 象必须存在(可以设置它required属性为false)。
@Resource默认是按照名称来装配注入的,只有当找不到与名称匹配 的bean才会按照类型来装配注入。

Spring配置元数据的方式
1)、XML配置;
2)、注解配置;
3)、java配置。

Spring bean的注入方式(XML文件方式)
1)、set方法注入
2)、构造方法注入(1、通过index设置参数的位置;2、通过type设置参数类型;3、通过参数名称设置)
3)、静态工厂注入
4)、实例工厂注入

Spring加载XML文件流程
1)、加载 xml 配置文件,遍历其中的 <bean> 标签
2)、获取<bean>标签中的 id 和 class 属性,加载 class 属性对应的类,并创建 bean
3)、遍历 <bean> 标签中的 <property> 标签,获取属性值,并将属性值填充到 bean 中
4)、将 bean 注册到 bean 容器中

Spring IoC(反射机制)
IoC(Inversion Of Control):控制反转,简单来说就是将对象的创建的权利及对象的生命周期的管理过程交由Spring框架来处理,从此在开发过程中不再需要关注对象的创建和生命周期的管理,而是在需要时由Spring框架提供,这个由spring框架管理对象创建和生命周期的机制称之为控制反转。
DI(Dependency Injection):依赖注入,由IoC容器在运行期间,动态地将某种依赖关系注入到对象之中

反射:在java运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

获取Class对象的四种方式:
1)、通过Class.forName(类的全限定名)
2)、通过java类型获取:类名.class(基本类型的包装类型使用.TYPE)
3)、通过对象实例获取:obj.getClass()
4)、通过类对应的类加载器获取:ClassLoader.loadClass(类的全限定名)

getDeclaredMethod和getMethod区别:
getDeclaredMethod:获取当前类的所有声明的方法,包括public、protected和private修饰的方法。需要注意的是,这些方法一定是在当前类中声明的, 从父类中继承的不算,实现接口的方法由于有声明所以包括在内。
getMethod:获取当前类和父类的所有public的方法。这里的父类,指的是继承层次中的所有父类。比如说,A继承B,B继承C,那么B和C都属于A的父类。


Spring AOP
AOP(Aspect Oriented Programming,面向切面编程):就是通过动态代理实现的,指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式;

AOP术语
通知(Advice):指拦截到连接点之后要执行的代码(描述了切面何时执行以及如何执行增强处理)
        @Before:前置通知,在执行业务代码(目标代码)前执行
        @After:后置通知,在执行业务代码(目标代码)后执行
        @AfterReturning:返回通知,在执行业务代码(目标代码)返回后执行
        @AfterThrowing:异常通知,在执行业务代码(目标代码)抛出异常后执行
        @Around:环绕通知,将业务代码(目标代码)封装起来
连接点(JoinPoint):就是被拦截到的程序执行点(被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器)
切点(PointCut):是对连接点进行拦截的条件定义
切面(Aspect):切面是通知和切点的结合。
引入(Introduction):引入允许我们向现有的类添加新的方法或者属性。
织入(Weaving):织入是将切面和业务逻辑对象连接起来, 并创建通知代理的过程。
目标对象(Target):指将要被增强的对象,即包含主业务逻辑的类对象。或者说是被一个或者多个切面所通知的对象。

静态代理:指在jvm运行之前就已经获取到代理类的class信息,逻辑由开发者实现;(由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了)
动态代理:在程序运行时运用反射机制动态创建而成。
        JDK动态代理:
        实现原理:JDK的动态代理是基于反射实现。JDK通过反射,生成一个代理类,这个代理类实现了原来那个类的全部接口,并对接口中定义的所有方法进行了代理。当我们通过代理对象执行原来那个类的方法时,代理类底层会通过反射机制,回调我们实现的InvocationHandler接口的invoke方法。并且这个代理类是Proxy类的子类;(在运行期,目标类加载后,为接口动态生成代理类,将切面织入到代理类中)
        实现方式:实现InvocationHandler接口,重写invoke方法,这个方法就是提供的代理方法;通过Proxy类的newProxyInstance方法返回一个代理对象。
Proxy.newProxyInstance(ClassLoader loader , 类<?>[] interfaces , InvocationHandler h)返回指定接口的代理类的实例,该接口将方法调用分派给指定的调用处理程序。
             *  第一个参数:类加载器
             *  第二个参数:增强方法所在的类,这个类实现的接口,支持多个接口
             *  第三个参数:实现这个接口InvocationHandler,创建代理对象写增强的部分。
        Cglib动态代理:
        实现原理:底层采用了ASM字节码生成框架,直接对需要代理的类的字节码进行操作,生成这个类的一个子类,并重写了类的所有可以重写的方法,在重写的过程中,将我们定义的额外的逻辑(简单理解为Spring中的切面)织入到方法中,对方法进行了增强。而通过字节码操作生成的代理类,和我们自己编写并编译后的类没有太大区别。(在运行期,目标类加载后,动态生成目标类的子类,将切面逻辑加入到子类中)
        实现方式:实现MethodInterceptor接口,重写intercept方法。
        JDK动态代理和Cglib动态代理的区别:
JDK动态代理只能对实现了接口的类生成代理,而不能针对类;CGLib是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法(继承)

JDK动态代理为什么只能针对接口?
1)、生成的代理类继承了Proxy,由于java是单继承,所以只能实现接口,通过接口实现 
2)、从代理模式的设计来说,充分利用了java的多态特性,也符合基于接口编码的规范 
(因为JDK动态代理类已经继承了Proxy这个类,所以只能通过接口来与被代理类建立联系(两个类建立起联系,一是继承的关系【jdk已经不能通过这个方式了,因为java仅支持单继承】,另一种就是实现同一个接口【JDK动态代理选这种】),所以必须要求被代理类也得实现一个接口,这样的话代理类与被代理类就能通过这个接口建立联系了。)

Spring AOP中的代理使用的默认策略
如果目标对象实现了接口,则默认采用JDK动态代理
如果目标对象没有实现接口,则采用CgLib进行动态代理
如果目标对象实现了接口,且强制CgLib代理,则采用CgLib进行动态代理

Spring MVC流程(工作原理)

1)、用户发送请求至前端控制器DispatcherServlet;
2)、前端控制器DispatcherServlet收到请求调用处理器映射器HandlerMapping;
3)、处理器映射器根据请求url找到具体的处理器,生成处理器执行链HandlerExecutionChain(包括处理器Handler和拦截器Interceptor集合)返回给前端控制器DispatcherServlet;
4)、前端控制器DispatcherServlet根据处理器Handler获取处理器适配器HandlerAdapter,执行HandlerAdapter处理一系列操作;
5)、处理器适配器HandlerAdapter调用处理器Handler(Controller)执行;
6)、处理器Handler返回ModelAndView;
7)、处理器适配器HandlerAdapter将ModelAndView返回到前端控制器DispatcherServlet;
8)、前端控制器DispatcherServlet将ModelAndView传给视图解析器ViewReslover;
9)、视图解析器返回真正的视图View;
10)、前端控制器DispatcherServlet对视图View进行渲染(模型数据Model填充至视图View中);
11)、前端控制器DispatcherServlet响应结果给用户。

ApplicationContext实现类
1)、ClassPathXmlApplicationContext:从类路径下加载配置文件
2)、FileSystemXmlApplicationContext:加载磁盘任意路径下的配置文件
3)、AnnotationConfigApplicationContext:读取注解创建容器
4)、XmlWebApplicationContext:从web应用下加载配置文件

Spring中BeanFactory和ApplicationContext的区别
BeanFactory:Spring里面最底层的接口,包含了各种Bean定义,读取bean配置文档,管理Bean的加载、实例化,控制bean的生命周期,维护bean之间的依赖关系;
ApplicationContext:BeanFactory的派生接口,除了具有BeanFactory所有功能外,还提供了国际化、统一资源文件访问方式、提供在监听器中注册bean的事件、同时加载多个配置文件等功能。
区别:
1)、BeanFactory采用延迟加载方式注入bean,即第一次getBean时才会加载实例化;ApplcationContext则采用预加载方式,即容器启动时,一次性创建所有bean实例;
2)、ApplicationContext是BeanFactory的派生接口,除了具有BeanFactory所有功能外,还提供了国际化、统一资源文件访问方式、提供在监听器中注册bean的事件、同时加载多个配置文件等功能;
3)、BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册。

BeanFactory和FactoryBean的区别
BeanFactory提供了IoC容器最基本的形式,给具体的IoC容器的实现提供了规范;
FactoryBean可以说为IoC容器中Bean的实现提供了更加灵活的方式,FactoryBean在IoC容器的基础上给Bean的实现加上了一个简单工厂模式和装饰模式,我们可以在getObject()方法中灵活配置。

Spring bean的作用域
singleton(容器中只会存在一个共享Bean实例,无论多少Bean引用它,始终指向同一对象)
prototype(每次通过容器获取prototype定义bean时,容器都创建一个新的Bean实例)
request(在一次Http请求中,容器会返回改Bean的同一实例。而对不同的Http请求则会产生新的Bean,而且该Bean仅在当前Http Request内有效)
session(在一次Http Session中,容器会返回Bean的同一实例。而不同的Session请求则会创建新的实例,该Bean实例仅在当前Session内有效)
global session(在一个全局Http Session中,容器会返回该Bean同一实例,仅在使用portlet context时有效)

Spring bean单例安全吗?如何解决安全问题?
如果是有状态对象就是非线程安全的;(有状态对象,即有实例变量的对象,可以保存数据)
如果是无状态对象就是线程安全的。(无状态对象,即没有实例变量的对象,不能保存数据,是不变类)
不安全解决方法:1)、加锁解决;2)、ThreadLocal解决(spring使用的就是此方法)。

Spring bean的生命周期?
Spring对bean进行实例化;
Spring将值和bean的引用注入到bean对应的属性中; 
如果bean实现了BeanNameAware接口,Spring将bean的ID传递给setBeanName()方法; 
如果bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory()方 法,将BeanFactory容器实例传入; 
如果bean实现了ApplicationContextAware接口,Spring将调用 setApplicationContext()方法,将bean所在的应用上下文的引用传入进来; 
如果bean实现了BeanPostProcessor接口,Spring将调用它们的postProcessBeforeInitialization()方法; 
如果bean实现了InitializingBean接口,Spring将调用它们的afterPropertiesSet()方法。类似地,如果bean使用initmethod声明了初始化方法, 该方法也会被调用; 
如果bean实现了BeanPostProcessor接口,Spring将调用它们的postProcessAfterInitialization()方法;
 此时,bean已经准备就绪,可以被应用程序使用了,它们将一直驻留在应用上 下文中,直到该应用上下文被销毁; 
如果bean实现了DisposableBean接口,Spring将调用它的destroy()接口方 法。同样,如果bean使用destroy-method声明了销毁方法,该方法也会被调用。 

Spring如何解决循环依赖问题?
构造器注入和prototype类型的field注入发生循环依赖时都无法初始化(无法解决)
field注入单例的bean时,尽管有循环依赖,但bean仍然可以被成功初始化
Spring解决单例循环依赖的问题,使用了三级缓存

Spring框架中采用了哪些设计模式
1)、工厂模式,BeanFactory就是简单产品工厂模式的体现,用来创建实例对象;
2)、单例模式,Spring Bean默认单例模式;
3)、代理模式,Spring AOP功能用到了JDK动态代理和cglib字节码生成技术;
4)、模板方法模式,用老解决代码重复问题,例如RestTemplate、JmsTemplate;
5)、观察者模式:Spring中的时间驱动模型,例如Spring中listener的实现-ApplicationListener;
6)、适配器模式:SpringMvc中的HandlerAdatper。

Spring 事务
spring事务配置方式
编程式事务:使用Transaction Ttempleate或者直接使用底层的Platform TransactionManager.对于编程式事务管理,spring推荐使用Transaction Template;简单的说就是在代码中需要直接加入处理事务的逻辑,可能需要在代码中显式调用begin Transaction() commit(). rollback() 等事务管理相关的方法,如在执行a方法的时候需要事务处理,你需要在a方法开始时候开启事务,处理完成之后,在方法结束的时候,关闭事务;
声明式事务:建立在AOP之上的,其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务,声明式事务最大的优点就是不需要通过编程的方式管理事务,这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需要在配置文件中做相关的事务规则声明(或通过基于@Transaction注解的方式),便可以将事务规则应用到业务逻辑中(声明式事务管理也有两种常用的方式,一种是基于tx和aop名字的xml配置文件,另一种就是基于@Transaction注解);
优缺点:显然声明式事务管理要优于编程式事务管理,这正是spring倡导的非侵入式的开发方式.声明式事务管理使业务代码不受污染,一个普通的POJO对象,只要加上注解就可以获得完全的事务支持.和编程式事务相比,声明式事务唯一不足的地方是,它的最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别.但是即便有这样的需求,也存在很多变通的方法,比如,可以将需要进行事务管理的代码块独立为方法等等。

事务产生的问题
脏读(Dirty read):脏读发生在一个事务读取了被另一个事务修改但尚未提交的数据时。如果这些改变在稍后被回滚了,那么第一个事务读取的数据就会是无效的;
不可重复读(Nonrepeatable read):不可重复读发生在一个事务执行相同的查询两次或两次以上,但每次查询结果都不相同时。这通常是由于另一个并发事务在两次查询之间更新了数据;(不可重复读重点在修改)
幻读(Phantom reads):幻读和不可重复读相似。当一个事务(T1)读取几行记录后,另一个并发事务(T2)插入了一些记录时,幻读就发生了。在后来的查询中,第一个事务(T1)就会发现一些原来没有的额外记录。(幻读重点在新增或删除)

Spring事务隔离级别
ISOLATION_DEFAULT:使用后端数据库默认的隔离级别(Oracle 默认级别--Read Committed,MYSQL默认级别--Repeatable Read);
ISOLATION_READ_UNCOMMITTED:允许读取尚未提交的更改。可能导致脏读、幻读或不可重复读;
ISOLATION_READ_COMMITTED:允许读取已提交的并发事务。可防止脏读,但幻读和不可重复读仍可能会发生;
ISOLATION_REPEATABLE_READ:对相同字段的多次读取的结果是一致的,除非数据被当前事务本身改变。可防止脏读和不可重复读,但幻读仍可能发生;
ISOLATION_SERIALIZABLE:完全服从ACID的隔离级别,确保不发生脏读、不可重复读和幻影读。这在所有隔离级别中也是最慢的,因为它通常是通过完全锁定当前事务所涉及的数据表来完成的。

Spring事务传播特性
PROPAGATION_REQUIRED:支持当前事务,若不存在新建;(默认)
PROPAGATION_SUPPORTS:支持当前事务,若不存在则不使用事务;
PROPAGATION_REQUIRED_NEW:若存在当前事务,则挂起,然后新建一个事务;
PROPAGATION_MANDATORY:支持当前事务,若不存在,抛出异常;
PROPAGATION_NOT_SUPPORTED:以非事务方式运行,若存在当前事务,则挂起;
PROPAGATION_NEVER:以非事务方式运行,若存在对当前事务,则抛出异常;
PROPAGATION_NESTED:若当前事务存在,则在嵌套事务中运行,若当前事务不存在,则行为与PROPAGATION_REQUIRED一致。

Spring事务失效情况
1)、数据库引擎不支持事务,如MySQL数据库MyISAM就不支持事务;
2)、方法没有被public修饰;( @Transactional 只能用于 public 的方法上,否则事务不会生效,因为事务底层基于AOP,jdk动态代理需要方法是public,若非public,也可开启AspectJ解决)
3)、异常被try catch捕捉了;
4)、异常类型错误,默认运行时异常(RuntimeException)才会回滚;(可以使用@Transactional(rollbackFor = Exception.class)修改)
5)、自身调用问题;(同一个类中的方法之间调用)
6)、重复开启注解扫描;(Spring+SpringMVC)
7)、类没有被Spring容器管理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值