【笔记】SpringFramework学习笔记

前言

SpringFramework学习笔记

核心概念

  • IoC(Inversion of Control)控制反转
    • 使用对象时,由主动new产生对象转换为由外部提供对象,此过程中对象创建控制权由程序转移到外部,此思想称为控制反转
  • Spring技术对IoC思想进行了实现
    • Spring提供了一个容器,称为IoC容器,用来充当IoC思想中的外部
    • IoC容器负责对象的创建、初始化等一系列工作,被创建或被管理的对象在IoC容器中称为Bean
  • DI(Dependency Injection)注入
    • 在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入

引入依赖

pox.xml
1
2
3
4
5
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>

准备工作

src/main/java/com/dao/UserDao.java
1
2
3
4
5
6
7
8
9
package com.dao;

public class UserDao {

public void method() {
System.out.println("userDao.method()");
}

}
src/main/java/com/service/UserService.java
1
2
3
4
5
6
7
8
9
10
11
12
package com.service;

import com.dao.UserDao;

public class UserService {

UserDao userDao = new UserDao();

public void method() {
userDao.method();
}
}

IoC容器快速入门

  • IoC容器的创建和bean对象的获取

配置bean

  • 创建applicationContext.xml配置文件并配置bean

<bean id="" class="" /><bean id="" class=""></bean>:一个bean标签表示一个配置

id="":自定义bean的名称,必须唯一不重复,通常首字母小写
class="":指定交给Spring管理的Java类,填写类的全局限定名

src/main/resources/applicationContext.xml
1
2
3
4
5
6
7
8
<?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">

<bean id="userDao" class="com.dao.UserDao"/>
<bean id="userService" class="com.service.UserService"></bean>

</beans>

创建IoC容器并获取bean对象

  • 在程序的入口创建IoC容器对象,传递配置文件名
  • 通过bean的id获取由Spring管理的bean对象,得到Object类型的对象,可以强制类型转换

getBean(""):指定bean的id

src/main/java/com/Application
1
2
3
4
5
6
7
8
9
public class Application {
public static void main(String[] args) {
// 获取IoC容器对象
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取bean对象
UserService obj = (UserService) applicationContext.getBean("userService");
obj.method();
}
}

DI依赖注入快速入门

通过setter注入

引用类型注入

new对象改为不创建对象
  • 通过set()方法为属性赋值
src/main/java/service/UserService.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import com.dao.UserDao;

public class UserService {

// UserDao userDao = new UserDao();
UserDao userDao;

public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}

public void method() {
userDao.method();
}
}
修改bean配置
  • 通过<property />配置,实现setter注入
  • 可以指定多个<property />配置,实现注入多个

name="":指定变量名(指定UserService.javaUserDao userDao;中的对象名)
ref="":指定变量值(指定applicationContext.xml中的<bean id="userDao" class="com.dao.UserDao"/>中bean的id或name)

src/main/resources/applicationContext.xml
1
2
3
4
5
6
7
8
9
10
<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">

<bean id="userDao" class="com.dao.UserDao"/>
<bean id="userService" class="com.service.UserService">
<property name="userDao" ref="userDao"/>
<property name="" ref=""/>
</bean>

</beans>

基本类型注入

直接赋值改为不赋值
  • 通过set()方法为属性赋值
src/main/java/service/UserService.java
1
2
3
4
5
6
7
8
9
10
11
package com.service;

public class UserService {

// private int id = 1;
private int id;

public void setId(int id) {
this.id = id;
}
}
修改bean配置
  • 通过<property />配置,实现注入
  • 可以指定多个<property />配置,实现注入多个

name="":指定变量名
value="":指定变量值

src/main/resources/applicationContext.xml
1
2
3
4
5
6
7
8
9
<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">

<bean id="userService" class="com.service.UserService">
<property name="id" value="1"/>
<property name="" value=""/>
</bean>

</beans>

通过构造器注入

引用类型注入

new创建对象改为不创建对象
  • 通过构造方法为属性赋值
src/main/java/service/UserService.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.service;

import com.dao.UserDao;

public class UserService {

// UserDao userDao = new UserDao();
UserDao userDao;

public UserService(UserDao userDao) {
this.userDao = userDao;
}

public void method() {
userDao.method();
}
}
修改bean配置
  • 通过<constructor-arg />配置,实现构造器注入
  • 可以指定多个<constructor-arg />配置,实现注入多个

