要定义一个人,首先要对他有一定的了解。你评价别人的准确度取决于你对他人了解的程度。
同样,要区分Spring\Springboot\SpringMVC 首先要做的就是先了解它们。
Spring不用说都知道是另外两个的父类,是一个容器,一个管理bean的容器。特性是DI 、 IOC、AOP。由于DI的特性,注入即代表被spring管理,可以说DI和IOC是密不可分的,否则DI的存在就没意义(交给你管理你却不能帮我创建对象,那为什么要注入给你管理),同样,你公司里都没员工(没给你注入对象),那你IOC管理创建什么对象。所以严格来说spring的特性应该是IOC和AOP。
IOC是一种思想,是Spring帮创建对象,不再需要自己new。凡是实现了DI的都实现控制反转。控制反转的一个重大作用就是实现了解耦,想想看,对象在用时才会被spring创建,不需要原来那种new的方式强行绑定。
AOP也可以说是一种思想,AOP允许你对spring容器里的任何对象方法进行增强。一般我们加功能都是new一个功能类,然后再使用功能类的方法,AOP做的就是这么一件事。但由于IOC的特性,就不需要你再自己new对象,AOP通过IOC能直接使用功能类方法,当然,这都不是AOP的核心。AOP的核心是:“统一配置”,当多个类有相同的功能模块时,AOP的价值就体现出来了。比如 面向所有类的全局异常处理,面向某些类需要实现的日志输出等都可以应用上,当然,如果你只有“一个类”想调用其它功能类方法,准备用AOP实现,那也不是不行,只是“杀鸡用牛刀”,用法有点另类罢了。
DI是辛苦的招聘专员,帮你把相关的对象都招进spring公司,spring公司才能安排对象做事。
spring工作过程是: 注入->实例化对象(使用对象)
DI原始方法是通过set方法注入,当然通过有参构造方法注入也行,和平常给对象赋值的方式一样。但构建有参构造方法会使无参构造方法失效,还要另外配置无参构造才行。
被调用时才通过spring创建对象。而spring创建对象或实例化的方式有3种:默认缺省且最常用的就是通过无参构造函数的方法,另外两种是静态工厂和实例工厂的方式,换个意思就是不通过spring实例化对象了,而是通过自己搞个工厂创建。这两种不太常用,有需要了解的可自行查阅资料。
比如是对象B被注入进对象A,A里有对应B的set方法,底层原理是通过反射获取到B的构造器,再拿到B的对象,然后A才能(通过B对象)调用到B的方法。一旦B中有有参构造器,除非有重写无参构造器,否则原来默认的无参构造将被覆盖失效。在spring框架中,重写有参构造方法时候,注意也多写一个无参构造器,省去后去找bug的麻烦。
Spring原始配置
//set方式注入
public class BookServiceImpl implements BookService {
private BookDao bookDao;//定义接口类型,后面具体接口实现类可通过bean随意配置。
//接口好处:可以传入任何的实现类,没有依赖于任何一个实现类,耦合度降低
//通过set的方式“注入”
public void setBookDao(BookDaoImpl bookDao) {
this.bookDao = bookDao;
}
//通过注入,才能调用到bookDao里面的save()方法
@Override
public void save() {
System.out.println("业务层:调用DAO层");
bookDao.save();//体现了依赖,因为引用类的功能拿到了
}
}
//Spring配置文件配置(resources底下的applicationContext.xml)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- contructor方式注入-->
<bean class="com.itheima.dao.impl.BookDaoImpl" id="bookDaoimpl">
<!--简单类型注入-->
<constructor-arg index="0" value="3"/>
<constructor-arg index="1" value="你好!"/>
</bean>
<!-- set方式注入-->
<bean class="com.itheima.service.impl.BookServiceImpl" id="bookServiceimpl">
<!--依赖绑定-->
<property name="bookDao" ref="bookDaoimpl"/> <!--引用类型注入-->
<property name="参数名" value="字符串"/> <!--简单类型注入-->
</bean>
</beans>
//Spring注入后的使用方法
@Test
public void testSaveBook() {
//1.创建IoC容器对象,加载spring核心配置文件
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// 2 从IOC容器中获取Bean对象(BookService对象)
BookService bookService= (BookService)ctx.getBean("bookService");
// 3 调用Bean对象(BookService对象)的方法
bookService.save();
// 4.关闭容器
ctx.close();
}
DI中的 依赖就是使得bean和bean之间有联系,注入则是它们之间建立联系的方法。
依赖的作用就是使得bean之间能使用到对方的方法。如实现类impl引用映射层mapper的sql执行。
spring经过几个使用阶段:
1.Spring通过applicationContext.xml方式管理bean,这种方式需要自己手动注入bean,非常麻烦不便捷,且一旦类多起来,这种管理方式就显得比较混乱。
2.Spring通过配置注解的方式管理。其中@Configuration代表主配置类,其它的只要加入了@Component@Repository等,spring就能实现自动接管。
spring已经简化了很多工作,但依然要自己另外搞数据库配置,mybatis配置等各种外部引用配置。
为了进一步偷懒,使得固定配置的代码少些,于是后面就有了Springboot。
springboot有一些显著的特征:
1.首先它有一个唯一的启动类。启动类自动配置了tomcat,使得不用再像spring那样要通过tomcat启动。
2.另外,一些参数类的信息,如数据库连接,mybatis配置等,直接写在yml这类的文件里即可,不需要再另外写config引入(当然如过滤器,静态资源放行等还是要的,因为这些是非参数类配置)。
3.springboot因为自动配置了tomcat,所以默认是自动拦截非resources->static路径下的所有请求的,不像springMVC需要另外配置拦截器。
Springboot不是spring的增强版,而是spring的封装简化版。精简了spring的配置,如对各种jar引用的版本号就进行了规范限制,省去了很多jar包冲突的麻烦。网上说“懒人整合包”(starter)就是个生动有趣的描述。核心思想:默认大于配置!
SpringMVC和springboot的联系,就功能层面说,其实可以大概换算成springmvc和spring的联系。当然,springmvc不能脱离spring运行,但springmvc可以脱离springboot运行。springmvc是spring里的一个扳手,没有springmvc的spring web项目当然也能运行。springmvc只是spring为了更好的处理web而诞生的一个框架(不用你手拧螺丝,你可以用扳手拧),代替封装了原始的servlet来处理所有的web事项。springmvc侧重于视图层、web层,而spring则侧重在业务层和持久层。
最后,springboot这个“整理师”又看不惯了,把springmvc和spring整合起来又精简了一遍。
网上说springboot对比springmvc,springboot更注重在后台,我对这话不全认同。结合我上面说的,那应该是spring对比springmvc,spring更注重后台处理才是。而springboot整合了spring和springmvc,有自己的tomcat,也有处理到前台的,只不过因为精简了配置,才使得springboot代码量都集中在了后台上。
三者关系界限无法用言语阐明,我用了我多年的画图功力画了下面这图帮助理解。
如发现错误,欢迎随时找我纠正,感谢!