1. 简介
2002年首次退出Spring的雏形,interface21 框架
2004年4月24日以interface21 为基础发布Spring1.0 正式版
Rod Johnson Spring Framwork创始人,音乐学
Spring理念:使现有技术更加容易使用,本身是一个大杂烩整合了现有的技术框架
SSH:Struct2 + Spring + Hibernate(全自动)
SSM:SpringMVC + Spring + Mybatis(半自动更灵活)
优点
- Spring是一个开源的免费框架(容器)
- Spring是一个轻量级的、非入侵式的框架
- 控制反转(IOC),面向切面编程(AOP)
- 支持事务的处理,对框架整合的支持
总结:Spring是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架
组成
七大模块
- Spring Boot
- 一个快速开发的脚手架
- 基于SpringBoot 开以快速开发单个微服务
- 约定大于配置
- Spring Cloud
- SpringCloud 是基于SpringBoot实现
学习Spring Boot 的前提就是完全掌握Spring SpringMVC Spring起到承上启下的作用
弊端:整合的框架太多之后,配置会非常繁琐,人称 ” 配置地狱 “
2、IOC
IOC是一种思想,DI(依赖注入)是实现IOC的一种方法
控制反转:
以前的我们要实现一个业务逻辑需要使用Dao层具体实现,Service层调用Dao层逻辑代码
并且还要通过每一个实现类都要定义一个接口再做出它的具体实现,如果有多个Dao业务,就需要在ServiceImpl 中改变它的具体实现,但是代码一旦多了起来这种方式就不可行了
IOC就是将将原来的由程序员控制实现的方式转变一下,添加一个set方法由用户动态的注入所需的参数,程序就不需要管创建了。
之前所写的代码所有东西都是由程序去进行创建,而现在是有我们自行控制创建对象主动权交给了调用者,程序不用去管怎么去创建了,只负责提供一个接口
IOC是一种通过描述(XML 或 注解)并通过第三方生产或获取特定对象的方式,在Spring中实现IOC 的是IOC容器,其实现方法是DI
3、第一个Spring程序
-
导入pom依赖
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.11</version> </dependency>
-
创建 hellospring类
package pojo; public class Hello { private String str; public String getStr() { return str; } public void setStr(String str) { this.str = str; } @Override public String toString() { return "pojo.hello{" + "str='" + str + '\'' + '}'; } }
-
创建 beans.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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="hello" class="pojo.Hello"> <!-- value:引用具体的值,基本类型 ref :引用spring容器中创建好了的对象 --> <property name="str" value="hello spring"/> <!-- collaborators and configuration for this bean go here --> </bean> </beans>
-
测试
import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import pojo.Hello; public class MyTest { @Test public void appTest(){ // 获取ApplicationContext,拿到spring 容器 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); // 获取过后,需要什么就直接get什么 Hello hello = (Hello)applicationContext.getBean("hello"); System.out.println(hello.getStr()); } }
到这里,要实现不同的操作都可以直接到 beans.Xml 配置文件中去修改,IOC就是一句话:对象由Spring来创建、管理、装配
4、IOC创建对象的方式
默认使用无参构造
可以构造有参构造
在配置文件加载的时候,容器(ApplicationContext)中管理的对象就已经初始化了
并且对象是唯一的
- 下标赋值(Constructor argument index)
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg index="0" value="7500000"/>
<constructor-arg index="1" value="42"/>
</bean>
- 类型匹配(Constructor argument type matching)
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg type="int" value="7500000"/>
<constructor-arg type="java.lang.String" value="42"/>
</bean>
- name(Constructor argument name)
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg name="years" value="7500000"/>
<constructor-arg name="ultimateAnswer" value="42"/>
</bean>
5、Spring 的配置
1.别名
<!-- 添加别迷宫之后就也可以通过别名来获取这个对象 --><alias name = "user" alias="userNew"/>
2.Bean的配置
id : 变量名
class: 全限定类名
name: 也是一个种起别名的方式,不过它可以起多个,支持多种分隔符
property: 用来注入这个类的属性
name: 属性名
value: 属性值
ref : 将属性值设置为Spring容器中已经创建好了的对象
<bean id="userT" class="com.kuang.pojo.userT" name="user2 u2,uT"> <property name="name" value="spring"></bean>
3.import
一般用于团队开发的时候,将多个配置文件合并为一个
将多个人开发的的beans.xml 合并为一个 applicationcontext.xml
<import resource="beans1.xml"/><import resource="beans2.xml"/>...
6、依赖注入
依赖:bean对象的创建依赖于容器
注入:bean对象中的所有属性,由容器来注入
1.构造器注入
- 参照于第4点
2.Set方式注入【重点】
在
bean
中使用property
标签进行注入不同的类型有不同的注入方式
<!-- 普通值注入 --><property name="name" value="value"/><!-- bean注入 --><property name="beanName" ref="classname"/><!-- 数组注入 --><property name="arrayName"> <array> <value>value1</value> <value>value2</value> ... </array></property><!-- list注入 --><property name="listName"> <list> <value>value1</value> <value>value2</value> ... </list></property><!-- map注入 --><property name="mapName"> <map> <entry key="keyName" value="value"> <entry key="keyName" value="value"> ... </map></property> <!-- set注入 --><property name="setName"> <set> <value>value1</value> <value>value2</value> </set></property> <!-- null --><property name="listName"> <null/></property> <!-- properties --><property name="listName"> <props> <prop key="keyName">value</prop> <prop key="keyName">value</prop> </props></property>
3.拓展方式注入
官网提供了 p-namespace 和 c-namespace 两种扩展方式
分别对应了 property (set注入) 和 constructor(构造器注入)方式,更简单快捷
但需要提前导入xml 约束
xmlns:p="http://www.springframework.org/schema/p"xmlns:c="http://www.springframework.org/schema/c"
c-namespace 方式:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:c="http://www.springframework.org/schema/c" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="beanTwo" class="x.y.ThingTwo"/> <bean id="beanThree" class="x.y.ThingThree"/><!-- traditional declaration with optional argument names --> <bean id="beanOne" class="x.y.ThingOne"> <constructor-arg name="thingTwo" ref="beanTwo"/> <constructor-arg name="thingThree" ref="beanThree"/> <constructor-arg name="email" value="something@somewhere.com"/> </bean><!-- c-namespace declaration with argument names --> <bean id="beanOne" class="x.y.ThingOne" c:thingTwo-ref="beanTwo" c:thingThree-ref="beanThree" c:email="something@somewhere.com"/></beans>
p-namespace 方式:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean name="jane" class="com.example.Person"> <property name="name" value="Jane Doe"/> </bean> <bean name="john-classic" class="com.example.Person"> <property name="name" value="John Doe"/> <property name="spouse" ref="jane"/> </bean> <bean name="john-modern"class="com.example.Person" p:name="John Doe" p:spouse-ref="jane"/> </beans>
4.bean的作用域(Scope)
Scope | Description |
---|---|
singleton | (Default) Scopes a single bean definition to a single object instance for each Spring IoC container. |
prototype | Scopes a single bean definition to any number of object instances. |
request | Scopes a single bean definition to the lifecycle of a single HTTP request. That is, each HTTP request has its own instance of a bean created off the back of a single bean definition. Only valid in the context of a web-aware Spring ApplicationContext . |
session | Scopes a single bean definition to the lifecycle of an HTTP Session . Only valid in the context of a web-aware Spring ApplicationContext . |
application | Scopes a single bean definition to the lifecycle of a ServletContext . Only valid in the context of a web-aware Spring ApplicationContext . |
websocket | Scopes a single bean definition to the lifecycle of a WebSocket . Only valid in the context of a web-aware Spring ApplicationContext . |
- 单例模式(Spring默认机制)
<bean id="accountService"class="com.something.DefaultAccountService" scope="singleton"/>
每次创建都是一个相同的对象
- 原型模式:每次从容器中get 的时候都会产生一个新的对象
<bean id="accountService"class="com.something.DefaultAccountService" scope="prototype"/>
- 其余的request、session、application这些只能在web开发中使用到
7、bean的自动装配(autowire)
是Spring满足bean依赖的一种方式
会在上下文中自动寻找,并自动给bean装配属性
Spring中的三种装配方式:
- xml中显式配置
- Java中显式配置
- 隐式的自动装配bean【重要】
传统的注入方式
<bean id="cat" class="Cat"/><bean id="dog" class="Dog"/><bean id="person" class="Person"> <property name="name" value="zj"/> <property name="cat" ref="cat"/> <property name="dog" ref="dog"/></bean>
ByName autowire
自动在容器上下文中查找和自己对象set方法后面的值对应的 bean id。
需要保证所有bean 的 id 唯一,并且bean 需要和自动注入的属性的set方法的xxx值一致
<bean id="cat" class="Cat"/>
<bean id="dog" class="Dog"/>
<bean id="person" class="Person" autowire="byName"/>
ByType autowire
自动在容器上下文中查找和自己对象属性类型想通过的bean。
需要保证所有bean 的 class 唯一,并且需要和自动注入的属性的类型一致
<bean id="cat" class="Cat"/>
<bean id="dog" class="Dog"/>
<bean id="person" class="Person" autowire="byType"/>
使用注解实现自动装配
jdk1.5 支持的注解,Spring 2.5就支持注解了
The introduction of annotation-based configuration raised the question of whether this approach is “better” than XML. The short answer is “it depends.”
- 导入约束:context约束
xmlns:context="http://www.springframework.org/schema/context"
- 配置注解支持: < context:annotation-config/>
<context:annotation-config/>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<!-- 1.1.导入约束 -->
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
<!-- 1.2.导入约束 -->
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 2.配置注解支持 -->
<context:annotation-config/>
</beans>
@Autowired
可以直接写在 属性 或者 set方法 上。
使用Autowired 就可以不用编写set方法了,前提是这个自动装配的属性在IOC(Spring)容器中存在,且符合命名 byName
@Autowired
private Dog dog;
@Autowired
public void setCat(Cat cat){
this.cat = cat;
}
如果使用 @Nullable 标注了一个字段
或 标注时使用 @Autowired (requierd = false)
则说明这个字段可以为 null
// 显式定义它的required 属性为false 默认为true ,说明这个对象可以为空
@Autowired(required = false)
private Cat cat;
@Nullable
@Nullable // 字段标记了这个注解,说明这个字段可以为null
@Qualifier
如果 @Autowire 自动配置的环境比较复杂,无法实现自动装配,可以使用
@Qualifier(value = “xxx”) 去指定一个唯一的 bean
@Autowired
@Aualifier(value = "dog")
private Dog dog;
@Resouce
Java 的原生注解
public class People{
@Resource
private Cat cat;
@Resource(name = "dog")
private Dog dog;
}
Autowired 和 Resource 的区别
- 都是用来实现自动装配的
- Autowired 通过 byType 的方式来实现,且要求这个对象必须存在【重点】
- Resource 通过 byName 的方式实现,如果找不到名字,就通过 byType 方式来实现,否则报错【重点】,它类似于 Qualifier + Autowired 的结合
8、Spring注解开发
在Spring 4 之后,要使用注解开发,必须要保证 aop 的包导入了
使用注解就需要导入 context 约束,增加注解的支持
指定要扫描的包,这个包下面的注解就会生效
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 指定要扫描的包,这个包下的注解就会生效 -->
<context:component-scan base-package="pojo"/>
<!-- 增加注解的支持,与spring -->
<context:annotation-config/>
</beans>
- bean
@Component // 组件,放在类上,说明这个类被Spring 管理了,就是bean
public class User{
private String name = "小明";
}
- 属性注入
@Component
public class User{
@Value("小明") // 相当于 <property name="name" value="小明"/>
private String name;
}
- 衍生的注解
@Component 有几个衍生注解,web 开发中会按照mvc三层架构分层
- dao : @Repositotry
- service : @service
- controller:@Controller
@Repository
public class User{
@Value("小明") // 相当于 <property name="name" value="小明"/>
private String name;
}
- 自动装配
@Autowired // 类型、名字
@Resource // 名字、类型
- 作用域
@Repository
@Scope("prototype")
public class User{
@Value("小明") // 相当于 <property name="name" value="小明"/>
private String name;
}
- 小结
-
xml与注解
- xml更加万能,适用于任何场合,维护简单方便
- 注解不是自己的类是用不了,维护相对复杂
-
最佳实践
- xml用来管理bean
- 注解负责完成属性的注入
- 使用过程中,让注解生效就需要开启注解的支持
<!-- 指定要扫描的包,这个包下的注解就会生效 --> <context:component-scan base-package="pojo"/> <!-- 增加注解的支持,与spring --> <context:annotation-config/>
9、JavaConfig实现配置
实体类
@Component // 这里的 @component 说明这个类被Spring接管了,注册到了容器中
public class User {
@Value("zj") // 属性注入值
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
配置类
@Configuration // 因为它本身也是一个Component,它也会被Spring 托管,注册到容器中,他就变成了一个配置类同 beans.xml
@Import(Javaconfig2.class)
//@Scope("singlet")
@ComponentScan("pojo")
public class JavaConfig {
@Bean // 注册一个bean,相当于一个bean标签,方法名相当于 id ,返回值相当于class
public User getUser(){
return new User(); // 要注入到 bean中的对象
}
}
测试类
public void test(){
// AnnotationConfigApplicationContext 通过配置类来获取Spring 容器
ApplicationContext context = new AnnotationConfigApplicationContext(JavaConfig.class);
// 方法名就相当于一个bean
User getUser = (User)context.getBean("getUser");
System.out.println(getUser);
}