name="":指定变量名(指定UserService.java中构造方法 public UserService(UserDao userDao) {}中的形参名)
ref="":指定变量值(指定applicationContext.xml中的<bean id="userDao" class="com.dao.UserDao"/>中bean的id或name)

src/main/resources/applicationContext.xml
1
2
3
4
5
6
7
8
9
10
11
<?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">

<bean id="userDao" class="com.dao.UserDao" />
<bean id="userService" class="com.service.UserService">
<constructor-arg name="userDao" ref="userDao" />
<constructor-arg name="" ref="" />
</bean>

</beans>

基本类型注入

直接赋值改为不赋值
  • 通过构造方法为属性赋值
src/main/java/service/UserService.java
1
2
3
4
5
6
7
8
9
10
11
12
package com.service;

public class UserService {

// private int id = 1;
private int id;

public UserService(int id) {
this.id = id;
}

}
修改bean配置
  • 通过<constructor-arg />配置,实现构造器注入
  • 可以指定多个<constructor-arg />配置,实现注入多个

name="":指定变量名
value="":指定变量值

src/main/resources/applicationContext.xml
1
2
3
4
5
6
7
8
9
10
<?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">

<bean id="userService" class="com.service.UserService">
<constructor-arg name="id" value="1" />
<constructor-arg name="" value="" />
</bean>

</beans>
解决形参名可能被修改的问题
  • 如果所有形参的类型均不相同,可以采用指定变量类型的方式解耦

type="":指定变量类型
value="":指定变量值

1
2
3
4
5
6
7
8
9
10
<?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">

<bean id="userService" class="com.service.UserService">
<constructor-arg type="int" value="1" />
<constructor-arg type="java.lang.String" value="" />
</bean>

</beans>
解决形参类型可能重复的问题
  • 可以直接指定形参的顺序,从0开始

index="":指定形参顺序
value="":指定变量值

1
2
3
4
5
6
7
8
9
10
<?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">

<bean id="userService" class="com.service.UserService">
<constructor-arg index="0" value="1" />
<constructor-arg index="" value="" />
</bean>

</beans>

通过setter自动装配

  • 自动装配只能为引用类型自动装配
  • 如果手动装配的配置和自动装配的配置同时出现,那么自动装配的配置会失效

引用类型注入

new对象改为不创建对象
  • 通过set()方法为属性赋值
src/main/java/service/UserService.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import com.dao.UserDao;

public class UserService {

// UserDao userDao = new UserDao();
UserDao userDao;

public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}

public void method() {
userDao.method();
}
}
修改bean配置
  • 添加被自动装配的bean配置
  • 在需要自动装配的bean上添加autowire=""属性

autowire=""指定自动装配方式

byType:按类型
byName:按名称
constructor:使用构造方法
default:默认
no:不使用自动装配

按类型自动装配
  • 在定义被自动装配的bean时,不能有多个相同类型的bean
  • 如果是按类型自动装配,被自动装配的bean甚至可以不定义id
src/main/resources/applicationContext.xml
1
2
3
4
5
6
7
<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">

<bean id="userDao" class="com.dao.UserDao"/>
<bean id="userService" class="com.service.UserService" autowire="byType"/>

</beans>
按名称自动装配
  • 被自动装配bean的id需要与set方法的属性名相同(setUserDao -> dao)
src/main/resources/applicationContext.xml
1
2
3
4
5
6
7
<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">

<bean id="userDao" class="com.dao.UserDao"/>
<bean id="userService" class="com.service.UserService" autowire="byName"/>

</beans>

通过setter多数据注入

数组类型注入

注入基本类型数据
new对象改为不创建对象
  • 通过set()方法为属性赋值
src/main/java/service/UserService.java
1
2
3
4
5
6
7
8
9
10
11
package com.service;

public class UserService {

int[] array;

public void setArray(int[] array) {
this.array = array;
}
}

修改bean配置
  • 通过<property></property>配置,实现setter注入

name="":指定变量名

<array></array>:数组类型注入

<value></value>:指定变量值

src/main/resources/applicationContext.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
<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">

<bean id="userService" class="com.service.UserService">
<property name="array">
<array>
<value>1</value>
<value></value>
</array>
</property>
</bean>

</beans>
注入引用类型数据
new对象改为不创建对象
  • 通过set()方法为属性赋值
src/main/java/service/UserService.java
1
2
3
4
5
6
7
8
9
10
11
package com.service;

