Spring入门-01

Spring入门-01

Spring简介

Spring是一个开源框架,它是由[Rod Johnson](https://baike.baidu.com/item/Rod Johnson)为了解决企业应用开发的复杂性而创建的

目前是JavaEE开发的灵魂框架

Spring可以简化JavaEE开发,可以非常方便整合其他框架,无侵入的进行功能增强

Spring的核心是 控制反转(IOC)面向切面(AOP)

IOC控制反转

概念

控制反转,之前对象的控制权在类手上,现在反转后到了Spring手上

入门案例

导入依赖

导入SpringIOC相关依赖

1
2
3
4
5
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.26</version>
</dependency>

编写实体类

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
package com.sinarcsinx.domain;

public class Dog {
private String name;
private int age;

@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public Dog() {
}

public Dog(String name, int age) {
this.name = name;
this.age = age;
}
}
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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package com.sinarcsinx.domain;

public class Student {

private String name;
private int id;
private int age;

private Dog dog;

public Dog getDog() {
return dog;
}

public void setDog(Dog dog) {
this.dog = dog;
}

@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", id=" + id +
", age=" + age +
", dog=" + dog +
'}';
}

public Student() {

}

public Student(String name, int id, int age, Dog dog) {
this.name = name;
this.id = id;
this.age = age;
this.dog = dog;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}
}

编写配置文件

resources目录下创建applicationContext.xml文件,文件名可以任意取,但是建议叫applicationContext

内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">

<!--
class:配置类的全类名
id:配置一个唯一标识
-->
<bean class="com.sinarcsinx.domain.Student" id="student" >
</bean>

</beans>

创建容器从容器中获取对象并测试

1
2
3
4
5
6
7
8
9
public static void main(String[] args) {
//获取StudentDaoImpl对象
//创建Spring容器,指定要读取的配置文件路径
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
//从容器中获取对象
Student student = (Student) app.getBean("student");
//调用对象的方法进行测试
System.out.println(student);
}

Output:

1
Student{name='null', id=0, age=0}

Bean的常用属性配置

id

bean的唯一标识,同一个Spring容器中不允许重复

class

全类名,用于反射创建对象

scope

scope主要有两个值:singletonprototype

如果设置为singleton则一个容器中只会有这个一个bean对象,默认容器创建的时候就会创建该对象

如果设置为prototype则一个容器中会有多个该bean对象,每次调用getBean方法获取时都会创建一个新对象

DI依赖注入

依赖注入可以理解成IoC的一种应用场景,反转的是对象间依赖关系维护权

set方法注入

在要注入属性的bean标签中进行配置,前提是该类有提供属性对应的set方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<bean class="com.sinarcsinx.domain.Dog" id="dog">
<property name="name" value="小白"></property>
<property name="age" value="6"></property>
</bean>

<bean class="com.sinarcsinx.domain.Student" id="student1" >
<!--
name属性用来指定要设置哪个属性
value属性用来设置要设置的值
ref属性用来给引用类型的属性设置值,可以写上Spring容器中bean的id
-->
<property name="name" value="sin"></property>
<property name="age" value="20"></property>
<property name="id" value="1"></property>
<property name="dog" ref="dog"></property>
</bean>

有参构造注入

在要注入属性的bean标签中进行配置,前提是该类有提供对应的有参构造

1
2
3
4
5
6
7
<!--使用有参构造进行注入-->
<bean class="com.sinarcsinx.domain.Student" id="student2">
<constructor-arg name="name" value="sina"></constructor-arg>
<constructor-arg name="age" value="20"></constructor-arg>
<constructor-arg name="id" value="30"></constructor-arg>
<constructor-arg name="dog" ref="dog"></constructor-arg>
</bean>

复杂类型属性注入

实体类如下(先加入Lombok依赖):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private int age;
private String name;
private Phone phone;
private List<String> list;
private List<Phone> phones;
private Set<String> set;
private Map<String, Phone> map;
private int[] arr;
private Properties properties;
}
1
2
3
4
5
6
7
8
9
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Phone {
private double price;
private String name;
private String password;
private String path;
}

配置如下:

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
45
46
47
48
49
50
51
52
<bean class="com.sinarcsinx.domain.Phone" id="phone">
<property name="price" value="3999"></property>
<property name="name" value="黑米"></property>
<property name="password" value="123"></property>
<property name="path" value="qqqq"></property>
</bean>

<bean class="com.sinarcsinx.domain.User" id="user">
<property name="age" value="10"></property>
<property name="name" value="sin"></property>
<property name="phone" ref="phone"></property>
<property name="list">
<list>
<value>东施</value>
<value>西施</value>
</list>
</property>

