目录
- 1. 何为Spring Bean容器?Spring Bean容器与Spring IOC 容器有什么不同吗?
- 2. Spring IOC 如何理解?
- 3. Spring DI 如何理解?
- 4. Spring 中基于注解如何配置对象作用域?以及如何配置延迟加载机制?
- 1.配置作用域需要注解@Scope(“Singleton”)
- 2.开启延迟加载:@Lazy(value=true)
- 5. Spring 工厂底层构建Bean对象借助什么机制?当对象不使用了要释放资源,目的是什么?何为内存泄漏?
- 6. 描述Spring MVC处理流程及应用优势?
- 处理流程
- 应用优势
- 7. Spring中的事务处理方式及优缺点?
- 编程式事务管理
- 声明式事务管理
- 8. MyBatis应用中#与$有什么异同点?
- 9. MyBatis应用动态SQL解决了什么问题?
- 10. Shiro框架权限管理时的认证和授权流程描述?
- 认证流程
- 授权流程
- 11. BeanFactory和ApplicationContext有什么区别?
- 12. 请解释Spring Bean的生命周期?
- 13. Spring Bean的作用域之间有什么区别?
- 14. 在Spring AOP 中,关注点和横切关注的区别是什么?
- 15. 使用Spring框架的好处是什么?
- 16. Spring 中用到了那些设计模式?
- 17. Spring 如何保证 Controller 并发的安全?
- 18. 在 Spring中如何注入一个java集合?
- 19. Spring支持的事务管理类型?
- 20. Spring框架的事务管理有哪些优点?
- 21. Spring MVC的主要组件?
- 22. SpringMvc怎么和AJAX相互调用的?
- 23. Mybatis 中#和$的区别?
- 24. mybatis的缓存机制,一级,二级介绍一下?
- 一级缓存
- 二级缓存
- 25. springMVC与Struts2的区别?
- 26. mybatis的基本工作流程?
- 27. 什么是MyBatis的接口绑定,有什么好处?
- 28. MyBatis的编程步骤?
- 29. JDBC编程有哪些不足之处,MyBatis是如何解决这些问题的?
- 30. MyBatis的优缺点?
- 优点
- 缺点
- 总结
1. 何为Spring Bean容器?Spring Bean容器与Spring IOC 容器有什么不同吗?
Spring Bean容器是Spring框架中用于管理应用程序对象的工具。具体来说,它负责实例化、配置和组装应用程序中的对象,这些对象被称为Bean。Bean是由Spring IoC(控制反转)容器管理的对象,这些Bean根据配置文件中的信息创建,并由IoC容器进行实例化和管理。
Spring Bean容器与Spring IOC容器在概念上是相同的,因为它们都是用来管理应用程序中对象的工具。然而,在实际应用中,人们通常会将“Bean容器”和“IOC容器”混用,尽管它们在技术上可以互换使用。Spring的IoC容器不仅管理Bean的生命周期,还提供了依赖注入(DI)功能,通过构造函数参数、工厂方法或对象实例后设置属性来定义其依赖项。
2. Spring IOC 如何理解?
Spring IOC(Inversion of Control,控制反转)是Spring框架的核心概念之一,它通过将对象的创建和依赖关系的管理交由Spring容器来完成,从而实现了对象之间的松耦合编程。在传统的软件开发中,对象之间的依赖关系通常由开发者手动管理和注入,这导致了代码之间的高耦合度。而使用Spring IOC后,这种依赖关系由Spring容器负责管理,从而降低了程序组件之间的耦合度。
具体来说,IOC的思想是将一个对象的控制权从程序内部转移到外部容器。例如,在传统编程中,我们通常会通过new关键字来创建对象,这样就直接控制了对象的生命周期和依赖关系。而在Spring中,这些任务都由Spring容器来处理,开发者只需要定义好需要的对象及其依赖关系,剩下的工作就交给Spring容器去完成。
依赖注入(DI)是实现IOC的一种方法。DI允许将对象的依赖关系通过构造器参数、工厂方法参数或属性的方式注入到对象中,而不是在对象内部显式地创建这些依赖对象。这种方式不仅简化了代码,还提高了可维护性和可测试性。
Spring IOC的实现基于工厂设计模式和反射技术。Spring容器作为一个高级工厂,负责对象的实例化、配置和管理。当需要使用某个对象时,Spring容器会根据配置信息动态地生成该对象,并将其依赖关系注入到相应的属性中。此外,Spring还提供了两种主要的IOC容器实现:BeanFactory和ApplicationContext。BeanFactory是基本的IOC容器接口,而ApplicationContext则提供了更多的功能,如国际化支持和事件发布等。
3. Spring DI 如何理解?
Spring IOC(Inversion of Control,控制反转)是Spring框架的核心概念之一,它通过将对象的创建和依赖关系的管理交由Spring容器来完成,从而实现了对象之间的松耦合编程。在传统的软件开发中,对象之间的依赖关系通常由开发者手动管理和注入,这导致了代码之间的高耦合度。而使用Spring IOC后,这种依赖关系由Spring容器负责管理,从而降低了程序组件之间的耦合度。
具体来说,IOC的思想是将一个对象的控制权从程序内部转移到外部容器。例如,在传统编程中,我们通常会通过new关键字来创建对象,这样就直接控制了对象的生命周期和依赖关系。而在Spring中,这些任务都由Spring容器来处理,开发者只需要定义好需要的对象及其依赖关系,剩下的工作就交给Spring容器去完成。
依赖注入(DI)是实现IOC的一种方法。DI允许将对象的依赖关系通过构造器参数、工厂方法参数或属性的方式注入到对象中,而不是在对象内部显式地创建这些依赖对象。这种方式不仅简化了代码,还提高了可维护性和可测试性。
Spring IOC的实现基于工厂设计模式和反射技术。Spring容器作为一个高级工厂,负责对象的实例化、配置和管理。当需要使用某个对象时,Spring容器会根据配置信息动态地生成该对象,并将其依赖关系注入到相应的属性中。此外,Spring还提供了两种主要的IOC容器实现:BeanFactory和ApplicationContext。BeanFactory是基本的IOC容器接口,而ApplicationContext则提供了更多的功能,如国际化支持和事件发布等。
4. Spring 中基于注解如何配置对象作用域?以及如何配置延迟加载机制?
1.配置作用域需要注解@Scope(“Singleton”)
单例(Singleton):在整个应用中,只创建 Bean 的一个实例。
原型(Prototype):每次注入或者通过 Spring 应用上下文获取的时候,都会创建一个新的 Bean 实例。
会话(Session): 在 Web 应用中,为每个会话创建一个 Bean 实例。
请求(Request):在 Web 应用中,为每个请求创建一个 Bean 实例。
2.开启延迟加载:@Lazy(value=true)
5. Spring 工厂底层构建Bean对象借助什么机制?当对象不使用了要释放资源,目的是什么?何为内存泄漏?
Spring 工厂底层构建Bean对象主要借助于 Spring 的 IOC(控制反转)容器机制。这个机制的核心是通过依赖注入来管理对象的创建和配置,从而简化了对象之间的依赖关系。
当对象不再使用时,Spring 容器会调用适当的生命周期方法来进行资源释放。这些方法包括 销毁 方法(如 destroy()),以确保在对象生命周期结束时能够正确地释放资源,避免内存泄漏。具体来说,如果是一个单例对象,Spring 在容器启动时调用构造方法创建对象,并在容器关闭时调用销毁方法;如果是多例对象,则每次请求都会重新创建对象。
内存泄漏是指应用程序在不再使用的对象上仍然保持对内存的占用,导致无法被垃圾回收器释放的现象。在 Spring 中,常见的内存泄漏原因包括未关闭的数据库连接、文件流等资源未正确释放。此外,ThreadLocal 的引用问题也可能导致内存泄漏,因为它们在没有外部强引用来维持其生命周期的情况下,会在下次JVM垃圾收集时被回收
6. 描述Spring MVC处理流程及应用优势?
Spring MVC是基于MVC(Model-View-Controller)设计模式的Web框架,它通过一系列组件的协作来处理HTTP请求。以下是其处理流程及应用优势的详细描述:
处理流程
用户发送一个HTTP请求到前端控制器DispatcherServlet。DispatcherServlet是Spring MVC的核心组件,负责接收所有进入应用的请求,并进行初步处理。
DispatcherServlet调用HandlerMapping对象,将请求的URL映射到具体的Handler(处理器),这一步决定了哪个Controller处理该请求。
HandlerAdapter根据Handler的信息创建一个MethodInvocableHandlerMethod实例,然后调用Controller的具体方法处理请求,并返回一个ModelAndView对象。
DispatcherServlet再调用ViewResolver对象解析ModelAndView中的视图名称,生成实际的View对象。
最后,View对象对Model数据进行渲染,生成最终的响应内容并返回给DispatcherServlet。
DispatcherServlet将渲染后的结果封装成响应对象并返回给客户端。
其他:
-
用户发送请求至前端控制器(DispatcherServlet);
提示:DispatcherServlet的作用:接收请求,调用其它组件处理请求,响应结果,相当于转发器、中央处理器,是整个流程控制的中心。 -
前端控制器(DispatcherServlet)收到请求后调用处理器映射器(HandlerMapping),处理器映射器(HandlerMapping)找到具体的Controller返回给前端控制器;
-
前端控制器(DispatcherServlet)调用处理器适配器(HandlerAdapter);
-
前端控制器(DispatcherServlet)将执行的结果(ModelAndView)传给视图解析器(ViewReslover),
视图解析器(ViewReslover)根据View(逻辑视图名)解析后返回具体JSP页面; -
前端控制器(DispatcherServlet)根据Model对View进行渲染(即将模型数据填充至视图中),
前端控制器(DispatcherServlet)将填充了数据的网页响应给用户;
应用优势
Spring MVC基于IoC(控制反转)容器创建,把应用程序分成几个独立的部分,每个部分都做自己的工作并通过应用程序上下文以松散耦合的形式与其他部分协作。
Spring MVC提供了高度的灵活性,可以根据不同的应用程序要求进行配置和使用。它支持多种视图技术如JSP、Velocity、Freemarker等,并且可以使用自定义视图解析器。
作为Spring框架的一部分,Spring MVC可以方便地利用Spring所提供的其他功能,同时也可以与其他框架轻松集成。
Spring MVC支持数据绑定和验证机制,能够自动将表单数据绑定到模型中,并在必要时进行校验,从而提高开发效率和用户体验。
Spring MVC不仅提供了一个前端控制器DispatcherServlet,还支持文件上传、语言环境和主题解析等多种功能。
通过以上流程和优势,Spring MVC为开发者提供了一种简单、灵活且可扩展的方式来构建Web应用程序,使其成为现代Web开发中的重要工具。
7. Spring中的事务处理方式及优缺点?
在Spring框架中,事务处理主要有两种方式:编程式事务管理和声明式事务管理。每种方式都有其优缺点。
编程式事务管理
优点:
细粒度控制:允许开发者在代码中显式地控制事务的开始、提交和回滚,可以精确地定义事务的边界。
灵活性高:适用于需要高度定制化事务控制的应用场景,例如跨多个数据源或不同类型的资源时。
缺点:
复杂性增加:需要手动编写大量的事务管理代码,增加了开发和维护的难度。
侵入性强:由于需要在代码中直接操作事务API(如beginTransaction()、commit()、rollback()),因此对应用代码的影响较大。
声明式事务管理
优点:
简化开发:通过注解或配置文件来声明事务规则,无需在代码中显式处理事务,极大地简化了开发工作。
轻量级容器:符合无侵入性原则,不会增加额外的依赖,适合大多数现代Java应用。
集成性好:与Spring的各种数据访问抽象层(如JDBC、Hibernate、JPA等)无缝集成,提供一致的编程模型。
细粒度控制:支持嵌套事务和跨层事务管理,能够实现更细粒度的事务控制能力。
缺点:
配置复杂:尽管声明式事务管理减少了代码中的事务管理逻辑,但其配置可能相对复杂,需要正确设置事务属性和传播行为。
性能开销:虽然一般情况下影响不大,但在某些极端情况下可能会引入一定的性能开销
。
8. MyBatis应用中#与$有什么异同点?
在MyBatis应用中,#和$符号用于动态构造SQL语句的占位符,它们之间有以下几点主要区别:
参数处理方式:
#
符号(即#{}
)将传入的参数视为字符串,并自动为参数添加单引号。例如,如果传入一个名为id的参数,那么最终生成的SQL语句会是order by “11”。
$
符号(即${}
)则直接将传入的参数值替换到SQL语句中,不进行任何特殊处理。这意味着它不会对参数进行任何转义或安全检查。
SQL注入防护:
使用#
符号可以很大程度上防止SQL注入,因为其预编译机制会自动处理特殊字符并确保安全性。
使用$
符号则无法有效防止SQL注入,因为它只是简单地将参数值拼接到SQL语句中,这使得SQL注入的风险大大增加。
性能差异:
#
符号使用的是PreparedStatement对象来执行SQL语句,这种方式效率较高且更安全。
$
符号使用的是Statement对象来执行SQL语句,这种方式效率较低且存在SQL注入风险。
适用场景:
在大多数情况下,推荐使用#符号,因为它提供了更高的安全性和更好的性能。
在某些特定情况下,如需要拼接变量且这些变量上不能带单引号时,可以选择使用$
符号。
其他
相同点:都是通过get来取值的;
不同点:$
传过去的字符串不带引号,#
号带引号;
9. MyBatis应用动态SQL解决了什么问题?
MyBatis应用动态SQL主要解决了以下几个问题:
灵活生成SQL语句:MyBatis的动态SQL可以根据不同的条件生成不同的SQL语句,从而实现灵活的查询和更新操作。这使得开发者能够根据具体的业务需求动态拼接SQL,满足各种复杂的查询和更新需求。
避免手动拼接SQL时的错误:在使用JDBC或其他类似框架时,手动拼接SQL字符串非常痛苦且容易出错,如忘记添加必要的空格或省略列表末尾的逗号等。MyBatis通过提供强大的动态SQL语言(如if、choose、when、otherwise、trim、where、set等标签),大大减少了这些错误的发生。
提高代码可读性和可维护性:通过将SQL语句与Java代码分离,MyBatis的动态SQL不仅提高了代码的可读性,还使得代码更加清晰和易于维护。此外,它还可以通过简单的XML配置或注解来定义和映射SQL语句,进一步提升了开发效率。
解决条件不满足导致的SQL语句错误:MyBatis提供了元素和OGNL表达式,可以自定义条件语句的行为,使其仅在有内容返回时插入“WHERE”,并删除以“AND”或“OR”开头的任何内容,从而避免因条件不满足而导致的SQL语句错误。
减少重复代码和提高重用性:MyBatis的动态SQL允许使用类似于Java中的if-else、switch-case结构,以及for循环等逻辑控制方式,从而提取可重用的SQL片段,减少重复代码。
10. Shiro框架权限管理时的认证和授权流程描述?
认证流程
创建Subject实例并登录
用户通过调用Subject.login (token)方法进行登录操作。这个token封装了用户的身份信息(如用户名和密码)。
SecurityManager委托给Authenticator进行认证
SecurityManager会自动调用Authenticator来执行认证逻辑。Authenticator会调用Realm获取用户的原始数据,并与用户提供的信息进行匹配,以验证用户身份。
Realm处理认证
Realm是Shiro的核心组件之一,负责具体的认证逻辑。它连接到数据库或其他存储系统,根据提供的用户名和密码验证用户身份。如果验证成功,则返回相应的身份信息。
会话管理
认证成功后,SecurityManager创建一个会话(Session),保存用户的认证信息。在没有退出之前,当前用户的所有信息都会保存在这个会话中。
授权流程
调用hasRole或isPermitted方法
在认证成功后,用户需要访问特定资源时,调用hasRole或isPermitted方法进行授权检查。这些方法会从SecurityManager获取用户的角色和权限信息。
SecurityManager委托给Authorizer进行授权
SecurityManager会委托给Authorizer进行授权逻辑处理。Authorizer会调用Realm获取用户的权限信息,并与请求的资源权限进行匹配,以确定用户是否有权限访问该资源。
Realm处理授权
同样地,Realm负责具体的授权逻辑。它会根据用户的角色和权限信息判断用户是否具有访问特定资源的权限。如果验证通过,则允许访问;否则,拒绝访问。
其他:
应用代码->调用Subject(登录用户)控制权限->Subject在shiro内部调用SecurityManager(安全管理器)->安全管理器调用Realm(程序和安全数据连接器,连接后台数据库)
11. BeanFactory和ApplicationContext有什么区别?
BeanFactory和ApplicationContext是Spring框架中的两个核心接口,它们都用于管理Bean的创建和依赖注入。然而,两者之间存在一些显著的区别:
继承关系:
ApplicationContext是BeanFactory的子接口。这意味着ApplicationContext不仅包含了BeanFactory的所有功能,还增加了额外的功能。
加载策略:
BeanFactory支持懒加载(延迟实例化),即只有在第一次调用getBean方法时才会实例化Bean。
ApplicationContext则在启动时就预先实例化所有的Bean,这样可以避免在运行时再进行实例化带来的性能开销。
国际化支持:
BeanFactory不支持国际化(i18n),而ApplicationContext提供了对国际化的支持,可以通过MessageSource接口获取多语言资源。
事件发布:
ApplicationContext能够将事件发布到注册为监听器的Bean中,这使得应用程序可以更容易地实现事件驱动的架构。
高级特性:
ApplicationContext提供了更多的高级特性,如AOP(面向切面编程)集成、环境属性访问、事务管理等。这些特性使得ApplicationContext更加适合企业级应用的开发。
应用场景:
在大多数情况下,推荐使用ApplicationContext作为Spring容器,因为它提供了更全面的功能和更好的用户体验。然而,在资源受限的小型嵌入式应用程序中,为了节省内存消耗,可以选择使用BeanFactory。
12. 请解释Spring Bean的生命周期?
pring Bean的生命周期是指从一个普通的Java类变成由Spring管理的对象的过程,这个过程分为四个主要阶段:实例化(Instantiation)、属性填充(Property Population)、初始化(Initialization)和销毁(Destruction)。每个阶段都有其特定的作用和回调方法,允许开发者在不同阶段进行自定义操作。
实例化(Instantiation) :
在这一阶段,Spring首先为Bean分配内存空间,并调用构造函数创建对象。这一步是Bean生命周期的开始,确保了Bean的基本结构已经形成。
属性填充(Property Population) :
属性填充是指将配置好的依赖注入到Bean中。Spring通过反射机制调用setter方法或直接使用字段赋值来完成属性的填充。这一过程也称为依赖注入(DI),是Spring的核心功能之一。
初始化(Initialization) :
初始化阶段是指调用Bean定义的初始化方法(如initMethod),或者调用实现了InitializingBean接口中的initMethod方法。在这个阶段,可以执行一些需要在Bean完全可用之前完成的操作,例如建立数据库连接、打开网络连接等。
销毁(Destruction) :
销毁阶段是指调用Bean定义的销毁方法(如destroyMethod),或者调用实现了 DisposableBean接口中的destroyMethod方法。在Spring容器关闭时,会调用这些方法来释放资源,例如关闭数据库连接、清理缓存等。
除了这四个主要阶段外,Spring还提供了许多扩展点,允许开发者在实例化、初始化和销毁过程中插入自定义代码。这些扩展点包括但不限于以下几种:
BeanPostProcessor:可以在实例化后和属性填充前进行处理。
BeanFactoryPostProcessor:可以在整个Bean生命周期中进行处理。
AOP代理生成:在Bean初始化过程中,Spring会自动为其生成AOP代理对象,以支持面向切面编程(AOP)。
13. Spring Bean的作用域之间有什么区别?
在Spring框架中,Bean的作用域决定了该Bean实例的生命周期和可见性范围。Spring提供了多种不同的作用域类型,每种类型都有其特定的应用场景和行为特点。以下是主要的作用域及其区别:
singleton(单例) :
这是默认的作用域,确保在整个应用程序中只有一个Bean实例。
Spring容器在第一次获取Bean时创建实例,并在后续请求中返回同一个实例。
适用于需要全局唯一实例的场景,如配置文件读取器、日志记录器等。
prototype(原型) :
每次请求都会创建一个新的Bean实例。
Spring容器在初始化、配置、装饰或装配完一个prototype bean后,不再管理其后续生命周期。
适用于需要多次创建不同实例的场景,如Web表单验证器、用户会话管理等。
request(请求) :
每一次HTTP请求都会产生一个新的Bean实例。
该Bean仅在当前HTTP请求内有效,请求结束后Bean即被销毁。
适用于Web应用中的短期数据处理,如表单提交后的临时对象。
session(会话) :
在同一个HTTP session中共享同一个Bean实例。
session结束时Bean被销毁。
适用于需要在用户会话期间保持状态的场景,如用户的登录信息。
globalSession(全局会话) :
在整个应用程序范围内共享同一个Bean实例。
全局会话结束时Bean被销毁。
适用于需要在整个应用程序范围内共享状态的场景,如企业级的权限管理。
14. 在Spring AOP 中,关注点和横切关注的区别是什么?
在Spring AOP(面向切面编程)中,关注点(Concern)和横切关注点(Cross-Cutting Concern)是两个相关但不同的概念。
关注点(Concern) :
关注点是指应用中一个模块的行为或功能。它代表了系统中的具体模块或任务,例如某个类的方法实现的功能。
每个关注点可以被定义为一个我们想实现的具体功能,并且通常与特定的业务逻辑直接相关。
横切关注点(Cross-Cutting Concern) :
横切关注点是指那些跨越多个模块的通用功能,这些功能影响整个应用程序而不仅仅是单个模块。例如日志记录、事务管理和安全性等。
这些横切关注点通常与核心业务逻辑无关,但需要在多个地方进行处理,因此通过AOP的切面可以将它们模块化,从而提高代码的可维护性和重用性。
15. 使用Spring框架的好处是什么?
使用Spring框架有诸多好处,这些优点主要体现在以下几个方面:
简化开发: Spring框架提供了丰富的工具和技术,能够帮助开发人员快速构建应用程序。例如,通过依赖注入(DI)和面向切面编程(AOP),可以减少代码的复杂性,提高开发效率。
非侵入式设计: Spring是一种非侵入式框架,这意味着应用程序代码对框架的依赖最小化,从而降低了系统的耦合度。
轻量级: Spring框架本身非常轻量,基本版本大约只有2MB,这使得它在内存和CPU资源有限的情况下进行应用程序的开发和发布变得十分有利。
支持多种数据访问技术: Spring框架支持各种数据访问技术,如JDBC、Hibernate等,使开发者能够方便地实现数据持久化。
事务管理:Spring提供了声明式事务管理功能,只需通过配置即可完成复杂的事务处理,包括异常时的事务回滚和操作成功时的数据提交等。
面向切面编程(AOP) :Spring支持AOP,允许将业务逻辑与系统服务分开,从而提高了代码的可维护性和可扩展性。
依赖注入(DI) :Spring的DI机制降低了业务对象替换的复杂性,提高了组件之间的解耦。
模块化和分层架构:Spring采用模块化和分层架构,可以增量引入到项目中,有利于面向接口编程习惯的养成。
独立于应用服务器:基于Spring框架的应用可以真正实现“Write Once, Run Anywhere”的承诺,独立于各种应用服务器。
测试友好:Spring框架的设计非常适合单元测试和集成测试,使得程序的测试更加方便和高效。
16. Spring 中用到了那些设计模式?
Spring 框架中使用了多种设计模式,以提高其灵活性、可维护性和扩展性。以下是一些在 Spring 中常用的设计模式:
简单工厂模式:通过一个工厂类根据传入的参数动态决定应该创建哪一个产品类。
工厂方法模式:通过定义一个用于创建对象的接口,让子类决定实例化哪一个类。
单例模式:确保一个类只有一个实例,并提供一个全局访问点。
适配器模式:将一个类的接口转换成客户期望的另一个接口。
装饰器模式:动态地给对象添加职责。
代理模式:为其他对象提供一种代理以控制对这个对象的访问。
观察者模式:定义对象间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。
策略模式:定义一系列算法,把它们一个个封装起来,并使它们可以互换。
模板方法模式:定义算法的骨架,而将一些步骤延迟到子类中去实现。
此外,还有其他一些设计模式如:
建造者模式:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
原型模式:通过复制现有的实例来创建新的对象,而不是通过从头开始创建对象。
外观模式:为子系统中的对象提供一个统一的接口。
桥接模式:使抽象部分和实现部分的可变性独立起来。
组合模式:把对象组合成树形结构来实现复用性。
享元模式:通过共享技术来使对象可以在内存中被高效地复用。
17. Spring 如何保证 Controller 并发的安全?
Spring 框架中的 Controller 对象默认是单例的,这意味着在高并发环境下,多个请求可能会同时访问同一个 Controller 实例,从而导致线程安全问题。为了保证 Controller 的并发安全,可以采取以下几种策略:
在 Controller 中尽量不要定义非静态成员变量,因为这些变量会被所有请求共享,容易引发线程不安全性问题。
可以使用 Spring 提供的 @ReentrantLock 注解来实现对 Controller 方法的并发控制。这个注解会在方法级别上创建一个可重入锁,用于控制并发访问。
在 Spring 配置文件中声明 Controller 的 scope 为 “prototype”,这样每次请求都会创建一个新的 Controller 实例,避免了共享实例变量的问题。
当需要共享数据时,优先考虑使用线程安全的数据结构,如
ConcurrentHashMap
、CopyOnWriteArrayList
等,以避免数据不一致的问题。
在多用户环境中,可以使用乐观锁等机制来确保数据的一致性和完整性。乐观锁通过版本号或时间戳来防止冲突,并且支持多个客户端同时读取和更新数据。
线程池是一种重要的并发控制机制,它可以减少线程的创建和销毁,提高系统的抗压能力。
使用 Java 的并发工具,如 synchronized 关键字、ReentrantLock 锁、Semaphore 信号量等,来控制并发访问资源。
通过以上几种方法,可以有效地提高 Spring Controller 的并发安全性,确保在高并发环境下数据的一致性和系统的稳定性。
18. 在 Spring中如何注入一个java集合?
在Spring中注入一个Java集合的方法主要有两种:使用注解和通过XML配置。
使用注解:
可以使用@Autowired注解来自动装配集合类型的Bean。例如,如果你有一个需要注入List、Set或Map的类,可以这样写:
@Autowired
private List<String> list;
@Autowired
private Set<String> set;
@Autowired
private Map<String, String> map;
当有多个相同类型的Bean时,可以结合使用@Qualifier注解来指定具体的Bean。例如:
@Autowired
@Qualifier("specificBean")
private List<String> list;
@Autowired
@Qualifier("specificBean")
private Set<String> set;
@Autowired
@Qualifier("specificBean")
private Map<String, String> map;
这种方式确保了注入的是特定的Bean实例。
通过XML配置:
在Spring的配置文件(如applicationContext.xml )中,可以通过标签来配置集合类型的Bean。Spring提供了四种主要的集合配置标签:
<list>
:用于注入可重复的List值。
<set>
:用于注入不重复的Set值。
<map>
:用于注入键值对的Map。
<props>
:用于注入键值对的Properties对象。
示例配置如下:
<bean id="listBean" class="java.util.ArrayList ">
<value>value1</value>
<value>value2</value>
</bean>
<bean id="setBean" class="java.util.HashSet ">
<value>value1</value>
<value>value2</value>
</bean>
<bean id="mapBean" class="java.util.HashMap ">
<entry key="key1" value="value1"/>
<entry key="key2" value="value2"/>
</bean>
<bean id="propsBean" class="java.util.Properties ">
<entry key="key1" value="value1"/>
<entry key="key2" value="value2"/>
</bean>
在需要使用这些集合的类中,通过@Autowired注解来注入相应的Bean:
@Autowired
private List<String> listBean;
@Autowired
private Set<String> setBean;
@Autowired
private Map<String, String> mapBean;
@Autowired
private Properties propsBean;
这两种方法各有优缺点,选择哪种方式取决于具体的应用场景和开发习惯。使用注解的方式更加简洁直观,适合快速开发;而通过XML配置的方式则提供了更多的灵活性和可维护性
19. Spring支持的事务管理类型?
Spring支持两种主要的事务管理类型:编程式事务管理和声明式事务管理。
编程式事务管理:
这种方式通过代码显式地控制事务的开始、提交和回滚。开发者需要在代码中调用beginTransaction()、commit()和rollback()等方法来管理事务。
编程式事务管理具有较高的灵活性,但其侵入性强,容易导致业务逻辑与事务管理代码混合在一起,难以维护。
声明式事务管理:
声明式事务管理基于AOP(面向切面编程),将事务处理部分从具体业务代码中解耦出来。开发者只需通过注解(如@Transactional)或XML配置来定义事务规则,而具体的事务操作由Spring AOP自动处理。
声明式事务管理的优点是代码侵入性低,业务代码更加简洁,适合大多数实际开发场景。
20. Spring框架的事务管理有哪些优点?
Spring框架的事务管理具有许多优点,这些优点使得它成为企业级应用开发中首选的事务管理方案之一。以下是Spring框架事务管理的一些主要优点:
-
声明式事务管理:Spring提供了简单的方式来声明事务,通过使用注解或XML配置,可以将事务逻辑从业务逻辑中分离出来,使得代码更加清晰和可维护。这种方式对应用代码的影响最小,符合无侵入的轻量级容器的思想。
-
编程式事务管理:除了声明式事务管理,Spring还提供了编程式事务管理,为开发者提供了一套简单的API而不是复杂的事务API。这使得开发者可以更灵活地控制事务行为。
-
统一的编程模型:Spring为不同的事务API(如JTA、JDBC、Hibernate、JPA和JDO)提供了一个不变的编程模式,这大大简化了跨不同事务API的编程工作。
-
异常处理和回滚:Spring事务管理提供了统一的异常处理机制,在事务发生异常时进行回滚操作,避免了数据损坏。这种机制确保了在事务完成前提交的所有更改都能正确地保存到数据库中。
-
多数据源支持:Spring框架能够很好地与各种数据访问抽象层集成,支持多数据源的事务管理。
-
灵活的事务传播行为:Spring允许开发者根据需要对具体的方法或者类进行细粒度的事务控制,实现灵活的事务传播行为。
-
性能优化:Spring事务管理使用缓存和批处理等技术来优化性能,提高系统的响应速度。
-
与Spring数据访问抽象层的集成:Spring事务管理与Spring的各种数据访问抽象层(如JPA、Hibernate等)有很好的集成性,进一步简化了开发工作。
21. Spring MVC的主要组件?
Spring MVC的主要组件包括以下几部分:
-
DispatcherServlet:前端控制器,是整个Spring MVC框架的入口。它负责接收请求并将其分发到相应的处理器(Controller)。
-
HandlerMapping:处理器映射器,负责将传入的请求URL和HTTP方法映射到具体的Controller上。
-
Controller:处理请求的控制器类,用于执行具体的业务逻辑,并返回ModelAndView对象。
-
ModelAndView:封装数据和视图信息的对象,由Controller创建并返回给DispatcherServlet。
-
ViewResolver:视图解析器,负责解析ModelAndView中的视图名称,将其转换为实际的View对象。
这些组件协同工作,共同完成Web应用中请求的处理流程。DispatcherServlet作为前端控制器,接收所有进入系统的请求;HandlerMapping根据请求的URL和HTTP方法找到对应的Controller;Controller处理业务逻辑并返回一个ModelAndView对象;最后,ViewResolver解析视图名称并渲染最终的视图输出.
缩减版:
- 前端控制器 DispatcherServlet
- 处理器映射器HandlerMapping
- 处理器适配器HandlerAdapter
- 处理器Handler
- 视图解析器 ViewResolver
- 视图View
22. SpringMvc怎么和AJAX相互调用的?
Spring MVC和AJAX可以相互调用,实现异步数据交互。具体步骤如下:
首先需要在项目中引入Jackson库,因为我们需要将Java对象转换为JSON格式的数据。
在配置文件中配置JSON的消息转换器,以确保Spring MVC能够处理JSON格式的数据。
在Spring MVC的控制器中定义一个处理AJAX请求的方法,并使用@ResponseBody注解将方法返回值转化为JSON格式。例如:
@Controller
public class AjaxController {
@RequestMapping("/getData")
@ResponseBody
public List用户() {
return 用户列表;
}
}
前端页面通过AJAX发送请求到Spring MVC控制器定义的方法。可以使用jQuery或原生JavaScript进行AJAX请求的发送。例如,使用jQuery发送AJAX请求:
$(document).ready(function() {
$("#submit").click(function() {
$.ajax({
url: "/getData",
type: "GET",
success: function(data) {
// 处理返回的数据
console.log (data);
}
});
});
});
Spring MVC控制器接收到AJAX请求后,处理请求并返回JSON数据。前端接收到数据后,可以将数据更新到页面上,实现无刷新的交互效果。
如果涉及到跨域请求,需要在服务器端设置CORS(跨域资源共享)策略,允许特定的域名访问服务器资源。
23. Mybatis 中#和$的区别?
在MyBatis中,#和$符号用于动态SQL的参数传递,它们之间有显著的区别:
-
预编译与字符串替换:
#
符号(即${}
)会将传入的数据作为字符串处理,并且会对数据进行预编译。这意味着它会将SQL中的#占位符替换成问号?,然后通过PreparedStatement来赋值。$
符号(即#{}
)则直接将传入的数据插入到SQL语句中,不进行任何预编译处理,使用的是Statement对象。
-
安全性:
- 使用
#
符号可以有效防止SQL注入,因为它是通过PreparedStatement进行预编译的,这能够确保SQL语句的安全性。 - 使用
$
符号时,由于是直接将值拼接到SQL语句中,存在SQL注入的风险,因此在安全性上不如#
符号。
- 使用
-
使用场景:
#
符号适用于大多数情况,特别是需要防止SQL注入的场景。例如,在动态指定表名或列名时,推荐使用#符号。$
符号适用于一些特殊场景,比如需要进行复杂的SQL语句拼接时,但必须注意其潜在的安全风险。
-
性能差异:
#
符号由于是预编译的,通常比$
符号的执行效率更高,因为它避免了每次执行前都重新解析和编译SQL语句的开销。- 相对来说,
$
符号由于每次执行前都需要重新拼接SQL语句并编译,因此在性能上可能稍逊一筹。
缩减版:
#{}
是预编译处理,${}是字符串替换。- Mybatis在处理
#{}
时,会将sql中的#{}
替换为?号,调用PreparedStatement的set方法来赋值; - Mybatis在处理时 , 就 是 把
{}
时,就是把时,就是把{}替换成变量的值,相当于字符串拼接; - 使用
#{}
可以有效的防止SQL注入,提高系统安全性。
24. mybatis的缓存机制,一级,二级介绍一下?
MyBatis的缓存机制分为一级缓存和二级缓存,两者在作用范围、配置方式和使用场景上有所不同。
一级缓存
一级缓存也称为本地缓存或SqlSession级别的缓存。它主要用于同一个SqlSession内的数据共享。当一个SqlSession对象执行了某个查询操作后,查询结果会被存储在该SqlSession的内部缓存中。如果再次执行相同的查询操作,MyBatis会优先从缓存中获取数据,而不是直接访问数据库。
一级缓存的实现是基于HashMap的本地缓存,其生命周期与SqlSession相同。当SqlSession被冲刷(flush)或者关闭(close)时,所有的缓存数据都会被清空。因此,一级缓存适用于频繁查询相同数据的场景,可以显著提高性能并减少数据库交互次数。
二级缓存
二级缓存又称为表级缓存或Application级别的缓存。它不仅限于单个SqlSession,而是跨多个SqlSession共享同一个缓存。二级缓存的作用范围更大,通常基于namespace进行管理,即同一个namespace下的所有select查询结果都会被缓存起来。
开启二级缓存需要手动配置,并且通过CachingExecutor来装饰Executor,在进入一级缓存的查询流程前先在CachingExecutor中进行二级缓存的查询。当某个namespace下有update或delete语句被执行时,该namespace下的缓存会被清空。
二级缓存的优势在于能够提高跨SqlSession的数据访问效率,尤其在分布式系统中,可以利用第三方缓存如Redis来存储缓存数据,从而进一步提升性能。然而,二级缓存也存在一些问题,比如缓存穿透、缓存击穿等,需要根据具体应用场景进行优化和处理。
一级缓存主要用于单个SqlSession内的数据共享,而二级缓存则提供了跨SqlSession的数据共享能力,两者结合使用可以有效提升MyBatis的性能和数据访问效率。
25. springMVC与Struts2的区别?
Spring MVC和Struts2都是流行的Java Web框架,但它们在设计、实现机制、性能和开发效率等方面存在显著区别。
- 请求入口:
Spring MVC的请求入口是DispatcherServlet,所有请求通过该servlet进行分发和处理。
Struts2的请求入口是FilterDispatcher,每次请求都会创建一个新的Action实例。 - 拦截器实现机制:
Spring MVC基于方法的拦截,每个请求对应一个方法,这个方法同时与一个URL对应,因此可以更容易实现RESTful URL。
Struts2基于类的拦截,每次请求都会实例化一个新的Action类,每个Action类对应一个request上下文。 - 配置方式:
Spring MVC实现了零配置,通过注解和XML配置文件较少,开发效率较高。
Struts2需要更多的配置文件,如interceptor链条、值栈等,学习成本较高。 - 性能:
经过专业人员的大量测试,Struts2的处理速度要比Spring MVC慢,因为每次请求都会实例化一个新的Action。
Spring MVC由于其单例模式的设计,在性能上稍微优于Struts2。 - 架构设计:
Spring MVC支持单例开发模式,控制器(Controller)作为单例被加载一次并共享给所有请求。
Struts2由于每次请求都会实例化一个新的Action,无法使用单例模式,只能使用多例。 - 表单处理功能:
Spring MVC提供了丰富的表单处理功能,包括数据绑定、表单验证、表单重复提交等。
Struts2的表单处理功能相对简单,需要使用第三方插件进行补充。 - 学习难度:
Spring MVC的学习曲线较为平缓,开发者可以在较短时间内上手。
Struts2由于涉及更多的技术点(如拦截器、值栈及OGNL表达式),学习成本较高。
26. mybatis的基本工作流程?
MyBatis的基本工作流程可以分为以下几个步骤:
首先,MyBatis会读取配置文件(如mybatis-config.xml ),该文件包含了数据库连接信息、SQL映射文件路径等。这些配置信息是后续操作的基础。
根据配置文件中的信息,MyBatis会加载并解析SQL映射文件或注解,并初始化相应的对象。然后,通过SqlSessionFactoryBuilder构建SqlSessionFactory对象。这个对象负责生成SqlSession对象。
SqlSessionFactory对象会创建一个SqlSession对象,用于与数据库进行交互。每次请求都会创建一个新的SqlSession对象,直到应用程序结束。
在SqlSession中,可以通过反射机制获取Mapper接口的代理对象。这样,开发者就可以通过Mapper接口调用增删改查的方法来执行SQL语句。
开发者通过Mapper接口调用相应的增删改查方法,MyBatis会将这些方法转换为具体的SQL语句,并通过SqlSession执行这些SQL语句。执行结果会被封装成Java对象返回给调用者。
如果在执行SQL语句的过程中涉及到事务管理,MyBatis会在适当的时候提交事务。默认情况下,MyBatis会在每次调用commit()方法时提交事务。
缩减版:
- 创建SqlSessionFactory
- 通过SqlSessionFactory创建SqlSession
- 通过SqlSession执行数据库操作
- 调用session.commit()提交事务
- 调用session.close()关闭事务
27. 什么是MyBatis的接口绑定,有什么好处?
MyBatis的接口绑定是指在MyBatis中定义一个接口,并将该接口中的方法与SQL语句进行绑定,从而通过调用接口的方法来执行相应的数据库操作。这种方式相较于传统的通过SqlSession提供的方法,具有更加灵活的选择和设置。
接口绑定的主要好处包括:
-
简化开发 :开发者只需要定义一个接口并声明对数据库的操作方法,MyBatis会动态生成实现类,自动执行SQL语句,无需手动编写SQL或SQL映射文件。
-
提高可维护性:由于接口与SQL语句是分离的,当需要修改SQL时,只需修改mapper.xml 文件中的SQL语句,而不需要修改代码,这样可以避免直接在代码中嵌入SQL语句带来的维护问题。
-
增强代码的可读性和清晰度:通过接口绑定,SQL语句被封装在单独的配置文件中,使得代码更加简洁明了,易于理解和维护。
-
支持多种实现方式:接口绑定可以通过注解和XML两种方式进行实现。注解方式是在接口的方法上使用@Select、@Update等注解来定义具体的SQL语句;XML方式则是在mapper.xml 文件中编写SQL语句,并通过配置将接口与对应的SQL语句绑定。
28. MyBatis的编程步骤?
MyBatis的编程步骤可以分为以下几个主要阶段:
- 配置数据源和MyBatis环境:
创建数据库和表,例如使用Navicat创建数据库和用户表。
在项目的pom.xml 文件中添加MySQL-connector-java和MyBatis依赖。
配置MyBatis的核心配置文件(SqlMapConfig.xml ),包括数据源、事务管理器等。
- 编写SQL映射文件或注解:
编写Mapper XML文件,定义SQL语句与Java对象之间的映射关系。
或者通过注解的方式在实体类和接口方法上直接指定SQL语句。
- 定义Mapper接口:
创建Mapper接口,该接口通常继承自BaseMapper接口,并且需要与SQL映射文件中的namespace一致。
定义接口中的方法,这些方法将对应SQL映射文件中的SQL语句。
- 创建实体类:
创建POJO(Plain Old Java Object)类,用于表示数据库中的记录。
- 编写业务逻辑:
实现Mapper接口,编写具体的业务逻辑代码来执行数据库操作。
使用SqlSession对象执行SQL操作,如增删改查等。
- 测试程序:
编写测试类,验证Mapper接口和业务逻辑是否正常工作。
29. JDBC编程有哪些不足之处,MyBatis是如何解决这些问题的?
JDBC编程存在以下不足之处:
-
频繁创建和释放数据库连接:在JDBC编程中,每次执行SQL语句时都需要手动创建和关闭数据库连接。这种频繁的操作会导致系统资源的浪费,从而影响系统性能。
-
SQL语句写在代码中:将SQL语句直接写在Java代码中,使得代码难以维护和管理。当数据库结构发生变化时,需要修改代码中的SQL语句,这增加了维护成本。
-
对结果集解析存在硬编码:JDBC对结果集的解析依赖于硬编码的列名,当SQL语句中的列名变化时,需要手动调整代码,这同样增加了系统的维护难度。
MyBatis通过以下方式解决了上述问题:
-
使用数据库连接池:MyBatis允许在配置文件(如SqlMapConfig.xml )中配置数据库连接池,这样可以有效管理数据库连接,避免频繁地创建和释放连接,从而提高系统性能。
-
分离SQL语句与Java代码:MyBatis将SQL语句从Java代码中分离出来,存储在XML配置文件或注解中。这样不仅提高了代码的可维护性,还使得SQL语句更加集中和易于管理。
-
自动映射结果集:MyBatis能够自动将SQL执行结果映射到Java对象,消除了手动解析结果集的需求,并且避免了因列名变化而需要修改代码的问题。
-
简化开发流程:MyBatis通过封装JDBC操作,减少了冗余的JDBC代码,使开发者可以更专注于业务逻辑的实现。同时,它支持各种数据库和ORM字段关系映射,进一步降低了学习成本
。
30. MyBatis的优缺点?
MyBatis是一个流行的Java持久层框架,它在开发中提供了许多优点和一些缺点。以下是详细的分析:
优点
- 灵活性高:MyBatis允许开发者直接编写SQL语句,可以更灵活地控制SQL语句的执行,便于优化和调整。
- 减少代码量:与JDBC相比,MyBatis减少了50%以上的代码量,简化了数据库访问操作。
- 简单易学:MyBatis框架小巧且简单,易于学习和使用。
- SQL与程序代码分离:SQL写在XML文件中,解除了SQL与程序代码的耦合,便于统一管理和维护。
- 强大的映射功能:MyBatis支持多种映射方式,可以将Java对象和SQL语句进行映射,使得开发人员可以更加便捷地访问数据库。
- 性能优秀:MyBatis比一些全自动ORM框架具有更好的性能,特别是在需要频繁访问数据库的情况下。
缺点
- SQL语句编写工作量大:尤其是当字段多、关联表多时,SQL语句的编写工作量较大,对开发人员的SQL功底有一定要求。
- 维护成本高:由于需要手动编写SQL语句和映射文件,因此维护成本较高。
- 易引起SQL注入问题:如果使用了恶意构造的数据(如参数是用户控制的),很容易导致SQL注入问题的发生。
- 数据库移植性差:SQL语句依赖于特定的数据库,不能随意更换数据库,这可能限制了系统的可移植性。
- 调试困难:MyBatis不像JDBC那样可以用断点的方式调试,需要通过日志输出信息来帮助调试。
总结
MyBatis的优点在于其灵活性、减少代码量、简单易学以及强大的映射功能,使其成为许多开发者的选择。然而,它也存在一些缺点,如SQL语句编写工作量大、维护成本高、易引起SQL注入问题以及数据库移植性差等。选择是否使用MyBatis取决于项目的具体需求和开发团队的实际情况。