public class UserService {

UserDao[] array;

public void setArray(UserDao[] array) {
this.array = array;
}
}

修改bean配置
  • 通过<property></property>配置,实现setter注入

name="":指定变量名

<array></array>:数组类型注入

<ref bean=""/>:指定bean对象的id

src/main/resources/applicationContext.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
<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">

<bean id="userDao" class="com.dao.UserDao"/>
<bean id="userService" class="com.service.UserService">
<property name="array">
<array>
<ref bean="userDao"/>
</array>
</property>
</bean>

</beans>

List集合类型注入

注入基本类型数据
new对象改为不创建对象
  • 通过set()方法为属性赋值
src/main/java/service/UserService.java
1
2
3
4
5
6
7
8
9
10
11
12
package com.service;

import java.util.List;

public class UserService {

List<String> list;

public void setList(List<String> list) {
this.list = list;
}
}
修改bean配置
  • 通过<property></property>配置,实现setter注入

name="":指定变量名

<list></list>:List集合类型注入

<value></value>:指定变量值

src/main/resources/applicationContext.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
<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">

<bean id="userService" class="com.service.UserService">
<property name="list">
<list>
<value>1</value>
<value></value>
</list>
</property>
</bean>

</beans>
注入引用类型数据
new对象改为不创建对象
  • 通过set()方法为属性赋值
src/main/java/service/UserService.java
1
2
3
4
5
6
7
8
9
10
11
12
package com.service;

import java.util.List;

public class UserService {

List<UserDao> list;

public void setList(List<UserDao> list) {
this.list = list;
}
}
修改bean配置
  • 通过<property></property>配置,实现setter注入

name="":指定变量名

<list></list>:List集合类型注入

<ref bean=""/>:指定bean对象的id

src/main/resources/applicationContext.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
<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">

<bean id="userDao" class="com.dao.UserDao"/>
<bean id="userService" class="com.service.UserService">
<property name="list">
<list>
<ref bean="userDao"/>
</list>
</property>
</bean>

</beans>

Set集合类型注入

注入基本类型数据
new对象改为不创建对象
  • 通过set()方法为属性赋值
src/main/java/service/UserService.java
1
2
3
4
5
6
7
8
9
10
11
12
package com.service;

import java.util.Set;

public class UserService {

Set<String> set;

public void setSet(Set<String> set) {
this.set = set;
}
}
修改bean配置
  • 通过<property></property>配置,实现setter注入

name="":指定变量名

<set></set>:Set集合类型注入

<value></value>:指定变量值

src/main/resources/applicationContext.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
<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">

<bean id="userService" class="com.service.UserService">
<property name="set">
<set>
<value>1</value>
<value></value>
</set>
</property>
</bean>

</beans>
注入引用类型数据
new对象改为不创建对象
  • 通过set()方法为属性赋值
src/main/java/service/UserService.java
1
2
3
4
5
6
7
8
9
10
11
12
package com.service;

import java.util.Set;

public class UserService {

Set<UserDao> set;

public void setSet(Set<UserDao> set) {
this.set = set;
}
}
修改bean配置
  • 通过<property></property>配置,实现setter注入

name="":指定变量名

<set></set>:Set集合类型注入

<ref bean=""/>:指定bean对象的id

src/main/resources/applicationContext.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
<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">

<bean id="userDao" class="com.dao.UserDao"/>
<bean id="userService" class="com.service.UserService">
<property name="set">
<set>
<ref bean="userDao"/>
</set>
</property>
</bean>

</beans>

Map集合类型注入

注入基本类型数据
new对象改为不创建对象
  • 通过set()方法为属性赋值
src/main/java/service/UserService.java
1
2
3
4
5
6
7
8
9
10
11
12
package com.service;

import java.util.Map;

public class UserService {

Map<String, String> map;

public void setMap(Map<String, String> map) {
this.map = map;
}
}
修改bean配置
  • 通过<property></property>配置,实现setter注入

name="":指定变量名

<map></map>:Set集合类型注入

<entry key="" value=""/>:指定键值对

src/main/resources/applicationContext.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
<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">

<bean id="userService" class="com.service.UserService">
<property name="map">
<map>
<entry key="k" value="v"/>
<entry key="" value=""/>
</map>
</property>
</bean>

</beans>
注入引用类型数据
new对象改为不创建对象
  • 通过set()方法为属性赋值
src/main/java/service/UserService.java
1
2
3
4
5
6
7
8
9
10
11
12
package com.service;

