一、自动装配(了解即可)
1. 代码实现
(1) 项目中添加BookDao、BookDaoImpl、BookService和BookServiceImpl类
java
public interface BookDao {
public void save();
}
public class BookDaoImpl implements BookDao {
private String databaseName;
private int connectionNum;
public void save() {
System.out.println("book dao save ...");
}
}
public interface BookService {
public void save();
}
public class BookServiceImpl implements BookService{
private BookDao bookDao;
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
(2) resources下提供spring的配置文件
XML
<bean class="com.itheima.dao.impl.BookDaoImpl"/>
<!--autowire属性:开启自动装配,通常使用按类型装配-->
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl" autowire="byType"/>
</beans>
核心逻辑: 按类型(byType)自动装配时,Spring 匹配的 "类型" 是什么
① 先找到 "要注入的成员变量",在 BookServiceImpl 类里,有一个需要注入的成员变量:
java
public class BookServiceImpl implements BookService {
// 这个成员变量的类型是 BookDao
private BookDao bookDao;
// 必须有 setter 方法(自动装配 byType/byName 都依赖 setter)
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
}
这里的关键是:成员变量 bookDao 声明的类型是 BookDao(接口),这就是 Spring 要去匹配的 "目标类型"。
② Spring 会做这几件事:
- 检查
BookServiceImpl里所有需要注入的成员变量(这里就是bookDao)。 - 拿到它的类型:
BookDao。 - 去整个 IoC 容器里,找所有类型是
BookDao或其子类 / 实现类的 bean。 - 如果找到恰好 1 个 ,就自动调用
setBookDao()把它注入进去; - 如果找到 0 个或多个,就报错(0 个注入失败,多个报
NoUniqueBeanDefinitionException)。
二、集合注入(了解即可)
1. 代码实现
(1) 注入数组类型数据
XML
<property name="array">
<array>
<value>100</value>
<value>200</value>
<value>300</value>
</array>
</property>
(2) 注入List类型数据
XML
<property name="list">
<list>
<value>itcast</value>
<value>itheima</value>
<value>boxuegu</value>
<value>chuanzhihui</value>
</list>
</property>
(3) 注入Map类型数据
XML
<property name="map">
<map>
<entry key="country" value="china"/>
<entry key="province" value="henan"/>
<entry key="city" value="kaifeng"/>
</map>
</property>
(4) 注入Properties类型数据
XML
<property name="properties">
<props>
<prop key="country">china</prop>
<prop key="province">henan</prop>
<prop key="city">kaifeng</prop>
</props>
</property>
三、IoC / DI 配置管理第三方bean
1. 思路分析
(1) 使用第三方的技术,需要在pom.xml添加依赖
(2) 在配置文件中将【第三方的类】制作成一个bean,让IoC容器进行管理
(3) 数据库连接需要基础的四要素驱动、连接、用户名和密码,【如何注入】到对应的bean中
(4) 从IoC容器中获取对应的bean对象,将其打印到控制台查看结果
2. 代码实现
(1) 导入druid的依赖
XML
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
(2) 配置第三方bean
XML
<!--管理DruidDataSource对象-->
<bean class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/spring_db"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
</beans>
说明:
-
driverClassName:数据库驱动
-
url:数据库连接地址
-
username:数据库连接用户名
-
password:数据库连接密码
-
数据库连接的四要素要和自己使用的数据库信息一致。
3. 加载properties文件
(1) 思路分析
① 在resources下创建一个jdbc.properties(文件的名称可以任意)
② 将数据库连接四要素配置到配置文件中
③ 在Spring的配置文件中加载properties文件
④ 使用加载到的值实现属性注入
其中第3,4步骤是需要大家重点关注,具体是如何实现。
(2) 代码实现
① 准备properties配置文件
resources下创建一个jdbc.properties文件,并添加对应的属性键值对
XML
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/spring_db
jdbc.username=root
jdbc.password=root
② 开启context命名空间
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"
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">
</beans>
③ 加载properties配置文件
在配置文件中使用context命名空间下的标签来加载properties配置文件
XML
<context:property-placeholder location="jdbc.properties"/>
④ 完成属性注入
XML
<context:property-placeholder location="jdbc.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
</beans>
4. 读取单个属性
(1) 思路分析
① 在项目中添加BookDao和BookDaoImpl类
② 为BookDaoImpl添加一个name属性并提供setter方法
③ 在jdbc.properties中添加数据注入到bookDao中打印方便查询结果
④ 在applicationContext.xml添加配置完成配置文件加载、属性注入(${key})
(2) 代码实现
① 在项目中添对应的类
BookDao和BookDaoImpl类,并在BookDaoImpl类中添加name属性与setter方法
java
public interface BookDao {
public void save();
}
public class BookDaoImpl implements BookDao {
private String name;
public void setName(String name) {
this.name = name;
}
public void save() {
System.out.println("book dao save ..." + name);
}
}
② 完成配置文件的读取与注入
XML
<context:property-placeholder location="jdbc.properties"/>
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
<property name="name" value="${jdbc.driver}"/>
</bean>
</beans>
**(3)**当有多个properties配置文件需要被加载,该如何配置?
XML
<!--方式一 -->
<context:property-placeholder location="jdbc.properties,jdbc2.properties" system-properties-mode="NEVER"/>
<!--方式二-->
<context:property-placeholder location="*.properties" system-properties-mode="NEVER"/>
<!--方式三 -->
<context:property-placeholder location="classpath:*.properties" system-properties-mode="NEVER"/>
<!--方式四-->
<context:property-placeholder location="classpath*:*.properties" system-properties-mode="NEVER"/>
</beans>
说明:
-
方式一:可以实现,如果配置文件多的话,每个都需要配置
-
方式二:
*.properties代表所有以properties结尾的文件都会被加载,可以解决方式一的问题,但是不标准 -
方式三:标准的写法,
classpath:代表的是从根路径下开始查找,但是只能查询当前项目的根路径 -
方式四:不仅可以加载当前项目还可以加载当前项目所依赖的所有项目的根路径下的properties配置文件
四、核心容器
1. Bean的三种获取方式
(1) 方式一:
java
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
这种方式存在的问题是每次获取的时候都需要进行类型转换
(2) 方式二:
java
BookDao bookDao = ctx.getBean("bookDao",BookDao.class);
这种方式可以解决类型强转问题,但是参数又多加了一个,相对来说没有简化多少。
(3) 方式三:
java
BookDao bookDao = ctx.getBean(BookDao.class);
这种方式就类似我们之前所学习依赖注入中的按类型注入。必须要确保IoC容器中该类型对应的bean对象只能有一个。
2. BeanFactory的使用(了解即可)
(1) 使用BeanFactory来创建IoC容器的具体实现方式为
java
public class AppForBeanFactory {
public static void main(String[] args) {
Resource resources = new ClassPathResource("applicationContext.xml");
BeanFactory bf = new XmlBeanFactory(resources);
BookDao bookDao = bf.getBean(BookDao.class);
bookDao.save();
}
}
(2) BeanFactory 和 ApplicationContext 之间的区别
-
BeanFactory是延迟加载,只有在获取bean对象的时候才会去创建
-
ApplicationContext是立即加载,容器加载的时候就会创建bean对象
-
ApplicationContext要想成为延迟加载,只需要按照如下方式进行配置
XML
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" lazy-init="true"/>
</beans>
五、IOC / DI 注解开发
1. 注解开发定义bean
(1) 代码实现
① 删除原XML配置
XML
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
② Dao上添加注解
在BookDaoImpl类上添加@Component注解
java
@Component("bookDao")
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ..." );
}
}
注意:@Component注解不可以添加在接口上,因为接口是无法创建对象的。
XML与注解配置的对应关系:

