【Spring】Spring核心与设计思想-创新互联

Spring核心与设计思想

创新互联公司网络公司拥有十年的成都网站开发建设经验,超过千家客户的共同信赖。提供做网站、成都做网站、网站开发、网站定制、卖友情链接、建网站、网站搭建、成都响应式网站建设公司、网页设计师打造企业风格,提供周到的售前咨询和贴心的售后服务文章目录
  • Spring核心与设计思想
    • 什么是框架
    • Ioc容器
      • 汽车示例
    • Spring IoC
    • DI
    • Spring创建和使用
      • 创建Spring项目
      • 将Bean注册到容器
      • 取出Bean对象
      • Application Context 和 BeanFactory

什么是框架

Spring其实就是我们java中的一个框架,不过这是之前流行的框架,现在比较流行的框架是SpringBoot。那什么是框架呢?

🔑框架其实就相当于脚手架,让我们开发起来更方便,比如之前用servlet实现网站的后端,步骤比较繁琐,又是创建目录,又是引入依赖,还需要配置SmartTomcat,也就是除了业务逻辑之外我们需要关注的东西比较多。那框架其实就是为了简化开发的,让我们尽量少关注这些环境问题,我们只需要实现业务逻辑就行了。

Ioc容器

那Spring具体是一个什么样的框架呢?用一句话来总结就是:

🔑Spring是一个包含了众多工具方法的IoC容器。

1️⃣首先包含了众多工具方法:这个好理解,就比如java中的一些工具类,向Arrays,Collections这些集合类,提供了很多方法,方便了我们的开发,Spring也是一样,提供了很多工具方法,有需要的时候直接调用就行了。

2️⃣什么是容器:比如在数据结构中的那些集合类,比如ArrayList,LinkedList,HashMap。这些类就可以称作存储数据的容器;再比如Tomcat是存储webapp的容器。

3️⃣Ioc:Inversion Of Control:控制反转的意思。在Spring中就是把控制权交到Spring手中。这句话并不好理解,下面我们用示例解释说明这句话。

🍎Spring核心功能:Spring是包含了众多工具方法的IoC容器,最核心的功能是容器管理。

汽车示例

比如我们要建造一辆汽车,传统开发思路是:造一辆车,汽车(car)依赖车身,车身(framework)依赖底盘,底盘(bottom)依赖轮胎(tire)。

🔑代码实现:

public class NewCar {public static void main(String[] args) {Car car = new Car();
        car.init();
    }
    static class Car{public void init(){//汽车需要依赖车身
            Framework framework = new Framework();
            framework.init();
        }
    }
    static class Framework{public void init(){//车身需要依赖底盘
            Bottom bottom = new Bottom();
            bottom.init();
        }
    }
    static class Bottom{public void init(){//底盘需要依赖轮胎
            Tire tire = new Tire();
            tire.init();
        }
    }
    static class Tire{private int size = 20;
        public void init(){System.out.println(size);
        }
    }
}

🍎按照传统的开发思路,造汽车需要车身,那就在Car类中的init方法中创建FrameWork,而车身又需要底盘,那就在FrameWork的init方法中创建底盘,造底盘需要轮胎,那就在底盘的init方法中创建轮胎。不过这时候轮胎尺寸是固定的,如果更改了需求,轮胎尺寸由用户自定义,那就需要改动代码:

import java.util.Scanner;

public class NewCar {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);
        int size = scanner.nextInt();
        Car car = new Car();
        car.init(size);
    }
    static class Car{public void init(int size){//汽车需要依赖车身
            Framework framework = new Framework();
            framework.init(size);
        }
    }
    static class Framework{public void init(int size){//车身需要依赖底盘
            Bottom bottom = new Bottom();
            bottom.init(size);
        }
    }
    static class Bottom{public void init(int size){//底盘需要依赖轮胎
            Tire tire = new Tire();
            tire.init(size);
        }
    }
    static class Tire{private int size = 20;
        public void init(int size){this.size = size;
            System.out.println(size);
        }
    }
}

