- 1 Maven 项目管理工具有什么优缺点?
- 2 在使用 Maven 管理项目时,常见的标签有什么?
- 3 请列举 Maven 的私服仓库?
- 4 Spring 的主要有哪些模块,各个模块主要提供了什么服务支持?
- 5 请简单叙述你对 Spring AOP 面向切面编程的理解?
- 6 BeanFactory 和 ApplicationContext 有什么区别?
- 7 Spring 是如何管理 bean 的生命周期的?
- 8 请说明目前常用的 Sring Boot 相比 Spring MVC 有什么优缺点?
- 9 MyBatis 的存在主要是为了解决什么问题,有什么优点?
- 10 MyBatis与Hibernate有哪些不同?
- 11 在使用 Mybatis 插件写 SQL 时,#{}和${}的区别是什么?
- 下面举一个简单的sql注入问题:
- 12 MyBatis 动态 SQL 的执行原理是什么?
- 13 怎样配置 MyBatis 的二级缓存?
1 Maven 项目管理工具有什么优缺点?
优点:
- 简化了项目依赖管理:
- 易于上手,对于新手可能一个”mvn clean package”命令就可能满足他的工作
- 便于与持续集成工具(jenkins)整合
- 便于项目升级,无论是项目本身升级还是项目使用的依赖升级。
- 有助于多模块项目的开发,一个模块开发好后,发布到仓库,依赖该模块时可以直接从仓库更新,而不用自己去编译。
- maven有很多插件,便于功能扩展,比如生产站点,自动发布版本等
缺点:
- maven是一个庞大的构建系统,学习难度大
- maven采用约定优于配置的策略(convention over configuration),虽然上手容易,但是一旦出了问题,难于调试。
- 当依赖很多时,m2eclipse 老是搞得Eclipse很卡。
- 中国的网络环境差,很多repository无法访问,比如google code, jboss 仓库无法访问等
2 在使用 Maven 管理项目时,常见的标签有什么?
3 请列举 Maven 的私服仓库?
http://maven.aliyun.com/nexus/content/groups/public
4 Spring 的主要有哪些模块,各个模块主要提供了什么服务支持?

- Spring Core: Core封装包是框架的最基础部分,提供IOC和依赖注入特性。这里的基础概念是BeanFactory,它提供对Factory模式的经典实现来消除对程序性单例模式的需要,并真正地允许你从程序逻辑中分离出依赖关系和配置。
2.Spring Context: 构建于Core封装包基础上的 Context封装包,提供了一种框架式的对象访问方法,有些象JNDI注册器。Context封装包的特性得自于Beans封装包,并添加了对国际化(I18N)的支持(例如资源绑定),事件传播,资源装载的方式和Context的透明创建,比如说通过Servlet容器。
3.Spring DAO: DAO (Data Access Object)提供了JDBC的抽象层,它可消除冗长的JDBC编码和解析数据库厂商特有的错误代码。 并且,JDBC封装包还提供了一种比编程性更好的声明性事务管理方法,不仅仅是实现了特定接口,而且对所有的POJOs(plain old Java objects)都适用。
4.Spring ORM: ORM 封装包提供了常用的“对象/关系”映射APIs的集成层。 其中包括JPA、JDO、Hibernate 和 iBatis 。利用ORM封装包,可以混合使用所有Spring提供的特性进行“对象/关系”映射,如前边提到的简单声明性事务管理。
5.Spring AOP: Spring的 AOP 封装包提供了符合AOP Alliance规范的面向方面的编程实现,让你可以定义,例如方法拦截器(method-interceptors)和切点(pointcuts),从逻辑上讲,从而减弱代码的功能耦合,清晰的被分离开。而且,利用source-level的元数据功能,还可以将各种行为信息合并到你的代码中。
6.Spring Web: Spring中的 Web 包提供了基础的针对Web开发的集成特性,例如多方文件上传,利用Servlet listeners进行IOC容器初始化和针对Web的ApplicationContext。当与WebWork或Struts一起使用Spring时,这个包使Spring可与其他框架结合。
7.Spring Web MVC: Spring中的MVC封装包提供了Web应用的Model-View-Controller(MVC)实现。Spring的MVC框架并不是仅仅提供一种传统的实现,它提供了一种清晰的分离模型,在领域模型代码和Web Form之间。并且,还可以借助Spring框架的其他特性。
5 请简单叙述你对 Spring AOP 面向切面编程的理解?
- 横向编程思想。
- 通过Aspect表明的注解类,给由spring管理的bean中方法提供操作。
- 用@Aspect注解方式来实现前置通知、返回通知、后置通知、异常通知、环绕通知
6 BeanFactory 和 ApplicationContext 有什么区别?
BeanFactory 是spring的原始接口,针对原始结构的实现类功能比较单一,BeanFactory接口实现的容器,特点是在每次获取对象时才会创建对象。
ApplicationContext 继承了BeanFactory接口,拥有BeanFactory的全部功能,并且扩展了很多高级特性,每次容器启动时就会创建所有的对象。
7 Spring 是如何管理 bean 的生命周期的?