③ 配置Spring的注解包扫描
为了让Spring框架能够扫描到写在类上的注解,需要在配置文件上进行包扫描
XML
<context:component-scan base-package="com.itheima"/>
</beans>
说明:
component-scan
-
component:组件,Spring将管理的bean视作自己的一个组件
-
scan:扫描
base-package指定Spring框架扫描的包路径,它会扫描指定包及其子包中的所有类上的注解。
-
包路径越多[如:com.itheima.dao.impl],扫描的范围越小速度越快
-
包路径越少[如:com.itheima],扫描的范围越大速度越慢
-
一般扫描到项目的组织名称即Maven的groupId下[如:com.itheima]即可。
④ Service上添加注解
在BookServiceImpl类上也添加@Component交给Spring框架管理
java
@Component
public class BookServiceImpl implements BookService {
private BookDao bookDao;
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
(2) @Component 及其衍生注解
| 名称 | @Component/@Controller/@Service/@Repository |
|---|---|
| 类型 | 类注解 |
| 位置 | 类定义上方 |
| 作用 | 设置该类为spring管理的bean |
| 属性 | value(默认):定义bean的id |
2. 纯注解开发模式
(1) 思路分析
- 将配置文件applicationContext.xml删除掉,使用类来替换。
(2) 代码实现
① 创建配置类
创建一个配置类SpringConfig
java
public class SpringConfig {
}
② 标识该类为配置类
在配置类上添加@Configuration注解,将其标识为一个配置类,替换applicationContext.xml
java
@Configuration
public class SpringConfig {
}
③ 用注解替换包扫描配置
在配置类上添加包扫描注解@ComponentScan替换<context:component-scan base-package=""/>
java
@Configuration
@ComponentScan("com.itheima")
public class SpringConfig {
}
④ 创建运行类并执行
java
public class AppForAnnotation {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
System.out.println(bookDao);
BookService bookService = ctx.getBean(BookService.class);
System.out.println(bookService);
}
}
(3) 执行流程
① 配置类的作用(替代 xml 文件)
java
@Configuration
@ComponentScan("com.itheima")
public class SpringConfig {
}
@Configuration注解:相当于给这个类贴上**"Spring 核心配置文件" 的标签,告诉 Spring 框架:"这个类不是普通的 Java 类,它是用来替代原来的 applicationContext.xml 的配置类"**@ComponentScan("com.itheima")注解:告诉 Spring"去com.itheima这个包(包括子包)里找所有带@Component/@Service/@Repository的类"
② 运行类的执行流程(核心)
java
public class AppForAnnotation {
public static void main(String[] args) {
// 1. 初始化Spring容器,加载配置类
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
// 2. 从容器中获取BookDao对象
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
System.out.println(bookDao);
// 3. 从容器中获取BookService对象
BookService bookService = ctx.getBean(BookService.class);
System.out.println(bookService);
}
}
逐行拆解执行逻辑:
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
- 第一步:识别
SpringConfig类上的@Configuration注解,确认这是核心配置类; - 第二步:读取
@ComponentScan("com.itheima"),去指定包下扫描所有带注解的类(比如BookDao带@Repository、BookService带@Service); - 第三步:自动创建这些类的实例(对象),并把对象存入 Spring 的 "容器"(ApplicationContext)中管理
(4) @Configuration、@ComponentScan
知识点1:@Configuration
| 名称 | @Configuration |
|---|---|
| 类型 | 类注解 |
| 位置 | 类定义上方 |
| 作用 | 设置该类为spring配置类 |
| 属性 | value(默认):定义bean的id |
知识点2:@ComponentScan
| 名称 | @ComponentScan |
|---|---|
| 类型 | 类注解 |
| 位置 | 类定义上方 |
| 作用 | 设置spring配置类扫描路径,用于加载使用注解格式定义的bean |
| 属性 | value(默认):扫描路径,此路径可以逐层向下扫描 |
六、注解开发依赖注入
1. 注解实现按照名称注入
(1) 当根据类型在容器中找到多个bean,注入参数的属性名又和容器中bean的名称不一致,这个时候该如何解决,就需要使用到@Qualifier来指定注入哪个名称的bean对象。
java
@Service
public class BookServiceImpl implements BookService {
@Autowired
@Qualifier("bookDao1")
private BookDao bookDao;
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
@Qualifier注解后的值就是需要注入的bean的名称。
注意:@Qualifier不能独立使用,必须和@Autowired一起使用
2. 简单数据类型注入
(1) 使用@Value注解,将值写入注解的参数中
java
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
@Value("itheima")
private String name;
public void save() {
System.out.println("book dao save ..." + name);
}
}
(2) 注解读取properties配置文件
@Value一般会被用在从properties配置文件中读取内容进行使用
① resource下准备properties文件
jdbc.properties
java
name=itheima888
② 使用注解加载properties配置文件
在配置类上添加@PropertySource注解
java
@Configuration
@ComponentScan("com.itheima")
@PropertySource("jdbc.properties")
public class SpringConfig {
}
③ 使用@Value读取配置文件中的内容
java
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
@Value("${name}")
private String name;
public void save() {
System.out.println("book dao save ..." + name);
}
}
七、注册开发管理第三方bean
1. 注解开发管理第三方bean
(1) 代码实现
① 在配置类中添加一个方法(后续里面的数据库信息会用另外一个类承接)
注意该方法的返回值就是要创建的Bean对象类型
java
@Configuration
public class SpringConfig {
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
ds.setUsername("root");
ds.setPassword("root");
return ds;
}
}
DataSource 是 javax.sql 包下的一个接口,它是 Java 官方定义的 "数据源" 标准规范,核心作用是:
- 统一管理数据库连接(替代传统的
DriverManager) - 支持连接池技术,复用数据库连接,提升性能
② 在方法上添加@Bean注解
@Bean注解的作用是将方法的返回值制作为Spring管理的一个bean对象
java
@Configuration
public class SpringConfig {
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
ds.setUsername("root");
ds.setPassword("root");
return ds;
}
}
2. 引入外部配置类
(1) 使用@Import引入
这种方案可以不用加@Configuration注解,但是必须在Spring配置类上使用@Import注解手动引入需要加载的配置类
① 去除JdbcConfig类上的注解
java
public class JdbcConfig {
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
ds.setUsername("root");
ds.setPassword("root");
return ds;
}
}
② 在Spring配置类中引入
java
@Configuration
//@ComponentScan("com.itheima.config")
@Import({JdbcConfig.class})
public class SpringConfig {
}
七、注解开发实现为第三方bean注入资源
1. 简单数据类型
(1) 代码实现
① 类中提供四个属性
java
public class JdbcConfig {
private String driver;
private String url;
private String userName;
private String password;
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
ds.setUsername("root");
ds.setPassword("root");
return ds;
}
}
② 使用@Value注解引入值
java
public class JdbcConfig {
@Value("com.mysql.jdbc.Driver")
private String driver;
@Value("jdbc:mysql://localhost:3306/spring_db")
private String url;
@Value("root")
private String userName;
@Value("password")
private String password;
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);
ds.setPassword(password);
return ds;
}
}
2. 引用数据类型
(1) 需求分析
假设在构建DataSource对象的时候,需要用到BookDao对象,该如何把BookDao对象注入进方法内让其使用呢?
(2) 代码实现
① 在SpringConfig中扫描BookDao
扫描的目的是让Spring能管理到BookDao,也就是说要让IoC容器中有一个bookDao对象
java
@Configuration
@ComponentScan("com.itheima.dao")
@Import({JdbcConfig.class})
public class SpringConfig {
}
② 在JdbcConfig类的方法上添加参数
java
@Bean
public DataSource dataSource(BookDao bookDao){
System.out.println(bookDao);
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);
ds.setPassword(password);
return ds;
}
(3) 执行流程
① 识别 SpringConfig 上的 @Configuration,确认这是主配置。
② 执行 @ComponentScan("com.itheima.dao"):
- 去
com.itheima.dao包下扫描,找到BookDaoImpl(它上面有@Repository或@Component注解)。 - 自动创建
BookDaoImpl对象,作为bookDaoBean 存入 IoC 容器。
③ 执行 @Import(JdbcConfig.class):
- 主动加载
JdbcConfig类,准备解析它里面的@Bean方法。
④ Spring 发现这个方法需要一个 BookDao 类型的参数。
⑤ 它会去 IoC 容器中查找:"有没有类型为 BookDao 的 Bean?"找到之前扫描创建的 bookDao 对象,确认可以作为参数传入。