import java.util.Map;

public class UserService {

Map<String, UserDao> map;

public void setMap(Map<String, UserDao> map) {
this.map = map;
}
}
修改bean配置
  • 通过<property></property>配置,实现setter注入

name="":指定变量名

<map></map>:Set集合类型注入

<entry key="" value=""/>:指定键值对,值为引用类型

src/main/resources/applicationContext.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<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">

<bean id="userDao" class="com.dao.UserDao"/>
<bean id="userService" class="com.service.UserService">
<property name="map">
<map>
<entry key="k" value="userDao"/>
<entry key="" value=""/>
</map>
</property>
</bean>

</beans>

Properties类型注入

注入基本类型数据
new对象改为不创建对象
  • 通过set()方法为属性赋值
src/main/java/service/UserService.java
1
2
3
4
5
6
7
8
9
10
11
12
package com.service;

import java.util.Properties;

public class UserService {

Properties properties;

public void setProperties(Properties properties) {
this.properties = properties;
}
}
修改bean配置
  • 通过<property></property>配置,实现setter注入

name="":指定变量名

<props></props>:Set集合类型注入

<prop key=""></prop>:指定键值对

src/main/resources/applicationContext.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
<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">

<bean id="userService" class="com.service.UserService">
<property name="properties">
<props>
<prop key="k">v</prop>
<prop key=""></prop>
</props>
</property>
</bean>

</beans>
注入引用类型数据
new对象改为不创建对象
  • 通过set()方法为属性赋值
src/main/java/service/UserService.java
1
2
3
4
5
6
7
8
9
10
11
12
package com.service;

import java.util.Properties;

public class UserService {

Properties properties;

public void setProperties(Properties properties) {
this.properties = properties;
}
}
修改bean配置
  • 通过<property></property>配置,实现setter注入

name="":指定变量名

<props></props>:Set集合类型注入

<prop key=""></prop>:指定键值对,值为引用类型

src/main/resources/applicationContext.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<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">

<bean id="userDao" class="com.dao.UserDao"/>
<bean id="userService" class="com.service.UserService">
<property name="properties">
<props>
<prop key="k">userDao</prop>
<prop key=""></prop>
</props>
</property>
</bean>

</beans>

管理第三方的bean

  • 以Druid为例

添加依赖

pom.xml
1
2
3
4
5
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>

由Spring管理对象

src/main/resources/applicationContext.xml
1
2
3
4
5
6
7
8
9
10
11
12
<?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">

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
<property name="url" value="jdbc:mysql:///" />
<property name="username" value="" />
<property name="password" value="" />
</bean>

</beans>

获取并使用bean对象

src/main/java/com/Application.java
1
2
3
4
5
6
7
public class Application {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
DataSource dataSource = (DataSource) applicationContext.getBean("dataSource");
System.out.println(dataSource);
}
}

Spring实例化bean的方式

  • 使用无参构造实例化bean对象
  • 使用静态工厂实例化bean对象
  • 使用实例工厂实例化bean对象

手动配置静态工厂方式获取bean对象

创建静态工厂类

src/main/java/com/factory/UserDaoFactory.java
1
2
3
4
5
6
7
8
9
package com.factory;

import com.dao.UserDao;

public class UserDaoFactory {
public static UserDao getUserDao() {
return new UserDao();
}
}

修改bean配置

class="":指定工厂类的全局限定名
factory-method="":指定工厂类中获取对象的方法名

src/main/resources/applicationContext.xml
1
2
3
4
5
6
7
<?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">

<bean id="userDao" class="com.factory.UserDaoFactory" factory-method="getUserDao"/>

</beans>

手动配置实例工厂方式获取bean对象

创建静态工厂类

src/main/java/com/factory/UserDaoFactory.java
1
2
3
4
5
6
7
8
9
package com.factory;

import com.dao.UserDao;

public class UserDaoFactory {
public UserDao getUserDao() {
return new UserDao();
}
}

修改bean配置

factory-bean="":指定工厂类bean的id
factory-method="":指定工厂类中获取对象的方法名

src/main/resources/applicationContext.xml
1
2
3
4
5
6
7
8
<?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">

<bean id="userDaoFactory" class="com.factory.UserDaoFactory"/>
<bean id="userDao" factory-bean="userDaoFactory" factory-method="getUserDao"/>

</beans>

自动配置实例工厂方式获取bean对象

