**Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。**这句话很好得诠释了什么是Spring,也给我们提供了学习Spring的一个大致方向,既IoC和AOP。官方文档的介绍也是从IoC开始的。
控制反转(Inversion of Control )是一个容器,控制反转的意思是将对象创建的控制权从业务层反转到展现层,或者说从程序员反转到用户手中。这么讲可能会很抽象,因此可以通过另一个概念来理解,即依赖注入(dependency injection,简称DI)。依赖注入和控制反转是同一个东西的不同角度描述,就是通过引入 IoC 容器,利用依赖注入的方式,实现对象之间的解耦。
这么说其实还是挺抽象,本来想加个例子来说明,但是这样会导致篇幅过于冗余,因此打消了这个念头。推荐B站上秦疆老师的视频以及他的博客,对初学很友好,例子都很通俗易懂。
这张是Spring官方文档上面的图,很清楚地展示了IoC的工作原理。配置元数据告诉IoC容器如何实例化、配置并组装应用程序中的对象,然后由IoC容器自动完成。配置元数据通过一个简单XML文件提供。
XML的基本内容也是在官方的文档中获取,内容如下:
<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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="..." class="...">
bean>
<bean id="..." class="...">
bean>
beans>
在配置一个bean时,需要为其指定一个id,这个id作为bean的名称在IoC是唯一的,class是需要注入的业务层类名。
属性注入要求bean提供一个默认的构造方法(不带参数的构造方法),并为需要注入的属性提供对应的Setter方法。Spring先调用默认构造方法实例化bean对象,然后通过反射的方式调用Setter方法注入属性值。看一个简单的例子。
package com.kai.info;
public class UserInfo {
private String name;
private int age;
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
}
属性注入配置:
<bean id="userInfo" class="com.kai.info.UserInfo">
<property name="name"><value>小王value>property>
<property name="age"><value>18value>property>
bean>
上述代码配置了一个bean,并为bean的3个属性提供了属性值。
构造方法注入是另外一钟常用的注入方式,使用的前提是bean提供带参数的构造方法。看一个简单例子。
package com.kai.info;
public class UserInfo {
private String name;
private int age;
public UserInfo(String name, int age) {
this.name = name;
this.age = age;
}
}
构造方法注入配置有多种方式,如:
通过一个简单例子解释下类型匹配和索引匹配。
<bean id="userInfo" class="com.kai.info.UserInfo">
<constructor-arg type="java.lang.String">
<value>小王value>
constructor-arg>
<constructor-arg type="int">
<value>18value>
constructor-arg>
bean>
<bean id="userInfo" class="com.kai.info.UserInfo">
<constructor-arg index="0" value="小王"/>
<constructor-arg index="1" value="18"/>
bean>
按类型匹配入参意思是通过构造方法中属性的类型来匹配,缺点很明显,当构造方法中有多个相同类型的属性时,按类型匹配就会出现问题。因此可以考虑索引匹配,但是如果出现重载的构造方法时,索引匹配显然也不是好的解决方法。因此两种方法又有其局限性,可以根据具体情况来选择使用,或者使用两者结合的方式匹配。
package com.smart.ditype;
public class CarFactory() {
// 创建Car的工厂方法
public Car createHongQiCar() {
Car car = new Car();
car.setBrad("红旗CA72");
return car;
}
}
工厂类负责创建一个或多个目标类实例(汽车工厂类创建一个红旗汽车实例,也可以创建法拉利、布加迪等其他汽车实例),工厂类对外屏蔽了目标类的实例化步骤。以下的配置片段使用CarFactory为Car提供工厂方法的注入:
<bean id="carFactory" class="com.smart.ditype.carFactory"/>
<bean id="car5" factory-bean="carFactory"
factory-method="createHongQiCar"/>
由于CarFactory工厂类是非静态的,所以首先需要定义一个工厂类的bean,然后通过factory-bean引用工厂类实例,最后通过factory指定对应的工厂类方法。
如果工厂类是静态的,则无需创建工厂类实例。如以下例子。
package com.smart.ditype;
public static class CarFactory() {
}
配置文件:
<bean id="carFactory" class="com.smart.ditype.carFactory" factory-method="createCar"/>
基于使用xml的方式配置bean是Spring2.0之前的特性,这种方式配置的bean因为xml文件过多导致有配置地狱的称号,因此Spring2.0开始引入了基于注解的配置方式。这两天刚好也看到一篇总结的不错的微信推文,因此这边就直接放上链接,不重复叙述。
在刚开始接触Spring时,会看到Sping、SpringMVC、SpringBoot、SpringCloud等概念,一时间总会有点分不清,这里分享我看到的一篇微信推文,我就不复述了,简单说下作者的总结吧。
主要参考材料
Tips:
本人是刚开始学习Sping,如有错误或者不足之处还望不吝赐教,欢迎共同交流学习!