• 链接 控制反转的必要性详见链接方便理解

优点:Spring是一个轻量级 非入侵式控制反转(IoC)面向切面编程(AOP)的容器框架
非入侵即引入一个新的东西不会让原有的出问题
支持声明式事务
能整合现有的几乎所有的java框架
作用总结:解耦,简化开发
简化开发的具体手段:
1、基于POJO的轻量级和最小侵入性编程,所有东西都是bean;
2、通过IOC,依赖注入(DI)和面向接口实现松耦合;
3、基于切面(AOP)和惯例进行声明式编程;
4、通过切面和模版减少样式代码,RedisTemplate,xxxTemplate;

Spring理念:使现有技术更加容易(比如简化Servlet)。是一个大杂烩,整合了现有的技术框架
最著名的即 SSH(Struct2+Spring+Hibernate)
SSH现在逐渐被SSM(SpringMVC+Spring+Mybatis)淘汰
上面SSH和SSM功能组成部分是上下对应的。如Mybatis取代了Hibernate

Spring三大思想:依赖注入DI 控制反转IOC 面向切面编程AOP
依赖注入是IOC的实现方式
IOC实现方式有很多种,可以XML配置或者注解,最新版spring还可以零配置实现

Spring组成
Spring由七大模块组成。
Spring简介 - 图1
Core:核心
ORM:对象关系映射

Spring家族
Spring+SpringBoot+SpringCloud
三者是逐级提升的。
SpringBoot是为了简化Spring而产生的。因为Spring是个大杂烩,整合了太多的东西。学到后期配置繁琐

IOC理论推导(以下是IOC的原型)

spring-study/spring-ioc-yuanli

首先需要创建一个maven项目
导入spring-webmvc(暂时还不清楚有没有必要)
创建2个包:Dao和Service。还有一个自带的包test(这里是三层架构模式,Dao为数据访问层,Service为业务层,还有一个表示层UI)这里未用到UI层

  1. Dao包:
  2. public interface UserDao {
  3. void getUser();}
  4. public class UserDaoImpl implements UserDao{
  5. public void getUser() {
  6. System.out.println("默认获取用户的数据"); }}
  7. Service包:
  8. public interface UserService {
  9. void getUser();}
  10. public class UserServiceImpl implements UserService {
  11. private UserDao userDao = new UserDaoImpl();
  12. public void getUser() {
  13. userDao.getUser(); }
  14. }
  15. Test:
  16. public class Mytest {
  17. public static void main(String[] args) {
  18. UserServiceImpl userService=new UserServiceImpl();
  19. userService.getUser(); }}
  20. 用户getUser调用的是业务层,dao层不需要接触.但是业务层会自动调用dao层(getUser调用UserDao.getUser
  21. 输出:默认获取用户数据

现在假如UserDao增加其他的需求。比如增加一个UserDaoMysqlImpl implement UserDao 方法为getUser(输出:Mysql获取用户数据)
那么需要改变 UserServiceImpl类里的new ``UserDaoImpl``改为new UserDaoMysql

假如再增加更多的UserDao多态对象,比如private UserDao userDao2=new UserDaoMysqlImpl();
UserServiceImpl的getUser方法里的userDao那里得改为userDao2
反正2种方法都得改原有代码,客户每换一个需求,程序员就得改一次代码。不方便。况且实际中增加的功能多得多

解决方法是
在业务实现层UserServiceImpl里增加一个setUserDao方法,让业务层自动选择需要实现哪个UserDao实现类
UserServiceImpl修改为
public class ``UserServiceImpl ``implements ``UserService {
UserDao ``userDao``;
public void ``setUser``(UserDao userDao){
``this``.``userDao``=userDao``;`` ``} 令实际userDao的类型=传入userDao的类型
``public void ``getUser``() {
``userDao``.getUser()``;`` ``}
}

Test类在getUser前再增加一行
userService.setUser(new UserDao的实现类);
这样就由用户去选择需要的功能,而不是用户改变需求,程序员也得修改原有代码(有点类似工厂模式)控制权从程序员转到了用户。程序由主动创建对象变成了被动的接受对象
即控制反转 控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。

比如用户需要输出:默认获取数据,就**set(new UserDaoImpl())**.需要Mysql获取数据,就**set(new UserDaoMysqlImpl())**。用户需要多个功能,就直接扩展代码:重复一下set和get方法即可。
此set方法即对象注入

这样用户可以专注业务层。dao层就不用再改了

IOC容器

以往各个功能组件之间就像贴合的齿轮,动一个就影响全局。现在IOC容器将各组件贴合处包起来。程序员与用户动某一个组件。其他连接的组件怎么改变由IOC容器去解决,我们不用管

Spring简介 - 图2

Spring容器

Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象

Spring简介 - 图3
采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。

  • spring容器就是一个对象工厂,所有的单例对象都有它创建并管理 ```xml

    应用上下文即ioc容器,拿到ioc容器可以通过getBean方法获取bean以使用

BeanFactory 「老祖宗」接口 #定义了getBean()方法。 └── ApplicationContext 最常用接口 └── AbstractApplicationContext 接口的抽象实现类 ├── ClassPathXmlApplicationContext 具体实现类之一,用于从classpath中加载一个或者多个xml文件构建应用程序的上下文 └── AnnotationConfigApplicationContext 具体实现类之二,用于从配置类/注解的类中读取构建应用程序上 |-——FileSystemXmlApplicationContext 该实现类用于从磁盘路径上加载配置文件以进行配置,配置文件可以在磁盘的任意位置。 ```

SpringAOP原理推导

SpringAOP和SpringMVC是是spring的重中之重,无论哪个厂都是必考。IOC不一定考
springAOP的底层原理为代理模式,见链接
不改变原来的代码的情况下,实现了对原有功能的增强,这是代理模式的运用,也是AOP中最核心的思想
image.png

AOP在spring中就是提供声明式事务,允许用户自定义切面
利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低(即AOP就跟代理模式一样,可以在不改变原有代码的情况下,去增加新的功能)

以下名词需要了解下:

  • 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志 , 安全 , 缓存 , 事务等等 ….
  • 切面(ASPECT):横切关注点 被模块化 的特殊对象。即,它是一个类。
  • 通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。
  • 目标(Target):被通知对象。
  • 代理(Proxy):向目标对象应用通知之后创建的对象。
  • 切入点(PointCut):切面通知 执行的 “地点”的定义。
  • 连接点(JointPoint):与切入点匹配的执行点。

Spring简介 - 图5Spring简介 - 图6
Spring简介 - 图7

上下文

上下文即服务,功能初始化时加载的一些信息,相当于一段代码中的全局变量。上下文信息可以是配置信息,可以是数据源,可以是一个容器等等

面试回答

ioc

  • 控制反转的好处是:
    • 不需要了解对象的构造函数所需哪些参数,我们直接拿来用即可。
    • 解耦,对象的类修改了不影响我们使用该对象的代码,使用代码无需变动