本文将介绍Spring的框架和本体内容,包括核心容器、注释开发、AOP和事务等。
所以简单说明一下Spring的必要性:
- Spring技术是JavaEE开发的必备技能,企业开发技术选型率高达90%!
- Spring有助于简化发展,降低企业级发展的复杂性
- Spring可以整合框架,有效整合其他技术,提高企业应用开发和运营效率
Spring的核心内容:
- Ioc技术
- DI技术
- AOP
- 事务处理
Spring可以进行框架集成:
- MaBatis
- MyBatis-plus
- Struts
- Struts2
- Hibernate
在下一篇文章中,我们将学习Spring的框架思想,学习Spring的基本操作,并结合案例掌握它
初识Spring温馨提醒:在学习本文之前,请先学习Javaweb的相关内容
(HTTP,Tomcat,Servlet,Request,Response,MVC,Cookie,Session,Ajax,Vue等内容)
官网:Spring | Home
Spring的发展已经形成了一个开发生态系统,Spring提供了相当多的项目,每个项目都用于完成特定的功能
常用的主流技术包括:
- Spring Framework:Spring框架
- Spring Boot:Spring简化代码开发
- Spring Cloud:Spring分布设计
在系统学习Spring之前,我们需要了解FrameWork系统的结构
- Spring Framework是Spring生态系统中最基本的项目,也是其他项目的基础
我们现在使用的Spring FrameWork是4.0版,已经趋于稳定
下面我们来解释一下架构图:
- Core Container:核心容器
- AOP:面向切面编程
- Aspects:实现AOP思想
- Data Access:数据访问
- Data Intergration:数据集成
- Web:Web开发
- Test:单元测试与集成测试
我们可以在官方中得到这样的评价:
- 强大的基于 JavaBeans 采用控制反转(Inversion of Control,IoC)原则的配置管理使应用程序的构建更加快捷简单。
- 数据库事务的一般抽象层允许插件式事务管理器简化事务的划分,使其与底层无关。
- 一个可以用于从 applet 到 Java EE 不同运行环境的核心等 Bean 工厂。
首先,让我们考虑一下我们以前的业务层和数据层:
// publicic数据层接口 interface BookDao { public void save();}
// publicic实现数据层的public class BookDaoImpl implements BookDao { public void save() { System.out.println("book dao save ..."); }}
// 业务层接口publiclicclic interface BookService { public void save();}
// 业务层实现publicliccp class BookServiceImpl implements BookService { private BookDao bookDao; public void save() { bookDao.save(); }}
如果我们修改BookDaoimpl内容,也应修改相应业务层实现中BookDao的new实现,甚至修改以下方法的对象
使用Spring前的问题代码书写现状:
- 耦合度偏高
解放方案:
- 使用对象时,不要在程序中主动使用new生成对象,并将其转换为从外部提供的对象
IoC(Inversion of Control)控制反转思想:
- 使用对象时,由主动new创建对象转换为外部提供对象
- 在此过程中,对象创建的控制权由程序转移到外部,称为控制反转
DI(Dependency Injection)依赖注入:
- 在容器中建立Bean和Bean之间的依赖关系和整个过程,称为依赖注入
Spring技术实现了Ioc思想:
- Spring提供了一个被称为物联网容器的容器,用作物联网思想的外部
- 物联网容器负责创建、初始化等一系列工作。物联网容器中创建和管理的对象称为Bean
// 实现public实现public class BookDaoImpl implements BookDao { public void save() { System.out.println("book dao save ..."); }}
// 包含daoservice的IoC容器/*可以建立连接*/
// 实现public实现public class BookServiceImpl implements BookService { private BookDao bookDao; public void save() { bookDao.save(); }}
目的:完全解耦
- IoC:使用IOC容器管理beann
- DI:在IOC容器中绑定依赖关系的bean
最终效果:
- 使用对象不仅可以直接从物联网容器中获得,还可以绑定已获得的Bean之间的依赖关系
首先,我们需要了解物联网的使用规则:
- IoC负责管理什么:Service和Dao
- 物联网容器是如何被管理对象告知的:(配置)
- 如何将管理对象交给物联网容器:(接口)
- 获得IoC容器后,如何获得Bean?:(接口方法)
- 使用Spring所需导入的坐标:(pom.xml)
以下是物联网入门的详细步骤:
- 在pommm创建Maven项目.将坐标导入xml
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.10.RELEASE</version> </dependency> </dependencies>
- 创建Spring.xml配置包(applicationContext.xml,XML在导入坐标后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 http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--2.配置bean--> <!--bean标签标签配置bean标签配置bean标签配置 id属性标记为bean命名 class属性表示bean定义类型(注意需要实现类)--> <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/> <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl"/></beans>
- 主函数
package com.itheima;import com.itheima.dao.BookDao;import com.itheima.service.BookService;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class App2 { public static void main(String[] args) { //3获取IoC容器 ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); //4.获取bean(根据bean配置id获取)///BookDao bookDao = (BookDao) ctx.getBean("bookDao");//bookDao.save(); // 注:需要类型转换 BookService bookService = (BookService) ctx.getBean("bookService"); bookService.save(); }}
DI入门首先需要了解DI的使用规则:
- bean基于IOC管理
- 使用new形式在Service中创建Dao对象是否保留:(否)
- 要求Dao对象在Service中进入Service:(提供方法)
- 如何描述Service和Dao之间的关系:(配置)
以下是DI入门的详细步骤(基于IOC入门):
- 删除new方法
public class BookServiceImpl implements BookService { //5.删除业务层中使用new创建的dao对象 private BookDao bookDao; public void save() { System.out.println("book service save ..."); bookDao.save(); }}
- 创建对象的set方法
public class BookServiceImpl implements BookService { //5.删除业务层中使用new创建的dao对象 private BookDao bookDao; public void save() { System.out.println("book service save ..."); bookDao.save(); } //6.提供相应的set方法 public void setBookDao(BookDao bookDao) { this.bookDao = bookDao; }}
- 创建Dao和Service之间的连接
<?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"> <!--2.配置bean--> <!--bean标签标配bean id属性标记为bean命名 class属性表示bean定义类型--> <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/> <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl"> <!--7.配置server与dao的关系--> <!--注:在server中配置关系property标签表示配置当前bean的属性 name属性表示配置的具体属性 ref属性表示参考哪个bean?--> <property name="bookDao" ref="bookDao"/> </bean></beans>
Bean整体介绍Bean是物联网中保存的对象,我们通过配置获得Bean
让我们从三个方面来解释Bean。:
bean基本配置首先我们先介绍一下bean本身的性质:
类别
描述
名称
bean
类型
标签
所属
beans标签
功能
Spring核心容器管理对象的定义
格式
<beans><bean> </bean></beans>
属性列表
id:bean的id,在一个容器中,id值唯一的classs可以通过id值获得相应的bean:bean的类型,即配置bean的全路径类名
范例
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
然后我们来介绍一下bean的别名:
类别
描述
名称
name
类型
标签
所属
bean标签
功能
定义bean的别名,可以定义多个,使用逗号,分号,空格分隔
范例
<bean id="bookService" name="service service4 bookEbi" class="com.itheima.service.impl.BookServiceImpl">
一般情况下,使用id和name都可以获得bean,但是建议使用唯一的id
无论是通过id还是name获得bean,如果找不到bean,就抛出异常NosuchbeanDefinitionException。
最后,我们来介绍一下bean的作用范围scope:
类别
描述
名称
scope
类型
标签
所属
bean标签
功能
定义bean的作用范围,可选范围如下:singleton:单独列(默认)prototype:非单列
范例
<bean id="bookDao" name="dao" class="com.itheima.dao.impl.BookDaoImpl" scope="prototype"/>
bean实例化这里的scope是指生成对象的数量
默认情况下,我们的scope是singleton,因为许多对象只需要创建一次,多次创建会导致内存膨胀。
bean适合交给容器进行管理(singleton):
业务层对象数据层对象对象的对象
bean不适合交给容器进行管理(prototype):
包装实体的域对象(带状态的bean)
bean的实例化通常分为四种方法,我们在下面逐一介绍:
- 结构方法(常用)
在配置条件下,我们需要在数据类中提供结构方法
// public数据类 class BookDaoImpl implements BookDao { public BookDaoImpl() { System.out.println("book dao constructor is running ..."); } public void save() { System.out.println("book dao save ..."); }}
<?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"> <!--方法一:构造方法实例化beann--> <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/></beans>
如果不存在参结构方法,则抛出异常Beancreationexception
- 静态工厂(理解)
在之前的案例中,我们有一个对象工厂的说法,我们可以设立工厂,并调用它的方法来获得bean
// 静态工厂package com.itheima.factory;import com.itheima.dao.OrderDao;import com.itheima.dao.impl.OrderDaoImpl;/////静态工厂创建对象publiccicc class OrderDaoFactory { public static OrderDao getOrderDao(){ System.out.println("factory setup..."); return new OrderDaoImpl(); }}
<?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"> <!--方法二:使用静态工厂实例beann--> <bean id="orderDao" class="com.itheima.factory.OrderDaoFactory" factory-method="getOrderDao"/></beans>
- 实例工厂(理解)
和静态工厂一样,但不同的是方法不是静态的,我们需要提前创建一个bean
// 实例工厂package com.itheima.factory;import com.itheima.dao.UserDao;import com.itheima.dao.impl.UserDaoImpl;///实例工厂创建对象publiccic class UserDaoFactory { public UserDao getUserDao(){ return new UserDaoImpl(); }}
<?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"> <!--方法三:使用实例工厂实例beann--> <bean id="userFactory" class="com.itheima.factory.UserDaoFactory"/> <!--factory-bean:实例工厂本身beanfactory-method:使用调用bean的方法--> <bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/></beans>
- FactoryBean(重要实用)
除了我们之前定义的工厂外,Spring还提供了FactoryBeann的官方版本
// FactoryBean工厂(需要接口,< >填写数据类接口)package com.itheima.factory;import com.itheima.dao.UserDao;import com.itheima.dao.impl.UserDaoImpl;import org.springframework.beans.factory.FactoryBean;///FactoryBean创建对象publiciciccictictic class UserDaoFactoryBean implements FactoryBean<UserDao> { //替换原始实例工厂中创建对象的方法 // UserDaoImpl()返回创建对象类型 public UserDao getObject() throws Exception { return new UserDaoImpl(); } // 这里填写接口类型 public Class<?> getObjectType() { return UserDao.class; } // 可修改scope属性 public boolean isSingleton() { return false; }}
<?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"> <!--方法四:使用FactoryBean实例bean--> <bean id="userDao" class="com.itheima.factory.UserDaoFactoryBean"/></beans>
bean生命周期先接单介绍生命周期的相关概念:
- 生命周期:从创造到消亡的完整过程
- bean生命周期:bean从创建到销毁的整个过程
- bean生命周期控制:在bean创建后到销毁前做点什么
接下来,我们将介绍生命周期控制方法:
- 数据层提供控制方法
在xml配置文件中设置由数据层提供的方法
// package数据层 com.itheima.dao.impl;import com.itheima.dao.BookDao;public class BookDaoImpl implements BookDao { public void save() { System.out.println("book dao save ..."); } ///表示bean初始化对应的操作 public void init(){ System.out.println("init..."); } ///表示bean销毁前相应的操作 public void destory(){ System.out.println("destory..."); }}
<!--配置文件--><?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"> <!--init-method:设置bean初始生命周期回调函数--> <!--destroy-method:设置bean销毁生命周期回调函数,仅适用于单例对象--> <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/> <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl"> <property name="bookDao" ref="bookDao"/> </bean></beans>
- 接口控制方法(理解)
Spring为创建提供了两个接口,我们只需要继承和实现这种方法
package com.itheima.service.impl;import com.itheima.dao.BookDao;import com.itheima.service.BookService;import org.springframework.beans.factory.DisposableBean;import org.springframework.beans.factory.InitializingBean;// InitializingBean,DisposableBean 分别对应afterPropertiesset和destroy方法,代表public的创建和销毁 class BookServiceImpl implements BookService, InitializingBean, DisposableBean { private BookDao bookDao; public void setBookDao(BookDao bookDao) { System.out.println("set ..."); this.bookDao = bookDao; } public void save() { System.out.println("book service save ..."); bookDao.save(); } public void destroy() throws Exception { System.out.println("service destroy"); } public void afterPropertiesSet() throws Exception { System.out.println("service init"); }}
<?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="bookDao" class="com.itheima.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/> <!--直接调用即可--> <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl"> <property name="bookDao" ref="bookDao"/> </bean></beans>
我们需要提到bean的销毁时机:(了解)
- 因为默认情况下,我们的bean不会被销毁,因为虚拟机会直接退出,claspathXmlaplicationcontext将被忽略
因此,要想销毁bean观察到destroy的实现,就需要手动关闭:
- 手动关闭容器方法:
package com.itheima;import com.itheima.dao.BookDao;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class AppForLifeCycle { public static void main( String[] args ) { // 注:以ClaspathXmlaplicationcontext为对象,因为只有这一类才有close方法 ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); BookDao bookDao = (BookDao) ctx.getBean("bookDao"); bookDao.save(); ///关闭容器 ctx.close(); }}
- 注册关闭钩子,在虚拟机退出前关闭容器,然后启动虚拟机
package com.itheima;import com.itheima.dao.BookDao;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class AppForLifeCycle { public static void main( String[] args ) { ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); BookDao bookDao = (BookDao) ctx.getBean("bookDao"); bookDao.save(); //注册关闭钩子函数,在虚拟机退出之前对此函数进行回调,关闭容器 ctx.registerShutdownHook(); }}
依赖于注入方式最后统计一下整个生命周期:
初始化容器:创建对象(内存分配)->实施结构方法->执行属性注入(set操作)->使用bean执行bean初始方法:执行业务操作关闭/销毁容器:执行bean销毁方法
首先,我们需要知道有两种方法可以在类中传输数据:
- 普通方法(Set)
- 构造方法
然后我们应该知道,数据的类型一般分为两种:
- 引入类型(数据层)
- 简单类型(基本数据类型和String)
因此,我们将依赖注入分为四种方式:
- 注入简单类型的setter引用类型
- 注入简单类型的介绍类型的结构器
首先,我们需要在bean中定义简单的类型属性,并提供可访问的set方法
package com.itheima.dao.impl;import com.itheima.dao.BookDao;public class BookDaoImpl implements BookDao { private String databaseName; private int connectionNum; ///setter注入需要为注入对象提供set方法 public void setConnectionNum(int connectionNum) { this.connectionNum = connectionNum; } ///setter注入需要为注入对象提供set方法 public void setDatabaseName(String databaseName) { this.databaseName = databaseName; } public void save() { System.out.println("book dao save ..."+databaseName+","+connectionNum); }}
然后使用property标签value属性在配置中注入简单的数据类型
<?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="bookDao" class="com.itheima.dao.impl.BookDaoImpl"> <!--注入简单类型--> <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"> <!--property标签:设置注入属性--> <!--name属性:设置注入的属性名,实际上是set方法对应的名称--> <!--value属性:设置注入简单类型的数据值--> <property name="connectionNum" value="100"/> <property name="databaseName" value="mysql"/> </bean></beans>
setter注入引用类型首先,我们需要定义bean中引用的类型属性,并提供可访问的set方法
package com.itheima.service.impl;import com.itheima.dao.BookDao;import com.itheima.dao.UserDao;import com.itheima.service.BookService;public class BookServiceImpl implements BookService{ private BookDao bookDao; private UserDao userDao; //setter注入需要提供需要注入对象的set方法 public void setUserDao(UserDao userDao) { this.userDao = userDao; } //setter注入需要提供需要注入对象的set方法 public void setBookDao(BookDao bookDao) { this.bookDao = bookDao; } public void save() { System.out.println("book service save ..."); bookDao.save(); userDao.save(); }}
然后在配置中使用property标签ref属性注入引用类型数据
<?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="bookDao" class="com.itheima.dao.impl.BookDaoImpl"> <property name="connectionNum" value="100"/> <property name="databaseName" value="mysql"/> </bean> <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/> <!--注入引用类型--> <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl"> <!--注入引用类型--> <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl"> <!--property标签:设置注入属性--> <!--name属性:设置注入的属性名,实际上是set方法对应的名称--> <!--ref属性:设置注入引用类型bean的id或name--> <property name="bookDao" ref="bookDao"/> <property name="userDao" ref="userDao"/> </bean></beans>
注入简单类型的构造器(理解)在bean中定义简单的类型属性并提供可访问的set方法
public class BookDaoImpl implements BookDao{private int connectionNumber; pubilc void setConnectionNumber(int connectionNumber){this.connectionNumber = connectionNumber; }}
constructorarg标签value属性在配置中注入简单类型的数据
<?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="bookDao" class="com.itheima.dao.impl.BookDaoImpl"> 根据结构方法的参数注入名称 <constructor-arg name="connectionNum" value="10"/> </bean> <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/></beans>
引用类型(理解)注入构造器在bean中定义引用类型属性并提供可访问的结构方法
public class BookDaoImpl implements BookDao{private BookBao bookBao; pubilc void setConnectionNumber(int connectionNumber){this.bookBao = bookBao; }}
使用constructorarg标签ref属性在配置中注入简单类型的数据
<?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="bookService" class="com.itheima.service.impl.BookServiceImpl"> <constructor-arg name="userDao" ref="userDao"/> <constructor-arg name="bookDao" ref="bookDao"/> </bean></beans>
参数配置问题(理解)注入构造器我们已经介绍了构造器的注入方法
但是,如果我们在bean中更改数据名称,配置将不再适应,因此提供了一些解决参数配置问题的方法:
- constructorarg标签type属性设置在配置中
<!--解决形参名称问题,与形参名不耦合--> <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"> 根据结构方法的参数类型注入 <constructor-arg type="int" value="10"/> <constructor-arg type="java.lang.String" value="mysql"/> </bean> <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/> <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl"> <constructor-arg name="userDao" ref="userDao"/> <constructor-arg name="bookDao" ref="bookDao"/> </bean>
- constructorarg标签index属性设置在配置中
<!--解决参数类型重复问题,使用位置解决参数匹配问题--> <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"> <!--根据结构方法的参数位置注入--> <constructor-arg index="0" value="mysql"/> <constructor-arg index="1" value="100"/> </bean> <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/> <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl"> <constructor-arg name="userDao" ref="userDao"/> <constructor-arg name="bookDao" ref="bookDao"/> </bean>
依靠注入方式的选择以下选择标准取决于注入方式:
- 强制依靠使用结构器,使用setter注入有可能不注入,导致null对象出现
- 可选依靠使用setter注入,灵活性高
- Spring框架提倡使用结构器,大多数第三方框架以结构器注入的形式初始化数据,相对严格
- 如有必要,可以两者并用,用结构器注入强制依赖注入,用setter注入可选依赖注入
- 在实际开发中,根据情况分析,如果受控对象没有提供setter方法,则只能使用构造器注入
- 尽量推荐settter注入自己开发的模块
之前我们已经学会了手动注射的方法,但是Spring实际上为我们提供了一种依赖自动装配的语法:
- 根据bean所依赖的资源,物联网容器在容器中自动搜索并注入bean的过程称为自动组装
自动装配方式:
- 按类型(常用)按类型(常用)
- 按名称
- 按构造方法
- 不启用
自动装配语法:
<?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 class="com.itheima.dao.impl.BookDaoImpl"/> <!--autowire属性:开启自动装配,通常使用按类型装配--> <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl" autowire="byType"/></beans>
依靠集合注入依靠自动装配的特点:
自动组装用于注入引用类型,不能按类型操作简单类型(byType)必须保证容器中相同类型的bean是唯一的,建议按名称组装时使用(byName)必须确保容器中有指定名称的bean。由于变量名与配置耦合,不建议使用低于setter注入和构造器注入的自动组装优先级。同时出现时,自动装配配置失效
除了基本类型和介绍类型外,我们有时还需要注入集合
下面我们简单介绍一下结合注入:
// 数据类 package com.itheima.dao.impl;import com.itheima.dao.BookDao;import java.util.*;public class BookDaoImpl implements BookDao { private int[] array; private List<String> list; private Set<String> set; private Map<String,String> map; private Properties properties; public void setArray(int[] array) { this.array = array; } public void setList(List<String> list) { this.list = list; } public void setSet(Set<String> set) { this.set = set; } public void setMap(Map<String, String> map) { this.map = map; } public void setProperties(Properties properties) { this.properties = properties; } public void save() { System.out.println("book dao save ..."); System.out.println(“遍历数组:” + Arrays.toString(array)); System.out.println(“遍历List” + list); System.out.println(“遍历Set” + set); System.out.println(“遍历Map” + map); System.out.println(“遍历Properties” + properties); }}
<!--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 http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"> <!--数组注入--> <!--注意:name:对应实现类中的内部成员名称<>里面的array等是固定词汇。--> <property name="array"> <array> <value>100</value> <value>200</value> <value>300</value> </array> </property> <!--集合注入list--> <property name="list"> <list> <value>itcast</value> <value>itheima</value> <value>boxuegu</value> <value>chuanzhihui</value> </list> </property> <!--集合注入set--> <property name="set"> <set> <value>itcast</value> <value>itheima</value> <value>boxuegu</value> <value>boxuegu</value> </set> </property> <!--集合注入map--> <property name="map"> <map> <entry key="country" value="china"/> <entry key="province" value="henan"/> <entry key="city" value="kaifeng"/> </map> </property> <!--注入Properties--> <property name="properties"> <props> <prop key="country">china</prop> <prop key="province">henan</prop> <prop key="city">kaifeng</prop> </props> </property> </bean></beans>
案例:数据源对象管理对于一个新的数据源对象,我们使用两个步骤来创建bean(我们以druid为例):
- 导入druid坐标
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.itheima</groupId> <artifactId>spring_09_datasource</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.10.RELEASE</version> </dependency> <!--这里介绍druid坐标--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.16</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> </dependencies></project>
- 作为Spring管理的beang,配置数据源对象
<?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 "> <!-- DruidataSource对象的管理--> <!--起id 设置class地址--> <bean id="dataSource" 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="123456"/> </bean></beans>
案例:加载properties文件本案例将介绍如何加载properties文件,并将文件带入property的基本信息
我们大致将步骤分为以下三个步骤:
- 开辟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 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的内容是,我们的命名空间开放过程只在原来的xml中: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 ">我们将添加以下内容: xmlns:context="http://www.springframework.org/schema/context"并且在xsi:添加到schemalocation中: http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd(从以上内容整体复制,然后修改末尾xsi)--></beans>
- 使用context命名空间加载指定的properties文件
<!-- 2.使用context空间加载properties文件--><context:property-placeholder location="jdbc.properties"/>
- 使用${}读取加载的属性值
<!-- 3.使用属性占位符${}读取properties文件中的属性--><!-- 说明:idea自动识别${}加载的属性值,需要手动点击才能查阅原始书写格式--> <bean 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>
除上述基本操作外,我们在使用context命名空间时还需要注意很多点:
- 不加载系统属性
<!--因为我们的系统属性优先>定义优先级,当我们的properties中的属性与系统设置的属性名相同时,Systemem可以优先匹配系统属性,导致错误-properties-设置mode--><context:property-placeholder location="jdbc.properties" system-properties-mode="NEVER"/>
- 加载多个properties文件
<!--我们可以用逗号或空间分隔加载多个properties文件--><context:property-placeholder location="jdbc.properties,jdbc2.properties" system-properties-mode="NEVER"/>
- 加载所有properties文件
<!--我们可以用通配符设置加载文件,用*代替所有前缀,只保留properties的后缀--><context:property-placeholder location="*.properties" system-properties-mode="NEVER"/>
- 标准格式加载properties
<!--我们通常用classpath来表示路径,以下形式更标准的classpath:*.properties : 设置并加载当前工程路径中的所有properties文件--> <context:property-placeholder location="classpath:*.properties" system-properties-mode="NEVER"/>
- 搜索从类路径或jar包中加载properties文件
<!--我们通常使用classpath*来表示路径来源classpath*:*.properties : 在jar包中设置加载当前工程路径和当前工程所依赖的所有properties文件--><context:property-placeholder location="classpath*:*.properties" system-properties-mode="NEVER"/>
核心容器bean和依赖注入的相关知识学习已经完成,接下来我们主要学习IOC容器中的核心容器。
这里提到的核心容器可以简单理解为ApplicationContext。接下来,我们将从以下问题入手,学习以下容器的相关知识:
- 如何创建容器?
- 创建容器后,如何从容器中获取bean对象?
- 容器的层次结构是什么?
- 什么是BeanFactory?
Aplicationcontext的创建方式为(XML配置文件在类路径下):
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
除此之外,Spring还提供了另一种创建方法(文件的绝对路径):
ApplicationContext ctx = new FileSystemXmlApplicationContext("D:\\workspace\\spring\\spring_10_container\\src\\main\\resources\\applicationContext.xml");
获取Bean的三种方式方法一是在当前案例中获取的方法:
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
这种方法的问题是,每次获得时都需要转换类型
方式二:
BookDao bookDao = ctx.getBean("bookDao",BookDao.class);
这种方法可以解决类型强转问题,但增加了另一个参数,相对没有简化多少。
方式三:
BookDao bookDao = ctx.getBean(BookDao.class);
这种方法类似于我们之前学到的依赖注入的类型注入。必须确保IOC容器中只有一个与此类型对应的bean对象。
容器层次结构下面我们给出容器的层次图
使用BeanFactory用BeanFactory创建IOC容器的具体实现方法如下:
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(); }}
为了更好地看到BeanFactory和ApplicationContext之间的区别,在BookDaoimpl中添加以下结构函数:
public class BookDaoImpl implements BookDao { public BookDaoImpl() { System.out.println("constructor"); } public void save() { System.out.println("book dao save ..." ); }}
如果不获得bean对象,打印会发现:
- beanFactory是延迟加载,只有在获得bean对象时才会创建
- Applicationcontext是立即加载的,容器加载时会创建bean对象
- 如果Applicationcontext想要成为延迟加载,只需按以下方式进行配置
- <?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="bookDao" class="com.itheima.dao.impl.BookDaoImpl" lazy-init="true"/> </beans>
接下来,我们对以往知识进行总结,包括以下内容:
容器相关- BeanFactory是IoC容器的顶层接口,当BeanFactory对象初始化时,Bean延迟加载
- Applicationcontext接口是Spring容器的核心接口,bean在初始化时立即加载
- Applicationcontext接口提供基本的bean操作方法,并通过其他接口扩展其功能
- Applicationcontext接口常用于初始ClaspathXmlaplicationcontext(常用)FileSystemXmlApplicationContext
在上述开发中,xml配置文件的形式仍然有点复杂
此时,我们需要充分发挥Spring的优势:简化开发,通过注释简化开发过程
下面,我们将在多个方面逐步将Bean转化为注释
注释开发Bean在之前的内容中,我们的bean在xml配置文件中组装
<?xml versinotallow="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--> <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/> </beans>
在后期,我们的bean可以以注释的形式直接在实现类中注释
我们使用@component定义bean,可以添加参数来表示id,也可以不添加参数。后期我们使用class类型进行匹配
package com.itheima.dao.impl;import com.itheima.dao.BookDao;import org.springframework.stereotype.Component;import org.springframework.stereotype.Controller;import org.springframework.stereotype.Repository;//@Component定义beannt@Component("bookDao")public class BookDaoImpl implements BookDao { public void save() { System.out.println("book dao save ..."); }}
package com.itheima.service.impl;import com.itheima.dao.BookDao;import com.itheima.service.BookService;import org.springframework.stereotype.Component;import org.springframework.stereotype.Service;//@Component定义beannt@Componentpublic 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(); }}
@Componenty延伸了三种类型,在实现方法上是一致的,但可以用于各种类型(仅用于自我识别)
- @Controller:用于定义表层bean
- @Service:用于业务层bean定义
- @Repository:用于定义数据层
package com.itheima.dao.impl;import com.itheima.dao.BookDao;import org.springframework.stereotype.Component;import org.springframework.stereotype.Controller;import org.springframework.stereotype.Repository;//@Component定义bean/////@Component("bookDao")//@Repository:@Component衍生注释@Repository("bookDao")public class BookDaoImpl implements BookDao { public void save() { System.out.println("book dao save ..."); }}
package com.itheima.service.impl;import com.itheima.dao.BookDao;import com.itheima.service.BookService;import org.springframework.stereotype.Component;import org.springframework.stereotype.Service;//@Component定义bean/////@Component//@Service:@Component衍生注释@Servicepublic 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(); }}
但是,在上述情况下,即使我们将@component类定义为beannt,
我们的xml文件无法检测到,因此我们需要配置相关的扫描组件来扫描bean
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" 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 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--<context:component-scan />:扫描文件base-package:表示扫描路径--> <context:component-scan base-package="com.itheima"/></beans>
纯注解开发我们前面提到的注释开发属于2.5的附属版本
在Spring3.0版本中,Spring提供了纯注释开发模式,用java代替配置文件,开启了Spring快速开发时代
以前,我们的xml配置文件非常繁琐:
<!--本地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 http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/> </beans>
但是,我们可以通过创建单独的类来表示配置文件:
- @Configuration:目前用于声明Spring配置类别
- @ComponentScan:用于扫描文件(类似于<context:component-scan base-package="com.itheima"/>)
package com.itheima.config;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;//声明目前Spring配置类别@Configuration/设置bean扫描路径,多路径书写字符串数组格式@ComponentScan({"com.itheima.service","com.itheima.dao"})public class SpringConfig {}
注:由于这类属于配置类,我们通常单独列出一个文件夹来表示
常用文件夹:config
命名规范:SpringConfig,UserConfig...
由于我们的开发不再依赖于xml配置文件,Spring容器在主函数中的获取方式也发生了变化:
package com.itheima;import com.itheima.dao.BookDao;import com.itheima.service.BookService;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class App { public static void main(String[] args) { // 这是我们以前的获取方式,xml文件采用路径获取 // ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); // 这是一种新的获取方式,直接提供配置类型 // Annotationconfigaplicationcontext加载Spring配置类初始Spring容器 ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class); // 以后的操作不需要改变 BookDao bookDao = (BookDao) ctx.getBean("bookDao"); System.out.println(bookDao); ///按类型获得bean BookService bookService = ctx.getBean(BookService.class); System.out.println(bookService); }}
注释开发Bean的范围和管理由于我们的Bean开发已经从xml转移到注释开发,一些配置设置也发生了变化
首先介绍Scope范围的设置方法:
- @Scope:定义bean的作用范围
package com.itheima.dao.impl;import com.itheima.dao.BookDao;import org.springframework.context.annotation.Scope;import org.springframework.stereotype.Repository;import javax.annotation.PostConstruct;import javax.annotation.PreDestroy;@Repository///@Scope设置bean的作用范围(singleton或prototype),不添加默认singleton@Scope("singleton")public class BookDaoImpl implements BookDao { public void save() { System.out.println("book dao save ..."); }}
然后我们介绍一下bean生命周期的init和destroy操作:
- @PostConstruct:定义init操作,表示构造后操作
- @PreDestroy:定义destroy操作,表示销毁前操作
在Spring3.0中,省略了以前繁琐的依赖注入,我们的bean依赖注入只留下自动组装操作:
- 使用@Autowired注释打开自动组装模式(按类型)
- 当有相同类型时,我们使用@Qualifier打开按名自动组装
package com.itheima.service.impl;import com.itheima.dao.BookDao;import com.itheima.service.BookService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.beans.factory.annotation.Value;import org.springframework.stereotype.Service;@Servicepublic class BookServiceImpl implements BookService { //@Autowired:注入引用类型,自动装配模式,默认按类型组装 @Autowired //@Qualifier:bean自动组装时,按bean的名称组装 @Qualifier("bookDao") private BookDao bookDao; public void save() { System.out.println("book service save ..."); bookDao.save(); }}
注:基于反射设计的自动组装创建对象,暴力反射对应属性为私有属性初始化数据,因此无需提供setter方法
注:建议使用无参结构方法创建对象(默认)。如果不提供相应的结构方法,请提供唯一的结构方法
注:@Qualifier是基于@Autowired实现的,必须保证Qualifier存在前有Autowired
除上述bean类型组装外,我们的简单类型组装仍然存在:
- 我们以@Value的形式配置简单类型的值
package com.itheima.dao.impl;import com.itheima.dao.BookDao;import org.springframework.beans.factory.annotation.Value;import org.springframework.stereotype.Repository;@Repository("bookDao")public class BookDaoImpl implements BookDao { //@Value:注入简单类型(无需提供set方法) @Value("123") private String name; public void save() { System.out.println("book dao save ..." + name); }}
之所以采用@Value的形式配置,是因为我们的类型值不一定是手动输入的,可能来自Properties资源:
- 首先,我们需要在Springconfig中配置相关资源
package com.itheima.config;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.PropertySource;@Configuration@ComponentScan("com.itheima)//@PropertySource加载properties配置文件@PropertySource({"jdbc.properties"})public class SpringConfig {}
- 然后,当我们在数据层调用时,我们使用${}来匹配数据
package com.itheima.dao.impl;import com.itheima.dao.BookDao;import org.springframework.beans.factory.annotation.Value;import org.springframework.stereotype.Repository;@Repository("bookDao")public class BookDaoImpl implements BookDao { //@Value:注入简单类型(无需提供set方法) @Value("${name}") private String name; public void save() { System.out.println("book dao save ..." + name); }}
注释第三方beann的开发在实际开发中,我们不仅需要管理自己的bean,有时还需要引进其他bean
让我们以Druid为例进行解释:
- 首先是pom.Druid坐标导入xml
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.itheima</groupId> <artifactId>spring_14_annotation_third_bean_manager</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.10.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.16</version> </dependency> </dependencies></project>
- 第三方Bean使用@Bean配置
// 这个bean也属于config文件,我们也把它放在config文件夹中/// 后续我们将解释如何连接package com.itheima.config;import com.alibaba.druid.pool.DruidDataSource;import com.itheima.dao.BookDao;import org.springframework.beans.factory.annotation.Value;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import javax.sql.DataSource;public class JdbcConfig { // 1.定义一种获得管理对象的方法 // 2.添加@Bean,表示当前方法的返回值是bean // @Bean修饰方法,形状参根据类型自动组装 @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("123456"); return ds; }}
- 在核心配置(导入法)中加入独立配置类
// SpringConfigpackage com.itheima.config;import com.alibaba.druid.pool.DruidDataSource;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.Import;import javax.sql.DataSource;@Configuration@ComponentScan("com.itheima")//@Import:导入配置信息(如果需要多个,也采用{}数组形式)@Import({JdbcConfig.class})public class SpringConfig {}
// JdbcConfigpackage com.itheima.config;import com.alibaba.druid.pool.DruidDataSource;import com.itheima.dao.BookDao;import org.springframework.beans.factory.annotation.Value;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import javax.sql.DataSource;//@Configurationpublic class JdbcConfig { ///@Bean修改方法,形状参根据类型自动组装 @Bean public DataSource dataSource(){ DruidDataSource ds = new DruidDataSource();// 配置信息 return ds; }}
注意第三方导入资源的开发注:除上述介绍方法外,还有其他方法,但介绍方法属于主流,所以我们不介绍其他学校,感兴趣的学生可以咨询
下面我们简单介绍一下我们的第三方bean也可能需要导入一些资源:
- 依赖注入的简单类型
package com.itheima.config;import com.alibaba.druid.pool.DruidDataSource;import com.itheima.dao.BookDao;import org.springframework.beans.factory.annotation.Value;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import javax.sql.DataSource;//@Configurationpublic class JdbcConfig { //1.定义获得管理对象的方法 @Value("com.mysql.jdbc.Driver") private String driver; @Value("jdbc:mysql://localhost:3306/spring_db") private String url; @Value("root") private String userName; @Value("root") private String password; //2.添加@Bean,表示当前方法的返回值是bean ///@Bean修改方法,形状参根据类型自动组装 @Bean public DataSource dataSource(){ DruidDataSource ds = new DruidDataSource(); ds.setDriverClassName(driver); ds.setUrl(url); ds.setUsername(userName); ds.setPassword(password); return ds; }}
- 依赖类型依赖注入
package com.itheima.config;import com.alibaba.druid.pool.DruidDataSource;import com.itheima.dao.BookDao;import org.springframework.beans.factory.annotation.Value;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import javax.sql.DataSource;public class JdbcConfig { @Bean public DataSource dataSource(BookDao bookDao){ // 我们只需要调用,该系统将自动为我们组装 System.out.println(bookDao); } }
引入类型注入只需为bean定义方法设置形参即可,容器将根据类型自动组装对象