4 依赖注入方式
4.1 概述
- 依赖注入描述容器中bean和bean中之间的依赖关系的过程,如果bean运行需要的是数字或者字符串呢?
- 引用类型
- 简单类型(基本数据类型String)
- 类型
- setter类型
- 简单类型
- 引用类型
- 构造器注入
- 简单类型
- 引用类型
4.2 setter注入
- 引用数据类型多个bean的依赖
- 接口UserDao
public interface UserDao {
public void save();
}
- 接口BookDao
public interface BookDao {
void save();
}
- 接口BookService
public interface BookService {
void save();
}
- 接口实现类UserDaoImpl
public class UserDaoImpl implements UserDao{
public void save(){
System.out.println("user dao save ...");
}
}
- 接口实现类BookDaoImpl
public class BookDaoImpl implements BookDao{
public void save(){
System.out.println("book dao save");
}
}
- 接口实现类**[重点]**
public class BookServiceImpl implements BookService {
//删除业务层中使用new的方式创建的dao对象
private BookDao bookDao;
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
//生成set方法
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
public void save(){
System.out.println("book service save ...");
bookDao.save();
userDao.save();
}
}
- 配置文件
<bean id ="bookDao" name = "dao" class = "com.itheima.dao.impl.BookDaoImpl" scope="prototype"/>
<bean id = "userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<bean id = "bookService" name = "service bookEbi" class = "com.itheima.service.impl.BookServiceImpl">
<property name="bookDao" ref="bookDao"/>
<property name="userDao" ref="userDao"/>
</bean>
- App类
public class App2 {
public static void main(String[] args) {
//3.获取IoC容器,ApplicationContext和配置一样,new一个接口实现类
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookService bookService = (BookService) ctx.getBean("bookService");
bookService.save();
}
}
- 打印结果
book service save ...
book dao save
user dao save ...
Process finished with exit code 0
- 简单类型
- 接口实现类BookDaoImpl
public class BookDaoImpl implements BookDao{
private int connectionNum;
private String databaseName;
public void setConnectionNum(int connectionNum) {
this.connectionNum = connectionNum;
}
public void setDatabaseName(String databaseName) {
this.databaseName = databaseName;
}
public void save(){
System.out.println("book dao save"+databaseName+","+connectionNum);
}
}
- 配置文件
<bean id ="bookDao" name = "dao" class = "com.itheima.dao.impl.BookDaoImpl">
<property name="databaseName" value="mysql"/>
<property name="connectionNum" value="10"/>
</bean>
- 打印结果
book service save ...
book dao savemysql,10
user dao save ...
Process finished with exit code 0
4.3 构造器注入
- 引用数据类型
- 接口实现类BookDaoImpl
public class BookDaoImpl implements BookDao{
public void save(){
System.out.println("book dao save");
}
}
- 接口实现类UserDaoImpl
public class UserDaoImpl implements UserDao{
public void save(){
System.out.println("user dao save ...");
}
}
- 接口实现类BookServiceImpl【更改之处】
public class BookServiceImpl implements BookService {
//删除业务层中使用new的方式创建的dao对象
private BookDao bookDao;
private UserDao userDao;
//private BookDao bookDao = new BookDaoImpl();
//去掉setter方法,进行构造方法构造依赖,记得整两
public BookServiceImpl(BookDao bookDao, UserDao userDao) {
this.bookDao = bookDao;
this.userDao = userDao;
}
public void save(){
System.out.println("book service save ...");
bookDao.save();
userDao.save();
}
}
- App入口
public class App2 {
public static void main(String[] args) {
//3.获取IoC容器,ApplicationContext和配置一样,new一个接口实现类
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookService bookService = (BookService) ctx.getBean("bookService");
bookService.save();
}
}
- 配置文件【更改之处】
<bean id ="bookDao" name = "dao" class = "com.itheima.dao.impl.BookDaoImpl"/>
<bean id ="userDao" name = "dao" class = "com.itheima.dao.impl.UserDaoImpl"/>
<bean id = "bookService" class = "com.itheima.service.impl.BookServiceImpl">
<constructor-arg name="bookDao" ref="bookDao"/>
<constructor-arg name="userDao" ref="userDao"/>
</bean>
这边的name表示构造器的形参
- 简单类型
- 实现接口类BookDaoImpl
也是用的构造器实现的
public class BookDaoImpl implements BookDao{
private String databaseName;
private int connectionNum;
public BookDaoImpl(String databaseName, int connectionNum) {
this.databaseName = databaseName;
this.connectionNum = connectionNum;
}
public void save(){
System.out.println("book dao save"+databaseName+connectionNum);
}
}
- 配置文件
这两顺序可以换
<bean id ="bookDao" class = "com.itheima.dao.impl.BookDaoImpl">
<constructor-arg name="databaseName" value="mysql"/>
<constructor-arg name="connectionNum" value="666"/>
</bean>
- 运行结果
book service save ...
book dao savemysql666
user dao save ...
Process finished with exit code 0
- 优化构造器
- 类型指定
如果构造器的形参变了,配置文件就得重新配置,出现耦合度比较高的情况,
因此可以直接写类型,不直接指定形参
<bean id ="bookDao" class = "com.itheima.dao.impl.BookDaoImpl">
<constructor-arg type="java.lang.String" value="mysql"/>
<constructor-arg type="int" value="10"/>
</bean>
- 位置指定
但是也可能出现两种类型一样的形参
于是出现了通过index需要指定
<bean id ="bookDao" class = "com.itheima.dao.impl.BookDaoImpl">
<constructor-arg index="0" value="mysql"/>
<constructor-arg index="1" value="100"/>
</bean>
- 其他
4.4 总结
- 构造器注入必须强制执行,setter可以执行也可以不执行
5 依赖自动装配
5.1 概念
IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配
5.2 种类
- 按类型
- 按名称
- 按构造方法
- 不启动自动装配
5.3 实践
5.3.1 按照byType匹配
- 具体设置
- 接口实现类BookServiceImpl
依旧记得保留setter方法
public class BookServiceImpl implements BookService {
//删除业务层中使用new的方式创建的dao对象
private BookDao bookDao;
// private BookDao bookDao = new BookDaoImpl();
//生成set方法
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
- 配置文件
加上autowire就可以了
<bean id ="bookDao" class = "com.itheima.dao.impl.BookDaoImpl" scope="prototype"/>
<bean id = "bookService"
class = "com.itheima.service.impl.BookServiceImpl" autowire="byType"/>
- 注意点
- 报错1
BookServiceImpl中的BookDao与配置文件中的bookDao中bean实现了Dao接口,如果没有就报错
也就是说是private BookDao bookDao中的BookDao 和<bean id =“bookDao” 中的bookDao进行类型的匹配
- 报错2
如果满足接口的Dao接口的有两个,就会装配失败
5.3.2 按照byName匹配
- 匹配原则
private BookDao bookDao中的bookDao和id ="bookDao"中的bookDao名字要一样,耦合度较高
- 配置文件内容
autowire="byName
<bean id ="bookDao" class = "com.itheima.dao.impl.BookDaoImpl" scope="prototype"/>
<!--按照名称匹配-->
<bean id = "bookService" class = "com.itheima.service.impl.BookServiceImpl" autowire="byName"/>
5.3.3 总结
- 自动装配用于引用类型依赖注入,不能对简单类型进行操作
- 按类型匹配byType保证容器中相同类型的bean唯一,推荐使用
- 使用按名称配对byName保证容器中具有指定名称的bean,因变量名与配置耦合,不推荐使用
- 自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效
6 集合注入
6.1 内容
- 数组
- List
- Set
- Map
- Propertites
6.2 配置内容
- BookDaoImpl接口实现类
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);
}
}
- 配置文件
<bean id ="bookDao" name = "dao" class = "com.itheima.dao.impl.BookDaoImpl">
<property name="array">
<array>
<value>100</value>
<value>200</value>
<value>300</value>
<ref bean="beanId"/>
</array>
</property>
<property name="list">
<list>
<value>itcast</value>
<value>itheima</value>
<value>boxuegu</value>
<value>chuanzhihui</value>
</list>
</property>
<property name="set">
<set>
<value>itcast</value>
<value>itheima</value>
<value>boxuegu</value>
</set>
</property>
<property name="map">
<map>
<entry key="country" value="china"/>
<entry key="province" value="guangdong"/>
<entry key="city" value="guangzhou"/>
</map>
</property>
<property name="properties">
<props>
<prop key="country">china</prop>
<prop key="province">guangdong</prop>
<prop key="city">guangzhou</prop>
</props>
</property>
</bean>
7 第三方bean注入:以数据源对象管理为例
7.1 概述
第三方的bean该如何管理
7.2 Druid管理
- pom中进行maven文件配置
Druid是阿里巴巴开发的数据连接池
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
- 判断使用setter还是构造器方法
发现DruidDataSource中有setter方法
- 配置文件进行配置
<!--管理DruidDataSource对象-->
<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="root"/>
</bean>
- App入口
public class App2 {
public static void main(String[] args) {
//3.获取IoC容器,ApplicationContext和配置一样,new一个接口实现类
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
DataSource dataSource = (DataSource) ctx.getBean("dataSource");
System.out.println(dataSource);
}
}
- 结果
{
CreateTime:"2022-11-06 23:08:56",
ActiveCount:0,
PoolingCount:0,
CreateCount:0,
DestroyCount:0,
CloseCount:0,
ConnectCount:0,
Connections:[
]
}
7.3 C3P0连接池管理
- mvnrepository中获取配置
- C3P0
网址:去Maven Repository: c3p0 » c3p0 » 0.9.1.2 (mvnrepository.com)复制代码
<!-- https://mvnrepository.com/artifact/c3p0/c3p0 -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
- mysql
网址:Maven Repository: mysql » mysql-connector-java » 5.1.16 (mvnrepository.com)
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.16</version>
</dependency>
- 加载到maven中
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.16</version>
</dependency>
- 使用setter注入
- 配置文件
<bean id="dataSource2" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring_db"/>
<property name="user" value="root"/>
<property name="password" value="root"/>
- App入口
public class App2 {
public static void main(String[] args) {
//3.获取IoC容器,ApplicationContext和配置一样,new一个接口实现类
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
DataSource dataSource = (DataSource) ctx.getBean("dataSource2");
System.out.println(dataSource);
}
}
- 结果
com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, dataSourceName -> 1hge1adasl3sdda8tlh5w|76b0bfab, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, identityToken -> 1hge1adasl3sdda8tlh5w|76b0bfab, idleConnectionTestPeriod -> 0, initialPoolSize -> 3, jdbcUrl -> jdbc:mysql://localhost:3306/spring_db, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 15, maxStatements -> 0, maxStatementsPerConnection -> 0, minPoolSize -> 3, numHelperThreads -> 3, numThreadsAwaitingCheckoutDefaultUser -> 0, preferredTestQuery -> null, properties -> {user=******, password=******}, propertyCycle -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, usesTraditionalReflectiveProxies -> false ]
8 加载properties文件
8.1 概述
- jbdc.properties配置文件
- 需求
需要让spring可以读取识别properties的文件
8.2 操作
- 配置文件中开辟新的空间
<?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
">
- 加载properties文件
- 开辟属性占位符,并确定properties的位置
- 使用${}改变value的值,并读取properties文件中的属性
<!--2.使用context空间加载properties文件-->
<!--2.1 property-placeholder这个叫做属性占位符,并确定位置-->
<context:property-placeholder location="jdbc.properties"/>
<!--2.2 改变value的值${}-->
<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>
- 将读出来的值放到name中
- jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/spring_db
jdbc.username=root
jdbc.password=root
- 配置文件增加这一个
<!-- 3. 将读出来的值放到name中-->
<bean id = "bookDao" class="com.itheima.dao.impl.BookDaoImpl">
<property name="name" value="${jdbc.driver}"/>
</bean>
- App实现类
public class App2 {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
}
}
- 结果
book dao savecom.mysql.jdbc.Driver
Process finished with exit code 0
- 注意
- 如果有多个配置文件都要加载
可以用,或者用*
使用classpath表示类路径
使用classpath*表示可以从本工程,或者以及依赖的jar包中读取