<property name="phones">
<list>
<ref bean="phone"></ref>
</list>
</property>

<property name="set">
<set>
<value>setEle1</value>
<value>setEle2</value>
</set>
</property>

<property name="map">
<map>
<entry key="k1" value-ref="phone"></entry>
<entry key="k2" value-ref="phone"></entry>
</map>
</property>

<property name="arr">
<array>
<value>10</value>
<value>11</value>
</array>
</property>

<property name="properties">
<props>
<prop key="k1">v1</prop>
<prop key="k2">v2</prop>
</props>
</property>
</bean>

Lombok

导入依赖

1
2
3
4
5
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
</dependency>

增加注解

1
2
3
4
5
6
7
8
9
@Data //根据属性生成set,get方法
@NoArgsConstructor //生成空参构造
@AllArgsConstructor //生成全参构造
public class Phone {
private double price;
private String name;
private String password;
private String path;
}

SPEL

我们可以再配置文件中使用SPEL表达式。写法如下:

1
2
<property name="age" value="#{20}"/>
<property name="car" value="#{car}"/>

注意:SPEL需要写到value属性中,不能写到ref属性

配置文件

读取properties文件

我们可以让Spring读取properties文件中的key/value,然后使用其中的值

设置读取properties

在Spring配置文件中加入如下标签:指定要读取的文件的路径

1
<context:property-placeholder location="classpath:filename.properties">

其中的classpath表示类加载路径下。

我们也会用到如下写法:classpath:**.properties 其中的* * 表示文件名任意

注意:context命名空间的引入是否正确

使用配置文件中的值

在我们需要使用的时候可以使用${key}来表示具体的值,注意要再value属性中使用才可以

例如:

1
<property name="propertyName" value="${key}"/>

引入Spring配置文件

我们可以在主的配置文件中通过import标签的resource属性,引入其他的xml配置文件

1
<import resource="classpath:applicationContext-book.xml"/>

低频知识点

bean的配置

name属性

我们可以用name属性来给bean取名

例如:

1
2
3
4
5
6
<bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource" name="dataSource2,dataSource3">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>

获取的时候就可以使用这个名字来获取了

1
2
3
4
5
public static void main(String[] args) {
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
DruidDataSource dataSource = (DruidDataSource) app.getBean("dataSource3");
System.out.println(dataSource);
}

lazy-init

可以控制bean的创建时间,如果设置为true就是在第一次获取该对象的时候才去创建

1
2
3
4
5
6
<bean class="com.alibaba.druid.pool.DruidDataSource" lazy-init="true"  id="dataSource" name="dataSource2,dataSource3">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>

init-method

可以用来设置初始化方法,设置完后容器创建完对象就会自动帮我们调用对应的方法

1
2
3
4
5
6
7
8
9
10
11
12
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
private String name;
private int id;
private int age;
//初始化方法
public void init(){
System.out.println("对学生对象进行初始化操作");
}
}
1
<bean class="com.sinarcsinx.domain.Student" id="student" init-method="init"></bean>

注意:配置的初始化方法只能是空参的

destroy-method

可以用来设置销毁之前调用的方法,设置完后容器销毁对象前就会自动帮我们调用对应的方法

1
<bean class="com.sinarcsinx.domain.Student" id="student"  destroy-method="close"></bean>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
private String name;
private int id;
private int age;

public void init(){
System.out.println("对学生对象进行初始化操作");
}

public void close(){
System.out.println("对象销毁之前调用,用于释放资源");
}
}

注意:配置的方法只能是空参的

factory-bean&factory-method

当我们需要让Spring容器使用工厂类来创建对象放入Spring容器的时候可以使用factory-bean和factory-method属性

配置实例工厂创建对象

配置文件中进行配置

1
2
3
4
5
6
<!--创建实例工厂-->
<bean class="com.sinarcsinx.factory.CarFactory" id="carFactory"></bean>
<!--使用实例工厂创建Car放入容器-->
<!--factory-bean 用来指定使用哪个工厂对象-->
<!--factory-method 用来指定使用哪个工厂方法-->
<bean factory-bean="carFactory" factory-method="getCar" id="car"></bean>

创建容器获取对象测试

1
2
3
4
ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取car对象
Car c = (Car) app.getBean("car");
System.out.println(c);
配置静态工厂创建对象

配置文件中进行配置

1
2
<!--使用静态工厂创建Car放入容器-->
<bean class="com.sinarcsinx.factory.CarStaticFactory" factory-method="getCar" id="car2"></bean>

创建容器获取对象测试

1
2
3
4
ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取car对象
Car c = (Car) app.getBean("car2");
System.out.println(c);