核心概念
- 什么IOC/DI思想?
- IOC:控制反转,控制反转的是对象的创建权
- DI:依赖注入,绑定对象与对象之间的依赖关系
- 什么是IOC容器?
- Spring创建了一个容器用来存放所创建的对象,这个容器就叫IOC容器
- 什么是Bean?
- 容器中所存放的一个个对象就叫Bean或Bean对象
IOC 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_01_quickstart</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>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
新建org.gz.dao包,分别实现如下接口和实现类
package org.gz.dao;
public interface BookDao {
public void save();
}
package org.gz.dao.impl;
import org.gz.dao.BookDao;
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
}
新建org.gz.dao包,分别实现如下接口和实现类
package org.gz.service;
public interface BookService {
public void save();
}
package org.gz.service.impl;
import org.gz.dao.BookDao;
import org.gz.service.BookService;
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;
}
}
启动(测试)类
package org.gz;
import org.gz.dao.BookDao;
import org.gz.dao.impl.BookDaoImpl;
import org.gz.service.impl.BookServiceImpl;
public class App {
public static void main(String[] args) {
BookServiceImpl bookService = new BookServiceImpl();
BookDao bookDao=new BookDaoImpl();
bookService.setBookDao(bookDao);
bookService.save();
}
}
在resource目录下新建applicationContext.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">
<!--1.导入spring的坐标spring-context,对应版本是5.2.10.RELEASE-->
<!--2.配置bean-->
<!--bean标签标示配置bean
id属性标示给bean起名字
class属性表示给bean定义类型-->
<bean id="bookDao" class="org.gz.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="org.gz.service.impl.BookServiceImpl">
<!--7.配置server与dao的关系-->
<!--property标签表示配置当前bean的属性
name属性表示配置哪一个具体的属性
ref属性表示参照哪一个bean-->
<property name="bookDao" ref="bookDao"/>
</bean>
</beans>
新建spring版本的测试类:
package org.gz;
import org.gz.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();
}
}
运行测试
bean实例化
-
构造方法实例化bean
-
静态工厂创建对象
- 实例工厂
-
FactoryBean创建对象
bean的生命周期
- 首先理解下什么是生命周期?
- 从创建到消亡的完整过程,例如人从出生到死亡的整个过程就是一个生命周期。
- bean生命周期是什么?
- bean对象从创建到销毁的整体过程。
- bean生命周期控制是什么?
- 在bean创建后到销毁前做一些事情。
具体的控制有两个阶段:
- bean创建之后,想要添加内容,比如用来初始化需要用到资源
- bean销毁之前,想要添加内容,比如用来释放用到的资源
生命周期控制 -- xml配置
生命周期控制--接口控制
实现InitializingBean, DisposableBean接口
close关闭容器
- ApplicationContext中没有close方法,它的子类中有close方法
- 所以需要将ApplicationContext更换成ClassPathXmlApplicationContext,然后调用close方法就好啦
public class App {
public static void main(String[] args) {
//ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) context.getBean("bookDao");
bookDao.save();
context.close();
}
}
调用ctx的registerShutdownHook()方法
public class App {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) context.getBean("bookDao");
bookDao.save();
context.registerShutdownHook();
}
}
不同点:
close()是在调用的时候关闭,registerShutdownHook()是在JVM退出前调用关闭。
注解开发定义bean
步骤一:
创建配置类
在配置类上面加一个@Configuration
注解,将其标识为一个配置类,用于替换掉applicationContext.XML
在配置类上添加包扫描注解@ComponentScan
替换<context:component-scan base-package=""/>
@Configuration
@ComponentScan("org.gz")
public class SpringConfig {
}
步骤一:
删除原有的XML配置
将配置文件中的bean标签删除掉
<bean id="bookDao" class="com.blog.dao.impl.BookDaoImpl"/>
步骤二:
在Dao上添加注解
在BookDaoImpl类上添加@Component
注解(BookDao接口略)
@Component("bookDao")
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
}
注意:@Component注解不可以添加在接口上,因为接口是无法创建对象的。
步骤五:
Service上添加注解
在BookServiceImpl类上也添加@Component
交给Spring框架管理(BookServie接口略)
@Component
public class BookServiceImpl implements BookService {
@Resource
private BookDao bookDao;
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
@Override
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
步骤四:
创建运行类并执行
创建一个新的运行类AppForAnnotation
public class AppForAnnotation {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
BookDao bookDao = (BookDao) context.getBean("bookDao");
bookDao.save();
BookService bookService = context.getBean(BookService.class);
bookService.save();
}
}
对于@Component注解,还衍生出了其他三个注解
@Controller
、@Service
、@Repository
通过查看源码会发现:这三个注解和@Component注解的作用是一样的,为什么要衍生出这三个呢?
这是方便我们后期在编写类的时候能很好的区分出这个类是属于表现层
、业务层
还是数据层
的类。
小结
- 记住
@Component
、@Controller
、@Service
、@Repository
这四个注解 - applicationContext.xml中
<context:component-san/>
的作用是指定扫描包路径,注解为@ComponentScan
@Configuration
标识该类为配置类,使用类替换applicationContext.xml
文件ClassPathXmlApplicationContext
是加载XML配置文件AnnotationConfigApplicationContext
是加载配置类
bean的作用范围
要想将BookDaoImpl变成非单例,只需要在其类上添加@scope
注解
@Component("bookDao")
@Scope("prototype")
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
}
修改后运行查看结果是否一致
public class AppForAnnotation {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
BookDao bookDao1 = (BookDao) context.getBean("bookDao");
BookDao bookDao2 = (BookDao) context.getBean("bookDao");
System.out.println(bookDao1);
System.out.println(bookDao2);
}
}
知识点:@scope
名称 | @Scope |
---|---|
类型 | 类注解 |
位置 | 类定义上方 |
作用 | 设置该类创建对象的作用范围,可用于设置创建出的bean是否为单例对象 |
属性 | value(默认):定义bean作用范围,默认值singleton(单例),可选值prototype(非单例) |
bean的生命周期
- 如何对方法进行标识,哪个是初始化方法,哪个是销毁方法?
只需要在对应的方法上添加@PostConstruct
和@PreDestroy
注解即可。
@Component("bookDao")
public class BookDaoImpl implements BookDao {
public BookDaoImpl() {
System.out.println("construct ... ");
}
public void save() {
System.out.println("book dao save ...");
}
@PostConstruct // 在构造方法之后执行,替换 init-method
public void init() {
System.out.println("init ... ");
}
@PreDestroy // 在销毁方法之前执行,替换 destroy-method
public void destroy() {
System.out.println("destroy ... ");
}
}
要想看到两个方法执行,需要注意的是destroy
只有在容器关闭的时候,才会执行,所以需要修改App的类
public class AppForAnnotation {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
BookDao bookDao = (BookDao) context.getBean("bookDao");
System.out.println(bookDao);
context.registerShutdownHook();//关闭容器
}
}
注意:JDK8版本以上,如果找不到
@PostConstruct
和@PreDestroy
注解,需要导入下面的jar包<dependency> <groupId>javax.annotation</groupId> <artifactId>javax.annotation-api</artifactId> <version>1.3.2</version> </dependency>
小结
配置文件中的bean标签中的id
对应@Component("")
,@Controller("")
,@Service("")
,@Repository("")
scope
对应@scope()
init-method
对应@PostConstruct
destroy-method
对应@PreDestroy