
- IoC(Inversion of Control)控制反转
- 使用对象时,由主动new产生对象转换为由外部提供对象,此过程中对象创建控制权由程序转移到外部,此思想称为控制反转
- Spring技术对IoC思想进行了实现
- Spring提供了一个容器,称为IoC容器,用来充当IoC思想中的“外部”
- IoC容器负责对象的创建、初始化等一系列工作,被创建或被管理的对象在IoC容器中统称为Bean
- DI(Dependency Injection)依赖注入
- 在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入
- 目标:充分解耦
1. 导入Spring坐标
<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.0modelVersion>
<groupId>org.examplegroupId>
<artifactId>spring_01_quickstartartifactId>
<version>1.0-SNAPSHOTversion>
<properties>
<maven.compiler.source>17maven.compiler.source>
<maven.compiler.target>17maven.compiler.target>
properties>
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.2.10.RELEASEversion>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
<scope>testscope>
dependency>
dependencies>
project>
2. 定义Spring管理的类(接口)
public interface BookDao {
public void save();
}
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
}
public interface BookService {
public void save();
}
public class BookServiceImpl implements BookService {
private BookDao bookDao = new BookDaoImpl();
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
3. 创建Spring配置文件,配置对应类作为Spring管理的bean
<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.lenyoo.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.lenyoo.service.impl.BookServiceImpl"/>
beans>
注意:bean定义时id属性在同一个上下文中不能重复
4. 初始化IoC容器(Spring核心容器/Spring容器),通过容器获取bean
package com.lenyoo;
import com.lenyoo.dao.BookDao;
import com.lenyoo.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main(String[] args) {
// 3. 获取IOC容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// 4. 获取bean
// BookDao bookDao = (BookDao) ctx.getBean("bookDao");
// bookDao.save();
BookService bookService = (BookService) ctx.getBean("bookService");
bookService.save();
}
}
3. DI入门案例
1. 删除使用new的形式创建对象的代码
public class BookServiceImpl implements BookService {
// 5. 删除业务层中使用new的方式创建的dao对象
private BookDao bookDao /*= new BookDaoImpl()*/;
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
2. 提供依赖对象对应的setter方法
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;
}
}
3. 配置service与dao之间的关系
<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.lenyoo.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.lenyoo.service.impl.BookServiceImpl">
<property name="bookDao" ref="bookDao"/>
bean>
beans>
注意:配置中的两个bookDao的含义是不一样的
对象已经能交给Spring的IOC容器来创建了,但是容器是如何来创建对象的呢?就需要研究下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 ...");
}
}
- 配置
<bean id="bookDao" class="com.lenyoo.dao.impl.BookDaoImpl"/>
- 无参构造方法如果不存在,将抛出异常BeanCreationException
- 静态工厂
public class OrderDaoFactory {
public static OrderDao getOrderDao(){
System.out.println("factory setup...");
return new OrderDaoImpl();
}
}
- 配置
<bean id="orderDao" class="com.lenyoo.factory.OrderDaoFactory" factory-method="getOrderDao"/>
3.2.3 实例化bean的三种方式——实例工厂(了解)
- 实例工厂
public class UserDaoFactory {
public UserDao getUserDao(){
return new UserDaoImpl();
}
}
- 配置
<bean id="userFactory" class="com.lenyoo.factory.UserDaoFactory"/>
<bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>
3.2.4 实例化bean的第四种方式——FactoryBean(实用)
- FactoryBean
public class UserDaoFactoryBean implements FactoryBean<UserDao> {
// 代替原始实例工厂中创建对象的方法
@Override
public UserDao getObject() throws Exception {
return new UserDaoImpl();
}
@Override
public Class<?> getObjectType() {
return UserDao.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
- 配置
<bean id="userDao" class="com.lenyoo.factory.UserDaoFactoryBean"/>
3.3 bean的生命周期
(1)关于Spring中对bean生命周期控制提供了两种方式:
- 在配置文件中的bean标签中添加
init-method和destroy-method属性
<bean id="bookDao" class="com.lenyoo.dao.impl.BookDaoImpl"
init-method="init" destroy-method="destroy"/>
- 类实现
InitializingBean与DisposableBean接口,这种方式了解下即可。
package com.lenyoo.service.impl;
import com.lenyoo.dao.BookDao;
import com.lenyoo.service.BookService;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {
private BookDao bookDao;
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
@Override
public void destroy() throws Exception {
System.out.println("service destroy");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("service init");
}
}
(2)对于bean的生命周期控制在bean的整个生命周期中所处的位置如下:
- 初始化容器
- 1.创建对象(内存分配)
- 2.执行构造方法
- 3.执行属性注入(set *** 作)
- 4.执行bean初始化方法
- 使用bean
- 1.执行业务 *** 作
- 关闭/销毁容器
- 1.执行bean销毁方法
(3)关闭容器的两种方式:
- ConfigurableApplicationContext是ApplicationContext的子类
- close()方法
- registerShutdownHook()方法
import com.lenyoo.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();
ctx.close();
}
}
4. DI相关内容
依赖注入方式,分别是:
- setter注入
- 简单类型
- 引用类型
- 构造器注入
- 简单类型
- 引用类型
- 在bean中定义引用类型属性,并提供可访问的set方法
public class BookServiceImpl implements BookService {
private BookDao bookDao;
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
public void save() {
System.out.println("book service save ...");
bookDao.save();
userDao.save();
}
}
- 配置中使用property标签ref属性注入引用类型对象
<bean id="bookDao" class="com.lenyoo.dao.impl.BookDaoImpl"/>
<bean id="userDao" class="com.lenyoo.dao.impl.UserDaoImpl"/>
<bean id="bookService" class="com.lenyoo.service.impl.BookServiceImpl">
<property name="bookDao" ref="bookDao"/>
<property name="userDao" ref="userDao"/>
bean>
4.1.2 Setter注入——简单类型
- 在bean中定义简单类型属性并提供可访问的set方法
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);
}
}
- 配置中使用property标签value属性注入简单类型数据
<bean id="bookDao" class="com.lenyoo.dao.impl.BookDaoImpl">
<property name="databaseName" value="mysql"/>
<property name="connectionNum" value="100"/>
bean>
4.2 构造器注入(了解)
4.2.1 构造器注入——引用类型(了解)
- 在bean中定义引用类型属性并提供可访问的构造方法
public class BookServiceImpl implements BookService {
private BookDao bookDao;
private UserDao userDao;
public BookServiceImpl(BookDao bookDao, UserDao userDao) {
this.bookDao = bookDao;
this.userDao = userDao;
}
- 配置中使用constructor-arg标签ref属性注入引用类型对象
<bean id="bookDao" class="com.lenyoo.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.lenyoo.service.impl.BookServiceImpl">
<constructor-arg name="bookDao" ref="bookDao"/>
<constructor-arg name="userDao" ref="userDao"/>
bean>
4.2.2 构造器注入——简单类型(了解)
- 在bean中定义简单类型属性并提供可访问的构造方法
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);
}
}
- 配置中使用constructor-arg标签value属性注入简单类型数据
<bean id="bookDao" class="com.lenyoo.dao.impl.BookDaoImpl">
<constructor-arg name="databaseName" value="mysql"/>
<constructor-arg name="connectionNum" value="10"/>
bean>
4.3 依赖自动装配
- IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配
- 自动装配方式
- 按类型(常用)
- 按名称
- 按构造方法
- 不启用自动装配
- 配置中使用bean标签autowire属性设置自动装配的类型
<bean id="bookDao" class="com.lenyoo.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.lenyoo.service.impl.BookServiceImpl" autowire="byType"/>
注意
- 自动装配用于引用类型依赖注入,不能对简单类型进行 *** 作
- 使用按类型装配时(byType)必须保障容器中相同类型的bean唯一,推荐使用
- 使用按名称装配时(byName)必须保障容器中具有指定名称的bean,因变量名与配置耦合,不推荐使用
- 自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效
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" class="com.lenyoo.dao.impl.BookDaoImpl">
<property name="array">
<array>
<value>100value>
<value>200value>
<value>300value>
array>
property>
<property name="list">
<list>
<value>itcastvalue>
<value>itheimavalue>
<value>boxueguvalue>
list>
property>
<property name="set">
<set>
<value>itcastvalue>
<value>itheimavalue>
<value>boxueguvalue>
<value>chuanzhihuivalue>
set>
property>
<property name="map">
<map>
<entry key="country" value="china"/>
<entry key="province" value="zhejiang"/>
<entry key="city" value="hangzhou"/>
map>
property>
<property name="properties">
<props>
<prop key="country">chinaprop>
<prop key="province">zhejiangprop>
<prop key="city">hangzhouprop>
props>
property>
bean>
5. IOC/DI配置管理第三方bean
5.1 案例:数据源对象管理
该案例使用数据源Druid(德鲁伊)和C3P0来配置学习
步骤1:导入第三方数据源依赖
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.1.16version>
dependency>
<dependency>
<groupId>c3p0groupId>
<artifactId>c3p0artifactId>
<version>0.9.1.2version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.16version>
dependency>
步骤2:配置第三方bean
<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>
<bean id="dataSource" 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"/>
<property name="maxPoolSize" value="1000"/>
bean>
步骤3:从IOC容器中获取对应的bean对象
public class App {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
DataSource dataSource = (DataSource) ctx.getBean("dataSource");
System.out.println(dataSource);
}
}
5.2 加载properties文件
- 开启context命名空间
<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>
- 使用context空间,加载指定properties文件
<context:property-placeholder location="jdbc.properties"/>
- 使用属性占位符${}读取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>
<bean id="bookDao" class="com.lenyoo.dao.impl.BookDaoImpl">
<property name="name" value="${jdbc.driver}"/>
bean>
当有多个properties配置文件需要被加载,该如何配置?
- 不加载系统属性
<context:property-placeholder location="jdbc.properties" system-properties-mode="NEVER"/>
- 加载多个properties文件
<context:property-placeholder location="jdbc.properties,jdbc2.properties"/>
- 加载所有properties文件
<context:property-placeholder location="*.properties"/>
- 加载properties文件标准格式
<context:property-placeholder location="classpath:*.properties" system-properties-mode="NEVER"/>
- 从类路径或jar包中搜索并加载properties文件
<context:property-placeholder location="classpath*:*.properties" system-properties-mode="NEVER"/>
6. 核心容器
6.1 容器的创建方式
- 方式一:类路径加载配置文件
// 1. 加载类路径下的配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
- 方式二:文件路径加载配置文件
// 2. 从文件系统下加载配置文件
ApplicationContext ctx = new FileSystemXmlApplicationContext("//Users/lenyoo/Documents/code/spring-app/spring_10_container/src/main/resources/applicationContext.xml");
6.2 bean的三种获取方式
- 方式一:使用bean名称获取
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
- 方式二:使用bean名称获取并指定类型
BookDao bookDao = ctx.getBean("bookDao", BookDao.class);
- 方式三:使用bena类获取
BookDao bookDao = ctx.getBean(BookDao.class);
6.3 BeanFactory
- 使用BeanFactory创建的容器是延迟加载
- 使用ApplicationContext创建的容器是立即加载
- 具体BeanFactory如何创建只需要了解即可。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)