需要从Car到FrameWork再到Bottom再到Tire,把尺寸size一级一级地向下传递。也就是说整个调用链都需要发生改变。那对于复杂的项目,可能调用链更多,那这时候更改了业务需求,需要的改动就会更多。这就叫做代码的耦合度太高。下面改进一下代码,就可以降低耦合度:

import java.util.Scanner;

public class NewCar {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);
        int size = scanner.nextInt();

        Tire tire = new Tire(size);
        Bottom bottom = new Bottom(tire);
        Framework framework = new Framework(bottom);
        Car car = new Car(framework);
    }
    static class Car{private Framework framework = null;
        public Car(Framework framework) {this.framework = framework;
        }
    }
    static class Framework{private Bottom bottom = null;
        public Framework(Bottom bottom){this.bottom = bottom;
        }
    }
    static class Bottom{private Tire tire = null;
        public Bottom(Tire tire) {this.tire = tire;
        }
    }
    static class Tire{private int size = 20;
        public Tire(int size){init(size);
        }
        public void init(int size){this.size = size;
            System.out.println(size);
        }
    }
}

🔑改进的策略是将new实例这部操作提取出来,之前是Car需要Framework,就在Car类中new出Framework实例,Framework需要Bottom就在Framework中new出Bottom实例。现在把new实例提取出来,也就是将控制权交出去。让类和类之间的关联降低,让代码的耦合度降低。

🔑之前的代码是我当前类需要底层类的实例,就在当前类中new底层类的实例,现在是我需要底层类的实例,就给我传一个底层类的实例。我的车身需要底盘,我不自己建造了,我外包给别人建造,建造好之后把底盘给我就行了。这样当再发生需求变更的时候就无需一级一级的修改代码了。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zt7Ytq4d-1669874585317)(https://hao-typora.oss-cn-beijing.aliyuncs.com/img/image-20221121112735320.png)]

🍊改进前:由上级类创建下级类的实例,改进后:将下级类实例传入上级类。下级的控制权不再交给上级。即使下级类发生任何改变,上级都是不受影响的。

🍎控制反转(IoC):控制反转就是控制权反转。比如A类需要B类对象,如果在A类中new出B类实例,那B类控制权就是在A类中。控制权反转就是如果A类对象需要B类对象,B类对象交由Spring来管理,对象的控制权交给Spring了,A类对象需要B类对象就从Spring来获取,Spring相当于是一个第三方。

Spring IoC

Spring是一个包含了众多工具方法的IoC容器,既然是个容器,Spring存储的其实是对象。它具备两个最基本的功能:将对象存入容器和从容器中取出对象。

说Spring是一个IoC容器是因为:对象的创建和销毁的权利都交给Spring来管理了,它本身又具备了存储对象和获取对象的能力。控制权交给了Spring,所以符合IoC的思想。

==将对象存入容器的好处:==将对象存入容器后,以后再需要直接取就行了,而new对象的方式是每次需要都需要工具都现做,用完就丢掉,下次用的时候还得重新做。

DI

DI:Dependency Injection (依赖注入)

所谓依赖注⼊,就是由 IoC 容器在运⾏期间,动态地将某种依赖关系注⼊到对象之中 ,就比如要创建一个Car需要先有一个FrameWork,此时FrameWork就是Car的依赖,创建Car对象的时候需要先把Framework传给Car对象。

Ioc和DI其实是具有相似之处的:Ioc是思想,而DI是这种思想的一种具体实现方式。

Spring创建和使用

Spring创建和使用总共分为三部分:

  1. 创建一个Spring项目
  2. 将Bean注册到容器(Spring中的Bean就是java中的对象)
  3. 获取并使用Bean
创建Spring项目

一:创建一个Spring项目:

总共三个步骤:

1️⃣创建一个Maven项目

2️⃣引入Spring依赖:

org.springframeworkspring-context5.2.3.RELEASEorg.springframeworkspring-beans5.2.3.RELEASE

3️⃣创建启动类(类名自己定)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GuBG3y4r-1669874585318)(https://hao-typora.oss-cn-beijing.aliyuncs.com/img/image-20221121170951814.png)]

将Bean注册到容器

二:将Bean注册到容器

1️⃣先有一个Bean,Bean可以理解为就是java中的对象。但是并不是真的创建出一个对象,然后存到Spring容器中。我们只需要一个类就行了,并不需要真的创建出对象,创建对象是Spring的工作。实际上是向Spring中注册一个类,将来有需要的时候Spring用这个类实例出对象。

image-20221121172355490

2️⃣添加配置文件spring-config.xml(文件名自定义)到resources根目录下

3️⃣注册Bean到容器中

  • 注册Bean到容器中其实是在spring-config.xml配置文件中添加一个标签,标识一个Hello类,class属性是包名+类名,id属性是标识符,可以自定义。id是唯一的,存储的多个Bean的id不能重复
  • 这里的注册Bean到容器中,并没有真正创建对象,因为Spring的创建对象机制是懒汉模式,也就是当你用的时候,也就是取对象的时候才真正创建对象。这里注册只是告诉Spring今后可能会用这个类创建对象,id和class让Spring能找到这个类并创建出对象。
取出Bean对象

从Spring中取出Bean对象:

🍎这个取对象的过程其实就是Spring帮我们创建好了对象,然后把对象的引用交给自己的程序,这里有个关键点就是:注册到Spring中的类的构造方法要么是无参的,要么是有参的且参数是存储于Spring中的对象(这个在构造方法注入中会讲到),不能是自己任写的,如果自己任写一个构造方法,参数是一个String类型,那Spring自然就不知道要给构造方法传什么字符串了,这时候就会报异常。

1️⃣获取Spring上下文对象:因为我们要从Spring中取出Bean,所以必须得先有个Spring上下文对象。构造方法的参数是resources根目录下的配置文件名

2️⃣获取对象:getBean方法的参数是之前在配置文件中存储的Bean的id。

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
    public static void main(String[] args) {
        //获取Spring上下文对象
        ApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("spring-config.xml");
        //获取对象
        Hello hello = (Hello) applicationContext.getBean("hello");
        //使用对象
        hello.sayHi();
    }
}