Bean的生命周期可以表达为:Bean的实例化(定义)- Bean的初始化 - Bean的使用 - Bean的销毁
1、实例化一个Bean--也就是我们常说的new;
2、按照Spring上下文对实例化的Bean进行配置(属性注入)--也就是IOC注入;
3、如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String)方法,此处传递的就是Spring配置文件中Bean的id值;
4、如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory(setBeanFactory(BeanFactory)传递的是Spring工厂自身(可以用这个方式来获取其它Bean,只需在Spring配置文件中配置一个普通的Bean就可以);
5、如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文(同样这个方式也可以实现步骤4的内容,但比4更好,因为ApplicationContext是BeanFactory的子接口,有更多的实现方法);
6、如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor经常被用作是Bean内容的更改,并且由于这个是在Bean初始化结束时调用那个的方法,也可以被应用于内存或缓存技术;
7、如果Bean在Spring配置文件中配置了init-method属性会自动调用其配置的初始化方法;
8、如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法、;
注:以上工作完成以后就可以应用这个Bean了,那这个Bean是一个Singleton的,所以一般情况下我们调用同一个id的Bean会是在内容地址相同的实例,当然在Spring配置文件中也可以配置非Singleton;
9、当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用那个其实现的destroy()方法;
10、最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。
Bean是一个被实例化,组装,并通过Spring IOC容器(BeanFactory和ApplicationContext容器)所管理的对象。
Spring支持五个作用域,分别是singleton、prototype、request、session、global session
[
](https://blog.csdn.net/qq_37109975/article/details/88718925)
8 请说明目前常用的 Sring Boot 相比 Spring MVC 有什么优缺点?
SpringMVC
(1)Spring MVC是Spring提供的一个强大而灵活的模块式web框架。通过Dispatcher Servlet, ModelAndView 和 View Resolver,开发web应用变得很容易。
(2)SpringMVC是一种基于Java的以请求为驱动类型的轻量级Web框架,其目的是将Web层进行解耦,即使用“请求-响应”模型,从工程结构上实现良好的分层,区分职责,简化Web开发。借助于注解,Spring MVC提供了几乎是POJO的开发模式,使得控制器的开发和测试更加简单。这些控制器一般不直接处理请求,而是将其委托给Spring上下文中的其他bean,通过Spring的依赖注入功能,这些bean被注入到控制器中。
(3)Spring框架最核心的就是所谓的依赖注射和控制反转。完全解耦类之间的依赖关系,一个类如果要依赖什么,那就是一个接口。至于如何实现这个接口,这都不重要了。只要拿到一个实现了这个接口的类,就可以轻松的通过xml配置文件把实现类注射到调用接口的那个类里。所有类之间的这种依赖关系就完全通过配置文件的方式替代了。
SpringMVC的优点:
(1)使用简单,学习成本低。
(2)很容易就可以写出性能优秀的程序.
(3)灵活性强,Spring MVC的框架易扩展
SpringMVC的缺点:
(1)Spring与MVC 的Servlet API 耦合,难以脱离容器独立运行
(2)太过于细分,开发效率低
(3)过度追求完美,有过度设计的危险解决的问题领域是:网站应用程序或者服务开发——URL路由、Session、模板引擎、静态Web资源等等。
Spring Boot引入自动配置的概念,让项目设置变得很容易。Spring Boot本身并不提供Spring框架的核心特性以及扩展功能,只是用于快速、敏捷地开发新一代基于Spring框架的应用程序。也就是说,它并不是用来替代Spring的解决方案,而是和Spring框架紧密结合用于提升Spring开发者体验的工具。同时它集成了大量常用的第三方库配置(例如Jackson, JDBC, Mongo, Redis, Mail等等),Spring Boot应用中这些第三方库几乎可以零配置的开箱即用(out-of-the-box),大部分的Spring Boot应用都只需要非常少量的配置代码,开发者能够更加专注于业务逻辑。Spring Boot只是承载者,辅助开发者简化项目搭建过程的。如果承载的是WEB项目,使用Spring MVC作为MVC框架,那么工作流程和SpringMVC的是完全一样的,因为这部分工作是Spring MVC做的而不是Spring Boot。
9 MyBatis 的存在主要是为了解决什么问题,有什么优点?
Mybatis是一个半自动的ORM持久层框架,内部封装了JDBC。作为开发者只需要关注sql语句本身。Mybatis是通过xml或注解的方式将需要执行的各种statement配置起来。通过Java对象和statement中的sql动态参数映射生成最终执行的sql语句,最终由Mabtais框架执行sql并将结果映射为Java对象并返回。MyBatis 支持定制化 SQL、存储过程以及高级映射。MyBatis 是可以双向映射的,可以将数据集映射为Java对象,也可以将Java对象映射为数据库中的记录。
优点:
简单易学,容易上手(相比于Hibernate) 基于SQL编程;
JDBC相比,减少了50%以上的代码量,消除了JDBC大量冗余的代码,不需要手动开关连接;
能够与Spring很好的集成;
提供XML标签,支持编写动态SQL语句。
提供映射标签,支持对象与数据库的ORM字段关系映射。
提供对象关系映射标签,支持对象关系组建维护。
10 MyBatis与Hibernate有哪些不同?
1)sql 优化方面
Hibernate 不需要编写大量的 SQL,就可以完全映射,提供了日志、缓存、级联(级联比 MyBatis 强大)等特性,此外还提供HQL(Hibernate Query Language)对 POJO 进行操作。但会多消耗性能。
MyBatis 手动编写 SQL,支持动态 SQL、处理列表、动态生成表名、支持存储过程。工作量相对大些。(优化工作比较方便)
2)开发方面
MyBatis 是一个半自动映射的框架(半自动ROM),因为 MyBatis 需要手动匹配 POJO、SQL 和映射关系。(Mybatis 需要写sql,并配置对象之间的关系)
Hibernate 是一个全表映射的框架(全自动ROM),只需提供 POJO 和映射关系即可。(Hibernate 不需要写sql, 就可以完成数据库的操作,虽然支持写sql的方式,但是一般都不写。通过java代码操作对象,框架自动封装成sql语句之后在执行,并且是跨数据库的)
3) Hibernate 优势
Hibernate 的 DAO 层开发比 MyBatis 简单,Mybatis 需要维护 SQL 和结果映射。
Hibernate 对对象的维护和缓存要比 MyBatis 好,对增删改查的对象的维护要方便。
Hibernate 数据库移植性很好,MyBatis 的数据库移植性不好,不同的数据库需要写不同 SQL。
Hibernate 有更好的二级缓存机制,可以使用第三方缓存。MyBatis 本身提供的缓存机制不佳。
4)Mybatis优势
MyBatis 可以进行更为细致的 SQL 优化,可以减少查询字段。
MyBatis 容易掌握,而 Hibernate 门槛较高。
总的来说,MyBatis 是一个小巧、方便、高效、简单、直接、半自动化的持久层框架。Hibernate 是一个强大、方便、高效、复杂、间接、全自动化的持久层框架。所以对于性能要求不太苛刻的系统,比如管理系统、ERP 等推荐使用 Hibernate,而对于性能要求高、响应快、灵活的系统则推荐使用 MyBatis。
11 在使用 Mybatis 插件写 SQL 时,#{}和${}的区别是什么?
1.#{}是预编译处理,是占位符,${}是字符串替换,是拼接符
2.Mybatis在处理#{}的时候会将sql中的#{}替换成?号,调用PreparedStatement来赋值
如:select * from user where name = #{userName};设userName=yuze看日志我们可以看到解析时将#{userName}替换成了 ?select * from user where name = ?;然后再把yuze放进去,外面加上单引号
3.Mybatis在处理${}的时候就是把${}替换成变量的值,调用Statement来赋值
如:select * from user where name = #{userName};设userName=yuze看日志可以发现就是直接把值拼接上去了select * from user where name = yuze;这极有可能发生sql注入,下面举了一个简单的sql注入案例
4.#{}的变量替换是在DBMS中、变量替换后,#{}对应的变量自动加上单引号
5.${}的变量替换是在DBMS外、变量替换后,${}对应的变量不会加上单引号
6.使用#{}可以有效的防止sql注入,提高系统的安全性
下面举一个简单的sql注入问题:
这是一条用户的账号、密码数据
当用户登录,我们验证账号密码是否正确时用这个sql:
username=yyy;password=123
select * from user where username=${username} and password=${password}
显然这条sql没问题可以查出来,但是如果有人不知道密码但是想登录账号怎么办
我们不需要填写正确的密码:
密码输入1 or 1=1,sql执行的其实是
select * from user where username='yyy' and password=1 or 1 =1
注意:这里的yyy外面的单引号不是${}符号提供的。${}没有这个功能,可以是sql手动拼接的,这里前后逻辑可能并不严密,但是sql注入最简单的例子就是这样。
12 MyBatis 动态 SQL 的执行原理是什么?
mybatis可以通过两种方式实现动态SQL,通过XML配置SQL,也可以使用注解的方式配置。两种不同的方式,执行的逻辑都不一样。
通过XML配置实现动态SQL
构建SqlSessionFactory对象时,解析mapper.xml文件,XMLStatementBuilder.parseStatementNode()根据不同的SQL标签()生成对应的MappedStatement对象,存放在Configuration.mappedStatements集合中。
然后遍历主标签里所有节点生成对应的SQL子节点对象(SqlNode)。XMLScriptBuilder.parseScriptNode()解析每个标签生成SqlNode对象。public SqlSource parseScriptNode() {List<SqlNode> contents = parseDynamicTags(context); //context 当前遍历到的sql标签MixedSqlNode rootSqlNode = new MixedSqlNode(contents);SqlSource sqlSource = null;if (isDynamic) {sqlSource = new DynamicSqlSource(configuration, rootSqlNode);} else {sqlSource = new RawSqlSource(configuration, rootSqlNode, parameterType);}return sqlSource;}
执行Executor.query()方法,根据keyStatementId获取到对应的MappedStatement对象,获取BoundSql对象时。遍历当前SqlSource.rootSqlNode对象。执行SqlNode.apply()方法。把动态sql拼接到DynamicContext.sqlBuilder字段中。
@Overridepublic BoundSql getBoundSql(Object parameterObject) {DynamicContext context = new DynamicContext(configuration, parameterObject);rootSqlNode.apply(context);SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());BoundSql boundSql = sqlSource.getBoundSql(parameterObject);for (Map.Entry<String, Object> entry : context.getBindings().entrySet()) {boundSql.setAdditionalParameter(entry.getKey(), entry.getValue());}return boundSql;}
使用sqlSourceParser.parse()方法替换sql中 ${}, #{} 为 ?,并且把大括号中的值存放在
ParameterMappingTokenHandler.parameterMappings集合中。//SqlSourceParser.parse()public SqlSource parse(String originalSql, Class<?> parameterType, Map<String, Object> additionalParameters) {ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler(configuration, parameterType, additionalParameters);GenericTokenParser parser = new GenericTokenParser("#{", "}", handler);String sql = parser.parse(originalSql);return new StaticSqlSource(configuration, sql, handler.getParameterMappings());}//TokenHandler.handleToken(content)@Overridepublic String handleToken(String content) {parameterMappings.add(buildParameterMapping(content));return "?";}
- 通过注解实现动态SQL
注解实现动态SQL不同的地方在于或许主标签的方式不一样。XML动态SQL可以直接解析等标签的节点。注解需要通过MapperAnnotationBuilder.getSqlSourceFromAnnotations(Method method, Class<?> parameterType, LanguageDriver languageDriver)方法获取SQL语句。然后在执行XMLScriptBuilder.parseScriptNode()解析每个标签生成SqlNode对象。private SqlSource getSqlSourceFromAnnotations(Method method, Class<?> parameterType, LanguageDriver languageDriver) {try {Class<? extends Annotation> sqlAnnotationType = getSqlAnnotationType(method);Class<? extends Annotation> sqlProviderAnnotationType = getSqlProviderAnnotationType(method);if (sqlAnnotationType != null) {if (sqlProviderAnnotationType != null) {throw new BindingException("You cannot supply both a static SQL and SqlProvider to method named " + method.getName());}Annotation sqlAnnotation = method.getAnnotation(sqlAnnotationType);final String[] strings = (String[]) sqlAnnotation.getClass().getMethod("value").invoke(sqlAnnotation);return buildSqlSourceFromStrings(strings, parameterType, languageDriver);} else if (sqlProviderAnnotationType != null) {Annotation sqlProviderAnnotation = method.getAnnotation(sqlProviderAnnotationType);return new ProviderSqlSource(assistant.getConfiguration(), sqlProviderAnnotation, type, method);}return null;} catch (Exception e) {throw new BuilderException("Could not find value method on SQL annotation. Cause: " + e, e);}}
13 怎样配置 MyBatis 的二级缓存?
mybatis 的缓存机制有两级:
(1)一级缓存:一级缓存mybatsi已近为我们自动开启,不用我们手动操作,而且我们是关闭不了的!!但是我们可以手动清除缓存。(SqlSession级别)
(2)二级缓存:二级缓存需要我们手动开启。(全局级别)
注:缓存说白了就是查询时可以去历史记录找一找,不用去数据库中查询(不用执行查询语句)。
1.配置文件配置二级缓存(两步):
<settings><!--(1):开启二级缓存,这个全局的配置二级缓存默认是开启的,但是还是需要写上,防止版本的更新--><setting name="cacheEnabled" value="true"/></settings>
2.在具体需要二级缓存的mapeer映射文件中开启二级缓存,值需要在相应的映射文件中添加一个cache标签即可
(2):在相应的映射文件中开启二级缓存<!-- 开启二级缓存 --><cache></cache>
2.注解开启二级缓存(两步):
1.在setting.xml(mybaits配置文件)中
<settings><!--默认是开启的,防止版本更新--><setting name="cacheEnabled" value="true"/></settings>
2.在dao中开启二级缓存
在类名上配置 注解:
@CacheNamespace(blocking = true)