创建一个工厂类

  • 创建一个工厂类,实现FactoryBean<>接口,在getObject()方法中返回创建的 对象,在getObjectType()方法中返回创建的对象的类型

FactoryBean<>:指定创建的对象的类型作为泛型

src/main/java/com/factory/UserDaoFactory.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.factory;

import com.dao.UserDao;
import org.springframework.beans.factory.FactoryBean;

public class UserDaoFactory implements FactoryBean<UserDao> {
// 创建对象
public UserDao getObject() throws Exception {
return new UserDao();
}
// 创建对象的类型
public Class<?> getObjectType() {
return UserDao.class;
}
}
工厂类创建非单例的实例
  • 默认工厂类创建的实例是单例的,通过重写isSingleton()方法,将返回值改为false,就可以创建出非单例的实例
src/main/java/com/factory/UserDaoFactory.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.factory;

import com.dao.UserDao;
import org.springframework.beans.factory.FactoryBean;

public class UserDaoFactory implements FactoryBean<UserDao> {
// 创建对象
public UserDao getObject() throws Exception {
return new UserDao();
}
// 创建对象的类型
public Class<?> getObjectType() {
return UserDao.class;
}
// 配置是否是单例的:true单例、false非单例
public boolean isSingleton() {
return true;
}
}

修改bean配置

class="":配置工厂类的全局限定名

1
2
3
4
5
6
7
<?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">

<bean id="userDao" class="com.factory.UserDaoFactory"/>

</beans>

bean的生命周期

  • 初始化容器 -> 使用bean -> 关闭/销毁容器
    • 初始化容器:创建对象 -> 执行构造方法 -> 执行属性注入(执行set()方法)-> 执行bean的初始化方法
    • 使用bean:执行业务操作
    • 关闭/销毁容器:执行销毁方法

手动配置生命周期方法

定义bean的生命周期方法

  • 在类中定义一个用于初始化的方法,方法名任意,这个方法期望在bean对象创建后执行
  • 在类中定义一个用于销毁的方法,方法名任意,这个方法期望在bean对象销毁前执行
src/main/java/com/dao/UserDao.java
1
2
3
4
5
6
7
8
9
10
11
public class UserDao {

public void init() {
System.out.println("userDao.init()");
}

public void destroy() {
System.out.println("userDao.destroy()");
}

}

修改bean配置

init-method="":指定初始化方法的方法名
destroy-method="":指定销毁方法的方法名

src/main/resources/applicationContext.xml
1
2
3
4
5
6
7
<?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">

<bean id="userDao" class="com.dao.UserDao" init-method="init" destroy-method="destroy"/>

