1、Mybatis 1.1 概念 MyBatis 是一个持久层框架,实现了对JDBC操作的封装,主要用于简化JDBC操作中的一些相对繁琐的步骤,例如参数的映射,结果集的映射等。可以简单快速地连接和操作数据库,同时把操作数据库的结果集封装为Java对象返回
1.2 Mybatis优点 Mybatis的优点: (1)Mybatis对JDBC进行封装,在实际开发中不用花费时间和精力去处理对数据库连接等的处理; (2)Mybatis自身支持连接池,也可以配置其他的连接池,如c3p0、druid,提高了程序的效率; (3)Mybatis是将SQL配置在mapper.xml文件中,当需求发生变更时只修改xml配置文件就可以了,类不需要重新编译。 (4)执行SQL后返回的ResultSet结果对象,Mybatis会帮我们处理,转换成Java对象,方便我们对结果的处理。
1.3 Mybatis架构
(1)sqlMapConfig.xml是Mybatis的核心配置文件,通过其中的配置可以生成SqlSessionFactory,也就是SqlSession工厂 (2)基于SqlSessionFactory可以生成SqlSession对象 (3)SqlSession是一个既可以发送SQL去执行,并返回结果,类似于JDBC中的Connection对象,也是Mybatis中至关重要的一个对象。 (4)Executor是SqlSession底层的对象,用于执行SQL语句 (5)MapperStatement对象也是SqlSession底层的对象,用于接收输入映射(SQL语句中的参数),以及做输出映射(即将SQL查询的结果映射成相应的结果)
1.4 底层原理 1、工作原理图
工作原理解析 mybatis应用程序通过SqlSessionFactoryBuilder从mybatis-config.xml配置文件(也可以用Java文件配置(注解)的方式,需要添加@Configuration)中构建出SqlSessionFactory(SqlSessionFactory是线程安全的); 然后,SqlSessionFactory的实例直接开启一个SqlSession,再通过SqlSession实例获得Mapper对象并运行Mapper映射的SQL语句,完成对数据库的CRUD和事务提交,之后关闭SqlSession。 说明:SqlSession是单线程对象,因为它是非线程安全的,是持久化操作的独享对象,类似jdbc中的Connection,底层就封装了jdbc连接。
详细流程如下 1、加载mybatis全局配置文件(数据源、mapper映射文件等),解析配置文件,MyBatis基于XML配置文件生成Configuration,和一个个MappedStatement(包括了参数映射配置、动态SQL语句、结果映射配置),其对应着<select | update | delete | insert>标签项。 2、SqlSessionFactoryBuilder通过Configuration对象生成SqlSessionFactory,用来开启SqlSession。 3、SqlSession对象完成和数据库的交互: a、用户程序调用mybatis接口层api(即Mapper接口中的方法) b、SqlSession通过调用api的Statement ID找到对应的MappedStatement对象 c、通过Executor(负责动态SQL的生成和查询缓存的维护)将MappedStatement对象进行解析,sql参数转化、动态sql拼接,生成jdbc Statement对象 d、JDBC执行sql。 e、借助MappedStatement中的结果映射关系,将返回结果转化成HashMap、JavaBean等存储结构并返回。
mybatis层次图:
1.5 Mybatis缓存 Mybatis的一级缓存是SqlSession级别。第一次执行select时候会发现sqlsession缓存没有记录,会去数据库查找,然后把结果保存到缓存,第二次同等条件查询下,就会从缓存中查找到结果。另外为了避免脏读,每次执行更新新增删除时候会清空当前sqlsession缓存。 二级缓存是namespace级别的。同一个namespace下的搜寻语句共享一个二级缓存。如果开启了二级缓存,则先从二级缓存中查找,查找不到则委托为SimpleExecutor查找,而它则会先从一级缓存中查找,查找不到则从数据库查找。 mybaits的二级缓存一般不怎么使用,默认一级缓存是开启的。
1.6 常见面试题 1、什么是Mybatis? (1)Mybatis是一个半ORM(对象关系映射)框架,它内部封装了JDBC,开发时只需要关注SQL语句本身,不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。程序员直接编写原生态sql,可以严格控制sql执行性能,灵活度高。 (2)MyBatis 可以使用 XML 或注解来配置和映射原生信息,将 POJO映射成数据库中的记录,避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。
(3)通过xml 文件或注解的方式将要执行的各种 statement 配置起来,并通过java对象和 statement中sql的动态参数进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射为java对象并返回。(从执行sql到返回result的过程)。
2、Mybaits的优点: (1)基于SQL语句编程,相当灵活,不会对应用程序或者数据库的现有设计造成任何影响,SQL写在XML里,解除sql与程序代码的耦合,便于统一管理;提供XML标签,支持编写动态SQL语句,并可重用。 (2)与JDBC相比,减少了50%以上的代码量,消除了JDBC大量冗余的代码,不需要手动开关连接; (3)很好的与各种数据库兼容(因为MyBatis使用JDBC来连接数据库,所以只要JDBC支持的数据库MyBatis都支持)。 (4)能够与Spring很好的集成; (5)提供映射标签,支持对象与数据库的ORM字段关系映射;提供对象关系映射标签,支持对象关系组件维护。
3、MyBatis框架的缺点: (1)SQL语句的编写工作量较大,尤其当字段多、关联表多时,对开发人员编写SQL语句的功底有一定要求。 (2)SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。
4、MyBatis框架适用场合: (1)MyBatis专注于SQL本身,是一个足够灵活的DAO层解决方案。 (2)对性能的要求很高,或者需求变化较多的项目,如互联网项目,MyBatis将是不错的选择。
5、MyBatis与Hibernate有哪些不同? (1)Mybatis和hibernate不同,它不完全是一个ORM框架,因为MyBatis需要程序员自己编写Sql语句。 (2)Mybatis直接编写原生态sql,可以严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,因为这类软件需求变化频繁,一但需求变化要求迅速输出成果。但是灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件,则需要自定义多套sql映射文件,工作量大。 (3)Hibernate对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件,如果用hibernate开发可以节省很多代码,提高效率。
6、#{}和${}的区别是什么?
Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值; Mybatis在处理${}时,就是把${}替换成变量的值。 使用#{}可以有效的防止SQL注入,提高系统安全性。
7、当实体类中的属性名和表中的字段名不一样怎么办 ?
第1种: 通过在查询的sql语句中定义字段名的别名,让字段名的别名和实体类的属性名一致。
第2种: 通过
8、模糊查询like语句该怎么写? SQL语句中的like模糊查询 select * from table where name like‘%张%’, 但实际开发中经常用到 select * from table where name like concat('%',#{name},'%')
9、通常一个Xml映射文件,都会写一个Dao接口与之对应,请问,这个Dao接口的工作原理是什么?Dao接口里的方法,参数不同时,方法能重载吗? Dao接口即Mapper接口。接口的全限名,就是映射文件中的namespace的值;接口的方法名,就是映射文件中Mapper的Statement的id值;接口方法内的参数,就是传递给sql的参数。 Mapper接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为key值,可唯一定位一个MapperStatement。在Mybatis中,每一个
(2)第二种: 使用 @param 注解: public interface usermapper { user selectuser(@param(“username”) string username,@param(“hashedpassword”) string hashedpassword); } 然后,就可以在xml像下面这样使用(推荐封装为一个map,作为单个参数传递给mapper):
(3)第三种:多个参数封装成map try{ //映射文件的命名空间.SQL片段的ID,就可以调用对应的映射文件中的SQL //由于我们的参数超过了两个,而方法中只有一个Object参数收集,因此我们使用Map集合来装载我们的参数 Map<String, Object> map = new HashMap(); map.put("start", start); map.put("end", end); return sqlSession.selectList("StudentID.pagination", map); }catch(Exception e){ e.printStackTrace(); sqlSession.rollback(); throw e; } finally{ MybatisUtil.closeSqlSession(); }
15、Mybatis动态sql有什么用?执行原理?有哪些动态sql?
Mybatis动态sql可以在Xml映射文件内,以标签的形式编写动态sql,执行原理是根据表达式的值完成逻辑判断并动态拼接sql的功能。
Mybatis提供了9种动态sql标签:trim | where | set | foreach | if | choose | when | otherwise | bind。
16、Xml映射文件中,除了常见的select|insert|updae|delete标签之外,还有哪些标签?
答:
20、MyBatis实现一对一有几种方式?具体怎么操作的? 有联合查询和嵌套查询,联合查询是几个表联合查询,只查询一次,通过在resultMap里面配置association节点配置一对一的类就可以完成; 嵌套查询是先查一个表,根据这个表里面的结果的 外键id,去再另外一个表里面查询数据,也是通过association配置,但另外一个表的查询通过select属性配置。
22、Mybatis是否支持延迟加载?如果支持,它的实现原理是什么? 答:Mybatis仅支持association关联对象和collection关联集合对象的延迟加载,association指的就是一对一,collection指的就是一对多查询。在Mybatis配置文件中,可以配置是否启用延迟加载lazyLoadingEnabled=true|false。 它的原理是,使用CGLIB创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用a.getB().getName(),拦截器invoke()方法发现a.getB()是null值,那么就会单独发送事先保存好的查询关联B对象的sql,把B查询上来,然后调用a.setB(b),于是a的对象b属性就有值了,接着完成a.getB().getName()方法的调用。这就是延迟加载的基本原理。 不光是Mybatis,几乎所有的包括Hibernate,支持延迟加载的原理都是一样的。
23、Mybatis的一级、二级缓存:
一级缓存: 基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该 Session 中的所有 Cache 就将清空,默认打开一级缓存。
二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap 存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。默认不打开二级缓存,要开启二级缓存,使用二级缓存属性类需要实现Serializable序列化接口(可用来保存对象的状态),可在它的映射文件中配置
24、什么是MyBatis的接口绑定?有哪些实现方式? 接口绑定,就是在MyBatis中任意定义接口,然后把接口里面的方法和SQL语句绑定, 我们直接调用接口方法就可以,这样比起原来了SqlSession提供的方法我们可以有更加灵活的选择和设置。 接口绑定有两种实现方式,一种是通过注解绑定,就是在接口的方法上面加上 @Select、@Update等注解,里面包含Sql语句来绑定;另外一种就是通过xml里面写SQL来绑定, 在这种情况下,要指定xml映射文件里面的namespace必须为接口的全路径名。当Sql语句比较简单时候,用注解绑定, 当SQL语句比较复杂时候,用xml绑定,一般用xml绑定的比较多。
25、使用MyBatis的mapper接口调用时有哪些要求? ①Mapper接口方法名和mapper.xml中定义的每个sql的id相同; ②apper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同; ③Mapper.xml文件中的namespace即是mapper接口的类路径。
27、简述Mybatis的插件运行原理,以及如何编写一个插件。 答:Mybatis仅可以编写针对ParameterHandler、ResultSetHandler、StatementHandler、Executor这4种接口的插件,Mybatis使用JDK的动态代理,为需要拦截的接口生成代理对象以实现接口方法拦截功能,每当执行这4种接口对象的方法时,就会进入拦截方法,具体就是InvocationHandler的invoke()方法,当然,只会拦截那些你指定需要拦截的方法。 编写插件:实现Mybatis的Interceptor接口并复写intercept()方法,然后在给插件编写注解,指定要拦截哪一个接口的哪些方法即可,记住,别忘了在配置文件中配置你编写的插件。
2、Spring 2.1 概念 1、Spring是一个开源的轻量级的应用开发框架,其目的是用于简化企业级应用程序开发,降低开发者的开发难度; 2、Spring提供的IoC和AOP应用,可以将组件的耦合度降至最低(即解耦),便于系统日后的维护和升级; 3、Spring为系统提供了一个整体的解决方案,开发者可以利用它本身提供的功能外,也可以与第三方框架和技术整合应用,可以自由选择采用哪种技术进行开发。(比如Spring整合SpringMVC、Spring整合MyBatis、Spring整合Struts2、Spring整合Hibernate、Spring整合Quartz[定时任务处理])
2.2 Spring优点 1).方便解耦,简化开发 通过Spring提供的IoC容器,可以将对象之间的依赖关系交由Spring进行控制,避免硬编码所造成的过度程序耦合。 2).AOP编程的支持 通过Spring提供的AOP功能,方便进行面向切面的编程,如性能监测、事务管理、日志记录等。 3).声明式事务的支持 4).方便集成各种优秀框架 5).降低Java EE API的使用难度,如对JDBC,JavaMail,远程调用等提供了简便封装
2.3 Spring架构 Spring 最初的目标就是要整合一切优秀资源,然后对外提供一个统一的服务。Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式,如下图所示:
1. 核心容器Spring Core核心容器,提供Spring框架的基本功能。核心容器的主要组件是BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转(IOC)模式,将应用程序的配置和依赖性规范与实际的应用程序代码分开。 2.Spring Context Spring 上下文,是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。 3.Spring AOP通过配置管理特性,Spring AOP 模块直接将面向切面的编程功能集成到了 Spring 框架中。可以很容易地使 Spring框架管理的任何对象支持AOP。Spring AOP模块为基于Spring 的应用程序中的对象提供了事务管理服务。通过使用Spring AOP,就可以将声明性事务管理集成到应用程序中。 4. Spring DAO JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。 5.Spring ORM Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括JDO、Hibernate和iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。 6.Spring Web Web上下文模块建立在应用程序上下文模块之上,为基于Web 的应用程序提供了上下文。所以Spring 框架支持与Jakarta Struts的集成。Web模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。 7.Spring MVC框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。
2.4 控制反转(IOC) 控制反转,就是指将对象的创建,对象的存储(map),对象的管理(依赖查找,依赖注入)交给了spring容器。(spring容器是spring中的一个核心模块,用于管理对象) 只需要将类提前配置在spring配置文件中,就可以将对象的创建交给spring容器,当需要对象时,不需要自己创建,而是直接通过spring获取即可,省去了new对象,可以降低代码之间的耦合性。 IOC如何实例化对象?
2.5 DI依赖注入 依赖注入,即组件之间的依赖关系由容器在应用系统运行期来决定,也就是由容器动态地将某种依赖关系的目标对象实例注入到应用系统中的各个关联的组件之中。 简单来说,所谓的依赖注入其实就是,在创建对象的同时或之后,如何给对象的属性赋值。 set方式注入: 1、创建User类,声明name和age属性,并添加对应的setter和getter方法,以及toString方法 2、在applicationContext.xml中声明User类的bean实例 3、修改applicationContext.xml中User实例的声明,为User实例注入属性(或者在applicationContext.xml中,将UserInfo对象作为值,赋值给User对象的userInfo属性)
构造方法注入: 1、为User类声明构造函数 2、修改applicationContext.xml文件,将set方式修改为构造方法注入。
2.6 底层原理(常见面试题) 1、什么是 Spring 框架?Spring 框架有哪些主要模块? Spring框架是一个为 Java 应用程序的开发提供了综合、广泛的基础性支持的 Java 平台。Spring帮助开发者解决了开发中基础性的问题,使得开发人员可以专注于应用程序的开发。Spring 框架本身亦是按照设计模式精心打造,这使得我们可以在开发环境中安心的集成 Spring框架,不必担心Spring 是如何在后台进行工作的。 Spring 框架至今已集成了 20 多个模块。这些模块主要被分如下图所示的核心容器、数据访问/集成,、Web、AOP(面向切面编程)、工具、消息和测试模块。
3、使用 Spring 框架能带来哪些好处? 下面列举了一些使用 Spring 框架带来的主要好处: 1、Dependency Injection(DI) 方法使得构造器和 JavaBean properties 文件中的依赖关系一目了然。 2、与 EJB 容器相比较,IOC 容器更加趋向于轻量级。这样一来 IOC 容器在有限的内存和 CPU资源的情况下进行应用程序的开发和发布就变得十分有利。 3、Spring 并没有闭门造车,Spring 利用了已有的技术比如 ORM 框架、logging 框架、J2EE、 Quartz 和 JDK Timer,以及其他视图技术。 4、Spring 框架是按照模块的形式来组织的。由包和类的编号就可以看出其所属的模块,开发者仅仅需要选用他们需要的模块即可。 5、要测试一项用 Spring 开发的应用程序十分简单,因为测试相关的环境代码都已经囊括在框架中了。更加简单的是,利用 JavaBean 形式的 POJO 类,可以很方便的利用依赖注入来写入测试数据。 6、Spring 的 Web 框架亦是一个精心设计的 Web MVC 框架,为开发者们在 web 框架的选择上提供了一个除了主流框架比如 Struts、过度设计的、不流行 web 框架的以外的有力选项。 7、Spring 提供了一个便捷的事务管理接口,适用于小型的本地事务处理(比如在单 DB 的环境下)和复杂的共同事务处理(比如利用 JTA 的复杂 DB 环境)。
4、请解释下 Spring 框架中的 IOC? Spring 中的 org.springframework.beans 包和 org.springframework.context 包构成了 Spring 框架 IOC 容器的基础。BeanFactory 接口提供了一个先进的配置机制,使得任何类型的对象的配置成为可能。 ApplicationContex 接口对 BeanFactory(是一个子接口)进行了扩展,在 BeanFactory 的基础上添加了其他功能,比如与 Spring 的 AOP 更容易集成,也提供了处理 message resource的机制(用于国际化)、事件传播以及应用层的特别配置,比如针对 Web 应用的 WebApplicationContext。
5、BeanFactory 和 ApplicationContext 有什么区别? BeanFactory 可以理解为含有 bean 集合的工厂类。BeanFactory 包含了种 bean 的定义,以便在接收到客户端请求时将对应的 bean 实例化。BeanFactory 还能在实例化对象时生成协作类之间的关系。此举将 bean 自身与 bean 客户端的配置中解放出来。BeanFactory 还包含了 bean 生命周期的控制,调用客户端的初始化方法(initialization methods)和销毁方法(destruction methods)。从表面上看,application context 如同 bean factory 一样具有 bean 定义、bean 关联关系的设置,根据请求分发 bean 的功能。但 application context 在此基础上还提供了其他的功能。 1.提供了支持国际化的文本消息 2.统一的资源文件读取方式 3.已在监听器中注册的 bean 的事件 以下是三种较常见的 ApplicationContext 实现方式: 1、ClassPathXmlApplicationContext:从 classpath 的 XML 配置文件中读取上下文,并生成上下文定义。应用程序上下文从程序环境变量中取得。 ApplicationContext context = new ClassPathXmlApplicationContext(“application.xml”); 2、FileSystemXmlApplicationContext :由文件系统中的 XML 配置文件读取上下文。 ApplicationContext context = new FileSystemXmlApplicationContext(“application.xml”); 3、XmlWebApplicationContext:由 Web 应用的 XML 文件读取上下文。
6、Spring 提供几种配置方式来设置元数据? 将 Spring 配置到应用开发中有以下三种方式: 1.基于 XML 的配置 2.基于注解的配置 3.基于 Java 的配置
7、如何使用 XML 配置的方式配置 Spring?
在 Spring 框架中,依赖和服务需要在专门的配置文件来实现,常用 XML 格式的配置文件。这些配置文件的格式通常用开头,然后一系列的 bean 定义和专门的应用配置选项组成。SpringXML配置的主要目的时候是使所有的Spring组件都可以用xml文件的形式来进行配置。这意味着不会出现其他的 Spring 配置类型(比如声明的方式或基于 Java Class 的配置方式)Spring 的 XML 配置方式是使用被 Spring 命名空间的所支持的一系列的 XML 标签来实现的。
Spring 有以下主要的命名空间:context、beans、jdbc、tx、aop、mvc 和 aso。
8、如何用基于 Java 配置的方式配置 Spring? Spring 对 Java 配置的支持是由@Configuration 注解和@Bean 注解来实现的。由@Bean注解的方法将会实例化、配置和初始化一个新对象,这个对象将由 Spring 的 IOC 容器来管理。@Bean 声明所起到的作用与 元素类似。被@Configuration 所注解的类则表示这个类的主要目的是作为 bean 定义的资源。被@Configuration 声明的类可以通过在同一个类的内部调用@bean 方法来设置嵌入 bean 的依赖关系。
9、怎样用注解的方式配置 Spring?
Spring 在 2.5 版本以后开始支持用注解的方式来配置依赖注入。可以用注解的方式来替代 XML方式的 bean 描述,可以将 bean 描述转移到组件类的内部,只需要在相关类上、方法上或者字段声明上使用注解即可。注解注入将会被容器在 XML 注入之前被处理,所以后者会覆盖掉前者对于同一个属性的处理结果。
注解装配在 Spring 中是默认关闭的。所以需要在 Spring 文件中配置一下才能使用基于注解的装配模式。如果你想要在你的应用程序中使用关于注解的方法的话,请参考如下的配置。
10、请解释 Spring Bean 的生命周期?
Spring Bean 的生命周期简单易懂。在一个 bean 实例被初始化时,需要执行一系列的初始化操作以达到可用的状态。同样的,当一个 bean 不在被调用时需要进行相关的析构操作,并从 bean容器中移除。Spring bean factory 负责管理在 spring 容器中被创建的 bean 的生命周期。Bean 的生命周期由两组回调(call back)方法组成。
1.初始化之后调用的回调方法。
2.销毁之前调用的回调方法。
Spring 框架提供了以下四种方式来管理 bean 的生命周期事件:
1、InitializingBean 和 DisposableBean 回调接口
2、针对特殊行为的其他 Aware 接口
3、Bean 配置文件中的 Custom init()方法和 destroy()方法
4、@PostConstruct 和@PreDestroy 注解方式
使用 customInit()和 customDestroy()方法管理 bean 生命周期的代码样例如下:
11、Spring Bean 作用域之间的区别? Spring 容器中的 bean 可以分为 5 个范围。所有范围的名称都是自说明的,但是为了避免混淆, 还是让我们来解释一下: 1.singleton:这种 bean 范围是默认的,这种范围确保不管接受到多少个请求,每个容器中只有一个 bean 的实例,单例的模式由 bean factory 自身来维护。 2.prototype:原形范围与单例范围相反,为每一个 bean 请求提供一个实例。 3.request:在请求 bean 范围内会每一个来自客户端的网络请求创建一个实例,在请求完成以后,bean 会失效并被垃圾回收器回收。 4.Session:与请求范围类似,确保每个 session 中有一个 bean 的实例,在 session 过期后,bean 会随之失效。 5.global-session:global-session 和 Portlet 应用相关。当你的应用部署在 Portlet 容器中工作时,它包含很多 portlet。如果你想要声明让所有的 portlet 共用全局的存储变量的话,那么这全局变量需要存储在 global-session 中。全局作用域与 Servlet 中的 session 作用域效果相同。
12、什么是 Spring inner beans? 在 Spring 框架中,无论何时 bean 被使用时,当仅被调用了一个属性。一个明智的做法是将这个 bean 声明为内部 bean。内部 bean 可以用 setter 注入“属性”和构造方法注入“构造参数”的方式来实现。比如,在我们的应用程序中,一个 Customer 类引用了一个 Person 类,我们的要做的是创建一个 Person 的实例,然后在 Customer 内部使用。 public class Customer{ private Person person; } public class Person{ private String name; private String address; private int age; //Setters and Getters } 内部 bean 的声明方式如下:
13、Spring 框架中的单例 Beans 是线程安全的么? Spring 框架并没有对单例 bean 进行任何多线程的封装处理。关于单例 bean 的线程安全和并发问题需要开发者自行去搞定。但实际上,大部分的 Spring bean 并没有可变的状态(比如Serview类和DAO类),所以在某种程度上说Spring的单例bean是线程安全的。如果你的bean有多种状态的话(比如 View Model 对象),就需要自行保证线程安全。 最浅显的解决办法就是将多态 bean 的作用域由“singleton”变更为“prototype”。
14、请举例说明如何在 Spring 中注入一个 Java 集合?
Spring 提供了以下四种集合类的配置元素:
1、该标签用来装配可重复的 list 值。
2、该标签用来装配没有重复的 set 值。
3、该标签可用来注入键和值可以为任何类型的键值对。
4、该标签支持注入键和值都是字符串类型的键值对。
下面看一下具体的例子:
15、如何向 Spring Bean 中注入 java.util.Properties? 第一种方法是使用如下面代码所示的 标签:
也可用”util:”命名空间来从 properties 文件中创建出一个 propertiesbean,然后利用 setter方法注入 bean 的引用。
16、请解释 Spring Bean 的自动装配? 在 Spring 框架中,在配置文件中设定 bean 的依赖关系是一个很好的机制,Spring 容器还可以自动装配合作关系 bean 之间的关联关系。这意味着 Spring 可以通过向 Bean Factory 中注入的方式自动搞定 bean 之间的依赖关系。自动装配可以设置在每个 bean 上,也可以设定在特定的 bean 上。 下面的 XML 配置文件表明了如何根据名称将一个 bean 设置为自动装配:
17、请解释各种自动装配模式的区别? 在 Spring 框架中共有 5 种自动装配,让我们逐一分析。 1.no:这是 Spring 框架的默认设置,在该设置下自动装配是关闭的,开发者需要自行在 bean定义中用标签明确的设置依赖关系。 2.byName:该选项可以根据 bean 名称设置依赖关系。当向一个 bean 中自动装配一个属性时,容器将根据 bean 的名称自动在在配置文件中查询一个匹配的 bean。如果找到的话,就装配这个属性,如果没找到的话就报错。 3.byType:该选项可以根据 bean 类型设置依赖关系。当向一个 bean 中自动装配一个属性时,容器将根据 bean 的类型自动在在配置文件中查询一个匹配的 bean。如果找到的话,就装配这个属性,如果没找到的话就报错。 4.constructor:造器的自动装配和 byType 模式类似,但是仅仅适用于与有构造器相同参数的bean,如果在容器中没有找到与构造器参数类型一致的 bean,那么将会抛出异常。 5.autodetect:该模式自动探测使用构造器自动装配或者 byType 自动装配。首先,首先会尝试 找合适的带参数的构造器,如果找到的话就是用构造器自动装配,如果在 bean 内部没有找到相 应的构造器或者是无参构造器,容器就会自动选择 byTpe 的自动装配方式。
18、如何开启基于注解的自动装配?
要使用 @Autowired,需要注册 AutowiredAnnotationBeanPostProcessor,可以有以下两
种方式来实现:
1、引入配置文件中的下引入
2、在 bean 配置文件中直接引入 AutowiredAnnotationBeanPostProcessor
19 、自动装配有哪些局限性? 自动装配有如下局限性: 重写:你仍然需要使用 和< property>设置指明依赖,这意味着总要重写自动装配。 原生数据类型:你不能自动装配简单的属性,如原生类型、字符串和类。 模糊特性:自动装配总是没有自定义装配精确,因此,如果可能尽量使用自定义装配。