Spring框架入门

一、Spring简要

什么是Spring?

Spring是一个非倾入容器,用于降低代码间的耦合度。根据不同的代码,使用IoC和AOP两种技术进行解耦。

主业务逻辑:逻辑联系紧密,复用性低
系统级服务:功能独立,主要是为业务提供系统级服务(日志、安全、事务),复用性强

IoC:使主业务不再自己维护关系,由Spring统一管理,“注入”
AOP:使系统级服务最大限度复用,不需要混杂进主业务,而是由Spring统一“织入”

非倾入:Spring的API不会侵入业务逻辑,不会破坏pojo(Plain Old Java Object)

ApplicationContext与BeanFactory容器的区别

1
2
3
4
5
1) ApplicationContext容器在进行初始化时,会将其中所有Bean对象创建
(占用系统资源,响应速度快)

2)BeanFactory容器中的对象,在容器初始化时并不会被创建,而是在获取该对象时才会被创建
(响应速度慢,不多占用系统资源)

最全约束

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?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"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">

<!-- 开启组件扫描器 -->
<context:component-scan base-package="beans">
</beans>

IoC是什么?

控制反转思想,DI(依赖注入)是主流的实现方式

其他实现方式:依赖查找

二、Bean简述

(一)动态工厂Bean

1
2
<bean id="factory" class="ServiceFactory">
<bean id="myService" factory-bean="factory" factory-method="getService">

(二)静态工厂Bean(推荐)

1
2
3
4
<!-- 需要工厂方法为静态方法 -->
<!-- 静态工厂,工厂对象无需创建,直接引用工厂类 -->
<bean id="testService" class="factory.ServiceFactory"
factory-method="getTestService"/>

(三)Bean的创建模式

1
2
3
4
<!-- 单例(默认) -->
<bean id="student" class="Student" scope="singleton">
<!-- 原型(对象创建时机:不随容器创建) -->
<bean id="student" class="Student" scope="prototype">

三、Bean生命周期的始末

1
2
<bean id="myService" class="ServiceImpl" 
init-method="起始方法名" destory-method="结束方法名">

要执行结束方法,需关闭容器。

1
2
// 关闭容器条件 1. Bean对象是单例的 2. 手动关闭容器
((ClassPathXmlApplicationContext)applicationContext).close();

生命周期顺序:

  1. 无参构造器
  2. 执行setter(需注入)
  3. 获取到Bean的id(需实现BeanNameAware)
  4. 获取到BeanFactory容器(需实现BeanFactoryAware)
  5. 执行postProcessBeforeInitialization()(需注册Bean后处理器BeanPostProcessor接口实现类)
  6. Bean初始化完毕(需实现InitializingBean)
  7. 初始化完毕之后(起始方法init-method执行)
  8. 执行postProcessAfterInitialization()方法
  9. doSome…
  10. 销毁之前(需实现接口DisposableBean)
  11. 销毁之前(执行destory-method=”结束方法名”)

四、Spring配置文件

标签id和name区别

id:必须满足XML的命名规范:
    必须字母开头,可以包含数字、字母、下划线、连字符、句号、冒号
name:可以包含任何字符

基于XML的DI

(一)设值注入

1
2
3
4
5
<!-- 需要提供setter方法 -->
<bean id="student" class="Student">
<property name="name" value="张三"/>
<property name="school" ref="mySchool"/>
</bean>

(二)构造注入

方法一

1
2
3
4
5
<!-- 需带参构造器 -->
<bean id="student" class="Student">
<constructor-arg index="0" value="李四">
<constructor-arg index="1" ref="mySchool">
</bean>

方法二

1
2
3
4
5
<!-- 需带参构造器 -->
<bean id="student" class="Student">
<constructor-arg value="李四">
<constructor-arg ref="mySchool">
</bean>

方法三

1
2
3
4
5
<!-- 需带参构造器 -->
<bean id="student" class="Student">
<constructor-arg name="name" value="李四">
<constructor-arg name="school" ref="mySchool">
</bean>

(三)实现接口注入

(四)命名空间注入

P命名空间设值注入

1
2
<!-- 需要setter方法 -->
<bean id="student" class="Student" p:name="王五" p:school-ref:mySchool/>

C命名空间构造注入

1
2
<!-- 需要带参构造方法 -->
<bean id="student" class="Student" c:name="王五" c:school-ref:mySchool/>

(五)集合属性注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

<bean id="mySome" class="Some">
<!-- 数组:引用类型 -->
<property name="schools">
<array>
<ref bean="mySchool">
<ref bean="mySchool2">
</array>
</property>
<!-- 字符串数组 -->
<property name="myStrs">
<array>
<value>北京</value>
<value>上海</value>
</array>
</property>
<!-- list:字符串 -->
<property name="myList">
<list>
<value>广州</value>
<value>云南</value>
</list>
</property>
<!-- set:字符串 -->
<property name="mySet">
<set>
<value>苏州</value>
<value>常州</value>
</set>
</property>
<!-- map:字符串 Object -->
<property name="myMap">
<map>
<entry key="password" value="123456">
</map>
</property>
<!-- Properyies对象 -->
<property name="myPros">
<props>
<prop key="education">大学</prop>
<prop key="gender"></prop>
</props>
</property>
</bean>