其中第二步获取对象常用的有三种方式,上面代码中通过id来获取是第一种,

第二种是通过类型来获取:

Hello hello = applicationContext.getBean(Hello.class);
  • 这种方式获取的对象不需要类型强转

不过这种方式有可能会出现bug,因为在Spring中可以对同一个类注册两次:(但是注册两次的id是不能相同的,否则会报错)

✅如果是第一种方式,根据id获取对象,那没有任何问题,但如果是第二种通过类型来获取,就会报错(因为此时在Spring中对同一个类注册了两次,而这两个Bean将会来产生两个对象,这两个对象又属于同一个类),如果这个类只注册了一次,那这两种获取对象的方式都不会报错。

第三种方式:使用id+类名

Hello hello = applicationContext.getBean("hello",Hello.class);

Application Context 和 BeanFactory

除了第二步创建对象有三种方式之外,获取Spring上下文对象还有另外一种方式:

BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("spring-config.xml"));

面试问题:Application Context 和 BeanFactory的区别:

1️⃣Application Context属于BeanFactory的子接口,BeanFactory提供了基础的访问容器的能力,而Application Context还提供了除此之外的其他能力,比如还添加了对国际化⽀持、资源访问⽀持、以及事件传播等⽅⾯的⽀持。

2️⃣ApplicationContext 是⼀次性加载并初始化所有的 Bean 对象,⽽ BeanFactory是需要那个才去加载那个,因此更加轻量。

你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧


网站题目:【Spring】Spring核心与设计思想-创新互联
网页地址:http://azwzsj.com/article/iocsi.html