标签:反转 process 版本 encoding 路径 代理 session throw obj
Spring Framework 简称 Spring,是 Java 开发中最常用的框架,地位仅次于 Java API,就连近几年比较流行的微服务框架 SpringBoot,也是基于 Spring 实现的,SpringBoot 的诞生是为了让开发者更方便地使用 Spring,因此 Spring 在 Java 体系中的地位可谓首屈一指。
当然,如果想要把 Spring 所有功能都讲的一清二楚,远远不是一两篇文章能够做到的,但幸运的是,Spring 的基础资料可以很轻易的搜索到,那么我们本讲主要的目的就是把 Spring 中的核心知识点和常见面试题分享给大家,希望对大家能有所帮助。
Spring 是一个开源框架,为了解决企业应用程序开发复杂性而创建的,Spring 的概念诞生于 2002 年,于 2003 年正式发布第一个版本 Spring Framework 0.9。下面一起来看 Spring 各个版本的更新特性和它的发展变化吧。
此版本主要是为了解决企业应用程序开发复杂性而创建的,当时 J2EE 应用的经典架构是分层架构:表现层、业务层、持久层,最流行的组合就是 SSH(Struts、Spring、Hibernate)。
Spring 1.x 仅支持基于 XML 的配置,确保用户代码不依赖 Spring,它主要包含了以下功能模块:aop、beans、ejb、jdbc、jndi、orm、transation、validation、web 等。
Spring 2.x 的改动并不是很大,主要是在 Spring 1.x 的基础上增加了几个新模块,如 ehcache、jms、jmx、scripting、stereotype 等。
Spring 3.x 开始不止支持 XML 的配置,还扩展了基于 Java 类的配置,还增加了 Expression、Instructment、Tomcat、oxm 等组件,同时将原来的 Web 细分为:Portlet、Servlet。
Spring 4.x 扩充了 Groovy、Messaging、WebMvc、Tiles2、WebSocket 等功能组件,同时 Spring 还适配了 Java 版本,全面支持 Java 8.0、Lambda 表达式等。随着 RESTful 架构风格被越来越多的用户所采用,Spring 4.x 也提供了 RestController 等注解新特性。
Spring 5.x 紧跟 Java 相关技术的更新迭代,不断适配 Java 的新版本,同时不断重构优化自身核心框架代码,支持函数式、响应式编程模型等。
Spring 核心包括以下三个方面:
下面分别来看它的这些特性。
控制反转(Inversion of Control,IoC),顾名思义所谓的控制反转就是把创建对象的权利交给框架去控制,而不需要人为地去创建,这样就实现了可插拔式的接口编程,有效地降低代码的耦合度,降低了扩展和维护的成本。
比如,你去某地旅游不再用自己亲自为订购 A 酒店还是 B 酒店而发愁了,只需要把住店的需求告诉给某个托管平台,这个托管平台就会帮你订购一个既便宜又舒适的酒店,而这个帮你订购酒店的行为就可以称之为控制反转。
依赖注入(Dependency Injection,DI),是组件之间依赖关系由容器在运行期决定,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。
IoC 是 Spring 中一个极为重要的概念,而 DI 则是实现 IoC 的方法和手段。
接下来,我们来看依赖注入的常见实现方式有哪些?
依赖注入的常见实现方式如下:
Java 代码:
public class UserController {
// 注入 UserService 对象
private UserService userService;
public void setUserService(UserService userService){
this.userService = userService;
}
}
XML 配置:
\<bean name="userController" class="com.learning.controller.UserController"\>
\<!-- 依赖注入 --\>
\<property name="userService" ref="userService"\>\</property\>
\</bean\>
\<bean name="userService" class="com.learning.dao.impl.UserServiceImpl"\>\</bean\>
Bean 标签的常用属性说明:
Java 代码:
public class UserController {
private UserService userService;
public UserController(UserService userService){
this.userService = userService;
}
}
XML 配置:
\<bean name="userController" class="com.learning.controller.UserController"\>
\<!-- 依赖注入 --\>
\<constructor-arg ref="userService"\>\</constructor-arg\>
\</bean\>
\<bean name="userService" class="com.learning.dao.impl.UserServiceImpl"\>\</bean\>
@Controller
public class UserController {
// 使用注解自动注入
@Autowired()
private UserService userService;
// do something
}
// 创建依赖对象
@Service
public class UserService {
// do something
}
创建依赖对象的常见注解:@Component、@Controller、@Service、@Repository。
总结:可以看出注解的方式要比传统的 XML(setter 和构造器注入)实现注入更为方便,同时注解方式也是官方力推的依赖注入最佳使用方式。
面向切面编程(Aspect Oriented Programming,AOP),它就好比将系统按照功能分类,每一个类别就是一个“切面”,我们再针对不同的切面制定相应的规则,类似开发模式被称为面向切面编程。
AOP 的示例我们就以开车为例,开车的完成流程是这样的:巡视车体及周围情况 → 发动 → 开车 → 熄火 → 锁车。
当然我们的主要目的是“开车”,但在开车之前和开完车之后,我们要做一些其他的工作,这些“其他”的工作,可以理解为 AOP 编程。
package com.learning.aop;
import org.springframework.stereotype.Component;
@Component("person")
public class Person {
public void drive() {
System.out.println("开车");
}
}
package com.learning.aop;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class CarAop {
@Before("execution(\* com.learning.aop.Person.drive())")
public void before() {
System.out.println("巡视车体及周围情况");
System.out.println("发动");
}
@After("execution(\* com.learning.aop.Person.drive())")
public void after() {
System.out.println("熄火");
System.out.println("锁车");
}
}
\<?xml version="1.0" encoding="UTF-8"?\>
\<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"\>
\<context:component-scan base-package="com.learning"/\>
\<aop:aspectj-autoproxy/\>
\</beans\>
package com.learning.aop;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class PersonTest {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
Person landlord = context.getBean("person", Person.class);
landlord.drive();
}
}
运行测试代码,执行结果如下:
巡视车体及周围情况
发动
开车
熄火
锁车
答:基于 @Value 的注解可以读取 properties 配置文件,使用如下:
@Value("#{configProperties[‘jdbc.username‘]}")
private String userName;
以上为读取 configProperties 下的 jdbc.username 配置。
答:Spring 通知类型总共有 5 种:前置通知、环绕通知、后置通知、异常通知、最终通知。
答:Spring IOC 就是把创建对象的权利交给框架去控制,而不需要人为的去创建,这样就实现了可插拔式的接口编程,有效地降低代码的耦合度,降低了扩展和维护的成本。
比如,去某地旅游不再用自己亲自为订购 A 酒店还是 B 酒店而发愁了,只需要把住店的需求告诉给某个托管平台,这个托管平台就会帮你订购一个既便宜又舒适的酒店,而这个帮你订购酒店的行为就可以称之为控制反转。
答:依赖注入是指组件之间的依赖关系由容器在运行期决定,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。
答:IoC 是 Spring 中一个极为重要的概念,提供了对象管理的功能,从而省去了人为创建麻烦,而 DI 正是实现 IoC 的方法和手段。
答:它们的作用对象不同:@Component 作用于类,而 @Bean 注解作用于方法。
@Component 通常是通过类路径扫描来自动侦测和装配对象到 Spring 容器中,比如 @ComponentScan 注解就是定义扫描路径中的类装配到 Spring 的 Bean 容器中;@Bean 注解是告诉 Spring 这是某个类的实例,当我需要用它的时把它给我,@Bean 注解比 @Component 注解自定义性更强,很多地方我们只能通过 @Bean 注解来注册 Bean,比如当我们引用第三方库中的类需要装配到 Spring容器时,则只能通过 @Bean 来实现,比如以下示例,只能通过 @Bean 注解来实现:
public class WireThirdLibClass {
@Bean
public ThirdLibClass getThirdLibClass() {
return new ThirdLibClass();
}
}
答:Spring 中 bean 的作用域有四种类型,如下列表:
Spring 默认的是单例模式。
答:当一个 bean 仅被用作另一个 bean 的属性时,它能被声明为一个内部 bean,为了定义 inner Bean,在 Spring 的基于 XML 的配置元数据中,可以在 <property/>
或 <constructor-arg/>
元素内使用 <bean/>
元素,内部 bean 通常是匿名的,它们的 Scope 一般是 prototype。
答:Spring 的注入方式包含以下五种:
其中最常用的是前三种,官方推荐使用的是注解注入,相对使用更简单,维护成本更低,更直观。
答:在 Spring 中操作数据库,可以使用 Spring 提供的 JdbcTemplate 对象,JdbcTemplate 类提供了很多便利的方法,比如把数据库数据转变成基本数据类型或对象,执行自定义的 SQL 语句,提供了自定义的数据错误处理等,JdbcTemplate 使用示例如下:
@Autowired
private JdbcTemplate jdbcTemplate;
// 新增
@GetMapping("save")
public String save(){
String sql = "INSERT INTO USER (USER\_NAME,PASS\_WORD) VALUES ('laowang','123')";
int rows = jdbcTemplate.update(sql);
return "执行成功,影响" + rows + "行";
}
// 删除
@GetMapping("del")
public String del(int id){
int rows= jdbcTemplate.update("DELETE FROM USER WHERE ID = ?",id);
return "执行成功,影响" + rows + "行";
}
// 查询
@GetMapping("getMapById")
public Map getMapById(Integer id){
String sql = "SELECT \* FROM USER WHERE ID = ?";
Map map= jdbcTemplate.queryForMap(sql,id);
return map;
}
答:Spring 的 JdbcTemplate 是对 JDBC API 的封装,提供更多的功能和更便利的操作,比如 JdbcTemplate 拥有:
答:Spring 实现事务有两种方式:编程式事务和声明式事务。
编程式事务,使用 TransactionTemplate 或 PlatformTransactionManager 实现,示例代码如下:
private final TransactionTemplate transactionTemplate;
public void add(User user) throws Exception{
// Spring编码式事务,回调机制
transactionTemplate.execute(new TransactionCallback<Object>() {
@Override
public Object doInTransaction(TransactionStatus status) {
try {
userMapper.insertSelective(user);
} catch (Exception e) {
// 异常,设置为回滚
status.setRollbackOnly();
throw e;
}
return null;
}
});
}
如果有异常,调用 status.setRollbackOnly() 回滚事务,否则正常执行 doInTransaction() 方法,正常提交事务。
如果事务控制的方法不需要返回值,就可以使用 TransactionCallbackWithoutResult(TransactionCallback 接口的抽象实现类)示例代码如下:
public void add(User user) throws Exception {
// Spring编码式事务,回调机制
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
try {
userMapper.insertSelective(user);
} catch (Exception e) {
// 异常,设置为回滚
status.setRollbackOnly();
throw e;
}
}
});
}
声明式事务,底层是建立在 Spring AOP 的基础上,在方式执行前后进行拦截,并在目标方法开始执行前创建新事务或加入一个已存在事务,最后在目标方法执行完后根据情况提交或者回滚事务。
声明式事务的优点:不需要编程,减少了代码的耦合,在配置文件中配置并在目标方法上添加 @Transactional 注解来实现,示例代码如下:
@Transactional
public void save() {
User user = new User("laowang");
userMapper.insertSelective(user);
if (true) {
throw new RuntimeException("异常");
}
}
抛出异常,事务会自动回滚,如果方法正常执行,则会自动提交事务。
答:Spring 的注入方式包含以下五种:
默认值为 ISOLATION_DEFAULT 遵循数据库的事务隔离级别设置。
答:可能的原因如下:
答:Spring AOP 的底层实现原理就是动态代理。Spring AOP 的动态代理有两种实现方式,对于接口使用的是 JDK 自带的动态代理来实现的,而对比非接口使用的是 CGLib 来实现的,关于动态代理的详细内容,可参考前面【反射和动态代理】的那篇文章。
答:Spring 中的 Bean 默认是单例模式,Spring 框架并没有对单例 Bean 进行多线程的封装处理,因此默认的情况 Bean 并非是安全的,最简单保证 Bean 安全的举措就是设置 Bean 的作用域为 Prototype(原型)模式,这样每次请求都会新建一个 Bean。
答:Spring 中 Bean 的生命周期如下:
以上几个步骤完成后,Bean 就已经被正确创建了,之后就可以使用这个 Bean 了。
答:Spring 优点如下:
答:Spring 和 Struts 区别如下:
Spring 特性如下:
Struts 特性如下:
答:它们的区别如下:
答:Spring 中使用的设计模式如下:
通过本节内容我们充分的了解了 Spring 的核心:IoC、DI、AOP,也是用代码演示了 Spring 核心功能的示例,其中可以发现的是 Spring 正在从之前的 XML 配置编程变为 Java 注解编程,注解编程让 Spring 更加轻量化简单化了,这一点在我们后面介绍 SpringBoot 的时候,会让你更加感同身受。对于开发者来说,只有真正掌握了 Spring,才能称得上是一名合格的 Java 工程师。当然,学习的目的是为了更好的应用,因此现在就一起动手实践起来吧。
欢迎关注我的公众号,回复关键字“Java” ,将会有大礼相送!!! 祝各位面试成功!!!
%97%E5%8F%B7%E4%BA%8C%E7%BB%B4%E7%A0%81.png)
标签:反转 process 版本 encoding 路径 代理 session throw obj
原文地址:https://www.cnblogs.com/dailyprogrammer/p/12272773.html