</beans>
关于销毁方法遇到的问题
  • 正常情况下,destroy()方法不会被执行,因为关闭程序时JVM会直接关闭,所以不会执行destroy()方法
  • 如果想要执行 destroy()方法`,可以手动关闭Spring容器或注册关闭钩子
手动关闭Spring容器
  • 通过ClassPathXmlApplicationContext类中的close()方法关闭Spring容器,这种方式比较暴力
  • 手动关闭Spring容器的方法只能在程序运行结束的位置添加
1
2
3
4
5
6
public class Application {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
applicationContext.close();
}
}
注册关闭钩子
  • 通过ClassPathXmlApplicationContext类中的registerShutdownHook()方法来注册关闭钩子
  • 注册关闭钩子的方法可以在任意位置添加
1
2
3
4
5
6
public class Application {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
applicationContext.registerShutdownHook();
}
}

自动配置生命周期方法

定义bean的生命周期方法

  • 在类中实现InitializingBean接口,并重写afterPropertiesSet()方法,在方法中定义bean对象set()方法执行之后执行的操作
  • 在类中实现DisposableBean接口,并重写destroy()方法,在方法中定义bean对象销毁前执行的操作
src/main/java/com/dao/UserDao.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.dao;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

public class UserDao implements InitializingBean, DisposableBean {

public void afterPropertiesSet() throws Exception {
System.out.println("userDao.afterPropertiesSet()");
}

public void destroy() throws Exception {
System.out.println("userDao.destroy()");
}
}

修改bean配置

  • 不需要额外配置
1
2
3
4
5
6
7
<?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">

<bean id="userDao" class="com.dao.UserDao"/>

</beans>

Spring读取properties文件

  • 以Druid为例

创建properties配置文件

  • 将抽离的变量存放在properties配置文件中
src/main/resources/druid.properties
1
2
3
4
url.driverClassName=com.mysql.cj.jdbc.Driver
url.url=jdbc:mysql:///demo
url.username=
url.password=

创建xml配置文件

  1. 创建Spring配置文件,并修改<beans></beans>中的属性,开启context命名空间
  2. 使用context空间加载properties文件
  3. 将Spring配置文件中定义的值改为属性占位符${}

<context:property-placeholder/>

location="":指定properties的文件路径,相对路径的根目录是src/main/resources

location="<properties_file_1>,<properties_file_2>":引入多个配置文件时,用逗号隔开
location="*.properties":引入全部

location="classpath:*.properties":从当前项目中(缺省值),引入全部
location="classpath*:*.properties":从当前项目和引入的jar包中,引入全部

system-properties-mode="":系统属性模式

NEVER:不加载系统属性

src/main/resources/applicationContext.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?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
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">

<context:property-placeholder location="classpath*:*.properties" system-properties-mode="NEVER"/>

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${url.driverClassName}" />
<property name="url" value="${url.url}" />
<property name="username" value="${url.username}" />
<property name="password" value="${url.password}" />
</bean>

</beans>

容器的操作

容器的加载

通过类路径加载配置文件

  • 相对路径的根目录是src/main/resources,多个配置文件用逗号隔开
1
2
3
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml", "applicationContext.xml");

通过文件系统路径加载配置文件

  • 相对路径的根目录是项目的根目录,多个配置文件用逗号隔开
1
2
3
ApplicationContext applicationContext = new FileSystemXmlApplicationContext("src/main/resources/applicationContext.xml");

ApplicationContext applicationContext = new FileSystemXmlApplicationContext("src/main/resources/applicationContext.xml", "src/main/resources/applicationContext.xml");
  • 也可以使用绝对路径引入
1
2
3
ApplicationContext applicationContext = new FileSystemXmlApplicationContext("/root/applicationContext.xml");

ApplicationContext applicationContext = new FileSystemXmlApplicationContext("/root/applicationContext.xml", "/root/applicationContext.xml");

容器中获取bean对象

获取Object类型bean对象

  • 获取Object类型bean对象,可以强制类型转换
1
DataSource dataSource = (DataSource) applicationContext.getBean("dataSource");

获取指定类型的bean对象

1
DataSource dataSource = applicationContext.getBean("dataSource", DataSource.class);

按照类型自动获取bean对象

  • 指定的类型在容器中必须只有唯一的bean对象
1
DataSourc e dataSource = applicationContext.getBean(DataSource.class);

BeanFactory

  • 旧版本Spring容器使用的是BeanFactory类型的对象

Object.class:根据数据类型获取bean对象

1
2
3
Resource resource = new ClassPathResource("applicationContext.xml");
BeanFactory beanFactory = new XmlBeanFactory(resource);
Object obj = beanFactory.getBean(Object.class);
  • 区别
    • ApplicationContext默认是立即加载bean,立即执行构造方法
    • BeanFactory默认是延迟加载bean,延迟执行构造方法

bean的相关配置

id="":定义bean的名称
name="":定义bean的别名,多个别名之间可以用逗号、分号、空格分隔
class="":定义bean的类型
scope="":定义bean的作用范围

singleton:缺省值,单例的
prototype:非单例的

init-method="":指定生命周期的初始化方法的方法名
destory-method="":指定生命周期的销毁方法的方法名
autowire="":指定自动装配方式

byType:按类型
byName:按名称
constructor:使用构造方法
default:默认
no:不使用自动装配

factory-bean="":指定实例工厂bean的id
factory-method="":指定bean工厂方法的方法名,通常用于静态工厂或实例工厂
lazy-init="":ApplicationContext实现延迟加载

true:开启延迟加载
false:缺省值,关闭延迟加载

src/main/resources/applicationContext.xml
1
2
3
4
5
6
7
8
9
10
11
12
<bean
id=""
name=""
class=""
scope=""
init-method=""
destroy-method=""
autowire=""
factory-method=""
factory-bean=""
lazy-init=""
/>

异常

No Such B ean Definition Exception

  • NoSuchBeanDefinitionException:没找到bean定义,获取bean对象时指定的bean名称与xml中配置的bean名称不相同
  • BeanCreateException:bean创建异常,无参构造不存在导致bean对象创建失败

完成

参考文献

哔哩哔哩——黑马程序员