简单写法

1
2
3
<property name="myStrs" value="北京,上海"/>
<property name="myList" value="广州,云南"/>
<property name="mySet" value="苏州,常州"/>

(六)自动注入

1
2
3
4
5
6
7
<bean id="school" class="School">
<property name="name" value="清华大学"/>
</bean>
<!-- byName:从容器中自动找寻与属性名称相同的Bean的id,自动织入school属性 -->
<bean id="student" class="Student" autowire="byName">
<property name="name" value="张三"/>
</bean>
1
2
3
4
5
6
7
<bean class="School">
<property name="name" value="清华大学"/>
</bean>
<!-- byType:从容器中自动找寻与属性类型相同(包括子类)的Bean,自动织入school属性 -->
<bean id="student" class="Student" autowire="byType">
<property name="name" value="张三"/>
</bean>

(七)SpEL表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- 要求:
李四年龄随机小于50
myStudent名称和myPerson相同
myStudent年龄和myPerson相同,若大于25按25算 -->
<bean id="myPerson" class="Person">
<property name="pname" value="李四">
<property name="page" value="#{T(java.lang.Math).random()*50}">
</bean>
<bean id="myStudent" class="Student">
<!-- 需要getter方法 -->
<property name="name" value="#{myPerson.pname}">
<property name="age" value="#{myPerson.page > 25 ? 25 : myPerson.page}">
</bean>

(八)内部Bean

1
2
3
4
5
6
7
8
<bean id="student" class="Student">
<property name="school">
<!-- 内部Bean无法直接被getBean获取 -->
<bean class="School">
<property name="name" value="清华大学"/>
</bean>
</property>
</bean>

(九)同类抽象Bean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!-- abstract:阻止base被获取 -->
<bean id="baseStudent" class="Student" abstract="true">
<property name="school" value="清华大学"/>
</bean>
<!-- parent:继承base的property,class -->
<bean id="myStudent1" parent="baseStudent">
<property name="name" value="张三"/>
</bean>
<bean id="myStudent2" parent="baseStudent">
<property name="name" value="李四"/>
</bean>
<bean id="myStudent3" parent="baseStudent">
<property name="name" value="王五"/>
</bean>

(十)异类抽象Bean

1
2
3
4
5
6
7
8
9
10
11
<!-- abstract:阻止base被创建(base无class,无abstract则创建报错) -->
<bean id="base" abstract="true">
<property name="school" value="清华大学"/>
</bean>
<!-- parent:继承base的property -->
<bean id="myStudent" class="Student" parent="base">
<property name="name" value="张三"/>
</bean>
<bean id="myTeacher" class="Teacher" parent="base">
<property name="name" value="李四"/>
</bean>

五、多个Spring配置文件关系

平等关系

配置文件:
    spring-beans.xml
    spring-base.xml

写法一(利用重载方法:可变参数)

1
2
3
String resource = "spring-base.xml";
String resource2 = "spring-beans.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(resource,resource2);

写法二(利用重载方法:可变参数)

1
2
3
4
String resource = "spring-base.xml";
String resource2 = "spring-beans.xml";
String[] resources = {resource,resource2};
ApplicationContext ac = new ClassPathXmlApplicationContext(resources);

写法三(推荐)

1
2
3
String resource = "spring-*.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
Student stu = (Student)ac.getBean("myStudemt");

包含关系

1
2
3
<!-- 若使用通配符,主配置文件格式需不同 -->
<import resource="classpath:spring-base.xml"/>
<import resource="classpath:spring-beans.xml"/>

六、基于注解的DI

必须1:导入aop包

必须2:开启组件扫描器

1
2
<!-- 开启组件扫描器 -->
<context:component-scan base-package="beans">
1
2
3
4
5
6
7
8
9
@Scope("prototype") // 单例 or 原型(默认单例)
@Component("mySchool") // 组件,表示当前类被Spring容器管理
public class School{
@Value("清华大学") // 注入值
private name;
public void setName(String name){
this.name = name;
}
}

(一)base-package相关

1
2
3
4
5
<!-- 扫描com.ssm这个包及其子包 -->
<context:component-scan base-package="com.ssm">

<!-- 仅扫描com.ssm这个包的子包 -->
<context:component-scan base-package="com.ssm.*">

(二)和@Component相关的注解

注解 使用位置
Repository 使用在Dao实现类上
Service 使用在Service实现类上
Controller 使用在SpringMVC的处理器上