1.Spring概述
1.1 为什么要学
专业角度:
简化开发,降低企业级开发的复杂性
框架整合,高效整合其他技术,提高企业级应用开发与运行效率
简化开发
- IoC
- AOP
- 事务处理
框架整合
- MyBatis
- MyBatis-plus
- Struts
- Struts2
- Hibernate
…
1.2 怎么学
学习Spring框架设计思想
学习基础操作,思想操作与思想间的练习
学习案例,熟练应用操作的同时,体会思想
1.3 初始Spring
官网:https://spring.io/
Spring发展到今天已经形成了一种开发的生态圈,Spring提供若干个项目,每个项目用于特定的功能
将要学习的:
Spring Framework
Spring Boot
Spring Cloud
2.Spring Framework
2.1 Spring Framework系统架构系统架构
Spring Framework是Spring生态圈中最基础的项目,是其他项目的根基
Data Access:数据访问(②)
Data Integration:数据集成
Web:Web开发
AOP:面向切面编程(③)
Aspects:AOP思想实现(③)
Core Container:核心容器(①)
Test单元测试与集成测试
2.2 核心概念
代码书写现状:耦合度偏高
解决方案:使用对象时,在程序中不要主动使用new产生对象,转换为由外部提供对象
IoC(Inversion of Control)控制反转
对象的创建权限由程序转移到外部,这个思想成为控制反转
Spring技术对IoC思想进行了实现
Spring提供了一个容器,成为IoC容器,用来充当IoC思想中的“外部”
IoC容器负责对象的创建、初始化等一系列工作,被创建或被管理的对象在IoC容器中统称为Bean
DI(Dependency Injection)依赖注入
在容器中建立bean与bean之间的依赖关系的整个过程,称之为依赖注入
目标:充分解耦
- 使用IoC容器管理bean
- 在IoC容器内将有依赖关系的bean进行关系绑定(DI)
最终效果:
使用对象时不仅可以从IoC容器中获取,并且获取到的bean已经绑定了所有的依赖关系。
2.3 入门案例
2.3.1 IoC入门案例
1.管理什么?(Service与Dao)
2.如何将被管理的对象告知IoC容器?(配置)
3.被管理的对象交给IoC容器,如何获取到IoC容器?(接口)
4.IoC容器得到后,如何从容器中获取bean?(接口方法)
5.使用Spring导入哪些坐标?(pom.xml)
① 导入代码(链接:https://pan.baidu.com/s/1SWxm7Zn7regqjcTE6VCAuw 提取码:76uw)
② 在非tomcat环境下运行APP.java
在idea中打印结果为:
book service save …
book dao save …
③ 在pom.xml的标签中导入坐标
导入spring的坐标spring-context,对应版本是5.2.10.RELEASE
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
刷新Maven
④ 新建配置文件applicationContext.xml(创建)
⑤ 在applicationContext.xml配置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-->
<!--bean标签表示配置bean
id属性表示给bean起名字
class属性表示给bean定义类型-->
<bean id="bookDao" class="com.example.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.example.service.impl.BookServiceImpl"/>
</beans>
⑥ 初始化IoC容器,通过容器获取bean
package com.example;
import com.example.dao.BookDao;
import com.example.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App2 {
public static void main(String[] args) {
//获取IoC容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取bean
// BookDao bookDao = (BookDao) ctx.getBean("bookDao");
// bookDao.save();
BookService bookService = (BookService) ctx.getBean("bookService");
bookService.save();
}
}
2.3.2 DI入门案例
DI入门案例思路分析
- 基于IoC管理bean
- Service中使用new形式创建的Dao对象是否保留?(否)
- Service中需要的Dao对象如何进入到Service中?(提供方法)
- Service与Dao之间的关系如何描述?(配置)
① 修改BookServiceImpl
删除业务层中使用new的方式创建的dao对象
提供对应的set方法
package com.example.service.impl;
import com.example.dao.BookDao;
import com.example.dao.impl.BookDaoImpl;
import com.example.service.BookService;
public class BookServiceImpl implements BookService {
//删除业务层中使用new的方式创建的dao对象
private BookDao bookDao;
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
//提供对应的set方法
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
}
② 修改配置文件
配置service与dao的关系
<bean id="bookService" class="com.example.service.impl.BookServiceImpl">
<!--配置service与dao的关系-->
<!-- property标签表示配置当前bean的属性-->
<!-- name属性表示配置哪一个具体的属性-->
<!-- ref属性表示参照哪一个bean-->
<property name="bookDao" ref="bookDao"/>
</bean>
③ 运行App2.java
2.4 bean
2.4.1 bean基础配置
bean别名配置
定义bean的别名,可定义多个,使用逗号(,)分号(;)空格( )分割
如:
<bean id="bookDao" name="dao bookDaoImpl" class="com.example.dao.impl.BookDaoImpl"/>
<bean id="bookDao" name="dao,bookDaoImpl" class="com.example.dao.impl.BookDaoImpl"/>
bean的作用范围配置
bean默认是单,通过scope修改
singleton:单例
propotype:非单例
如:
<bean id="bookDao" class="com.example.dao.impl.BookDaoImpl" scope="prototype"/>
1.为什么bean默认是单例?
spring管理对象时主要是管理可复用得到对象
2.适合交给容器进行管理的bean
表现层对象
业务层对象
数据层对象
工具对象
3.不适合交给容器进行管理的bean
封装实体的域对象
2.4.2 bean实例化——构造方法(常用)
bean本质上就是对象,创建bean使用构造方法完成
① 配置
<!--方式一:构造方法实例化bean-->
<bean id="bookDao" class="com.example.dao.impl.BookDaoImpl" />
② 在BookDaoImpl中提供构造方法
public BookDaoImpl(){
System.out.println("book dao constructor is running...");
}
③ 运行App2发现book dao constructor is running…被打印,说明bean是通过无参构造方法构造的
如果不提供无参构造方法,将抛出异常BeanCreationException
2.4.3 bean实例化——静态工厂
① 创建工厂类
package com.example.factory;
import com.example.dao.BookDao;
import com.example.dao.impl.BookDaoImpl;
public class BookDaoFactory {
public static BookDao getBookDao(){
System.out.println("factory setup...");
return new BookDaoImpl();
}
}
② 修改配置文件
<!--方式二:使用静态工厂实例化bean-->
<bean id="bookDao" class="com.example.factory.BookDaoFactory" factory-method="getBookDao"/>
③ 运行APP2.java
2.4.3 bean实例化——工厂实例化与FactoryBean
① 修改工厂类创建对象方法为非静态
public BookDao getBookDao(){...}
② 修改配置文件
<!--方式三:使用实例化工厂实例化bean-->
<bean id="bookFactory" class="com.example.factory.BookDaoFactory"/>
<bean id="bookDao" factory-method="getBookDao" factory-bean="bookFactory"/>
③ 运行App2.java
改进:使用FactoryBean实例化(实用)
① 创建对应的FactoryBean类
package com.example.factory;
import com.example.dao.BookDao;
import com.example.dao.impl.BookDaoImpl;
import org.springframework.beans.factory.FactoryBean;
public class BookDaoFactoryBean implements FactoryBean<BookDao> {
//代替原始实例工程中创建对象的方法
public BookDao getObject() throws Exception {
return new BookDaoImpl();
}
public Class<?> getObjectType() {
return BookDao.class;
}
}
② 修改配置
<bean id="bookDao" class="com.example.factory.BookDaoFactoryBean"/>
③ 运行App2.java
若要获得非单例的对象,则在FactoryBean类中重写isSingleton方法
如
public boolean isSingleton() {
return false;
}
2.4.4 bean的生命周期
初始化容器
1.创建对象(内存分配)
2.执行构造方法
3.执行属性注入(set操作)
4.执行bean初始化方式
使用bean
1.关闭业务操作
关闭/销毁容器
1.执行bean销毁方法
① 在bean的类中编写初始化和销毁需要调用的方法
package com.example.dao.impl;
import com.example.dao.BookDao;
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初始化对应的操作
public void init(){
System.out.println("init...");
}
//表示bean销毁前对应的操作
public void destory(){
System.out.println("destroy...");
}
}
② 添加配置
<bean id="bookDao" class="com.example.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/>
③ 测试
package com.example;
import com.example.dao.BookDao;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AppForLifeCycle {
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//设置关闭钩子
ctx.registerShutdownHook();
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
/*暴力的关闭方法*/
// ctx.close();
}
}
另一种设置方式,不需要修改配置
继承InitializingBean, DisposableBean两个接口,重写对应方法即可
package com.example.service.impl;
import com.example.dao.BookDao;
import com.example.service.BookService;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {
//删除业务层中使用new的方式创建的dao对象
private BookDao bookDao;
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
//提供对应的set方法
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
public void destroy() throws Exception {
System.out.println("service destroy...");
}
public void afterPropertiesSet() throws Exception {
System.out.println("service init...");
}
}
2.5 依赖注入
思考:向一个类中传递数据的方式有几种?
1.普通方法(set方法)
2.构造方法
思考:依赖注入描述了在容器中建立bean与bean之间依赖关系的过程,如果bean运行需要的是数字或字符串呢?
1.引用类型
2.简单类型(基本数据类型与String)
注入方式:
Setter注入
1.简单类型
2.引用类型
构造器注入
1.简单类型
2.引用类型
2.5.1 Setter注入
引用类型注入
在之前已经使用过
① 在bean中定义引用类型属性并提供可访问的set方法
② 配置中使用property标签ef属性注入引用类型对象
若需要注入多个则写多个property
简单类型注入
① 在bean 中定义引用类型属性并提供可访问的set方法
package com.example.dao.impl;
import com.example.dao.BookDao;
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 BookDaoImpl(){
System.out.println("book dao constructor is running...");
}
public void save() {
System.out.println("book dao save ... " + connectionNum + "," + databaseName);
}
}
② 配置中使用property标签value属性注入简单类型数据
<bean id="bookDao" class="com.example.dao.impl.BookDaoImpl" >
<property name="databaseName" value="mysql"/>
<property name="connectionNum" value="10"/>
</bean>
2.5.2 构造器注入
标准书写,引用类型和简单类型注入
① 在bean的构造器中添加
package com.example.service.impl;
import com.example.dao.BookDao;
import com.example.service.BookService;
public class BookServiceImpl implements BookService{
private BookDao bookDao;
public BookServiceImpl(BookDao bookDao) {
this.bookDao = bookDao;
}
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
package com.example.dao.impl;
import com.example.dao.BookDao;
public class BookDaoImpl implements BookDao {
private int connectionNum;
private String databaseName;
public BookDaoImpl(){
System.out.println("book dao constructor is running...");
}
public BookDaoImpl(int connectionNum, String databaseName) {
this.connectionNum = connectionNum;
this.databaseName = databaseName;
}
public void save() {
System.out.println("book dao save ... " + connectionNum + "," + databaseName);
}
}
② 修改配置文件
<bean id="bookDao" class="com.example.dao.impl.BookDaoImpl" >
<constructor-arg name="databaseName" value="mysql"/>
<constructor-arg name="connectionNum" value="10"/>
</bean>
<bean id="bookService" class="com.example.service.impl.BookServiceImpl">
<constructor-arg name="bookDao" ref="bookDao"/>
</bean>
解决构造器传参的耦合高的两种解决方案
1.配置中使用constructor-arg标签type属性设置按形参类型注入
<bean id="bookDao" class="com.example.dao.impl.BookDaoImpl" >
<constructor-arg type="java.lang.String" value="mysql"/>
<constructor-arg type="int" value="10"/>
</bean>
2.配置中使用constructor-arg标签index属性设置按形参类型注入
<bean id="bookDao" class="com.example.dao.impl.BookDaoImpl" >
<constructor-arg index="1" value="mysql"/>
<constructor-arg index="0" value="10"/>
</bean>
2.5.3 依赖注入方式选择
1.强制依赖使用构造器进行,使用setter注入有概率不进行注入导致null对象出现
2.可选依赖使用setter注入进行,灵活性强
2.Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨
3.如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用setter注入完成可选依赖的注入
4.实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注入
5.自己开发的模块推荐使用setter注入
2.5.4 依赖自动装配
IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配
自动装配方式
1.按类型(常用)
2.按名称
3.按构造方法
4.不启用自动装配
配置中使用bean标签autowire属性设置自动装配类型(bean需要提供set方法)
<bean id="bookDao" class="com.example.dao.impl.BookDaoImpl" />
<bean id="bookService" class="com.example.service.impl.BookServiceImpl" autowire="byType"/>
依赖自动装配特征
- 自动装配用于引用类型依赖注入,不能对简单类型进行操作
- 使用按类型装配时(byType)必须保障容器中相同类型的bean唯一,推荐使用
- 使用按名称装配时(byName)必须保障容器中具有指定名称的bean,因变量名与配置耦合,不推荐使用
- 自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效
2.5.5 集合注入
① bean中添加集合对象
package com.example.dao.impl;
import com.example.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 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.example.dao.impl.BookDaoImpl">
<property name="array">
<array>
<value>100</value>
<value>200</value>
<value>300</value>
</array>
</property>
<property name="list">
<list>
<value>www</value>
<value>yyy</value>
<value>zzz</value>
</list>
</property>
<property name="set">
<set>
<value>www</value>
<value>yyy</value>
<value>zzz</value>
<value>zzz</value>
</set>
</property>
<property name="map">
<map>
<entry key="country" value="china"/>
<entry key="provice" value="zhejiang"/>
<entry key="city" value="hangzhou"/>
</map>
</property>
<property name="properties">
<props>
<prop key="country">china</prop>
<prop key="provice">zhejiang</prop>
<prop key="city">hangzhou</prop>
</props>
</property>
</bean>
</beans>
③ 测试
package com.example;
import com.example.dao.BookDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AppForDICollection {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
}
}
④结果
book dao save ...
遍历数组:[100, 200, 300]
遍历List[www, yyy, zzz]
遍历Set[www, yyy, zzz]
遍历Map{country=china, provice=zhejiang, city=hangzhou}
遍历Properties{provice=zhejiang, city=hangzhou, country=china}
2.6 IOC/DI配置管理第三方bean
2.6.1 案例:数据源对象管理
druid管理
① 添加druid坐标
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
② 配置 管理DruidDataSource对象
<!--管理DruidDataSource对象-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://192.168.1.224:3306/spring_db"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
③ 测试
package com.example;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import javax.sql.DataSource;
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);
}
}
c3p0
① 添加坐标
<!-- https://mvnrepository.com/artifact/c3p0/c3p0 -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
② 配置 管理DruidDataSource对象
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.cj.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://192.168.1.224:3306/spring_db"/>
<property name="user" value="root"/>
<property name="password" value="123456"/>
</bean>
③ 测试(运行App.java)
2.6.2 加载properties文件
① 在resource包下新建jdbc.properties(需要加载的properties文件)
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://192.168.1.224:3306/spring_db
jdbc.username=root
jdbc.password=123456
② 配置 读取properties文件
<?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
https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 1.开启context命名空间-->
<!-- 2.使用context命名空间加载properties文件-->
<context:property-placeholder location="jdbc.properties"/>
<!--3.使用属性占位符${}读取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>
1.如果遇到uername等加载不到,可能是与系统默认参数冲突,系统默认参数优先级较高
解决方法:在context:property-placeholder中添加system-properties-mode=“NEVER”
<context:property-placeholder location="jdbc.properties" system-properties-mode="NEVER"/>
2.多个配置文件可以通过逗号分隔,也可以使用classpath:*.properties
<context:property-placeholder location="classpath:\*.properties" system-properties-mode="NEVER"/>
加载类路径或jar包中的properties文件,使用classpath*😗.properties
2.7 核心容器
2.7.1 创建容器
方式一:类路径加载配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
方式二:文件路径加载配置文件
ApplicationContext ctx = new FileSystemXmlApplicationContext("D:\\applicationContext.xml");
方式三:加载多个配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("bean1.xml","bean2.xml");
2.7.2 获取bean
方式一:使用bean名称获取
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
方式二:使用bean名称获取并指定类型
BookDao bookDao = ctx.getBean("bookDao",BookDao.class);
方式三:使用bean类型获取
BookDao bookDao = ctx.getBean(BookDao.class);
2.7.3 容器相关
- BeanFactory是IoC容器的顶层接口,初始化BeanFactory对象时,加载的bean延迟加载
- ApplicationContext接口是Spring容器的核心接口,初始化时bean立即加载
- ApplicationContext接口提供基础的bean操作相关方法,通过其他接口扩展其功能
- ApplicationContext接口常用初始化类
- ClassPathXmlApplicationContext(常用)
- FileSystemXmlApplicationContext
2.8 注解开发
① 使用@Component定义bean
package com.example.dao.impl;
import com.example.dao.BookDao;
import org.springframework.stereotype.Component;
@Component("bookDao")
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
}
package com.example.service.impl;
import com.example.dao.BookDao;
import com.example.service.BookService;
import org.springframework.stereotype.Component;
@Component
public class BookServiceImpl implements BookService{
private BookDao bookDao;
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
//提供对应的set方法
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
}
② 在核心配置文件中通过组件扫描加载bean
<context:component-scan base-package="com.example" />
③ 测试
package com.example;
import com.example.dao.BookDao;
import com.example.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App2 {
public static void main(String[] args) {
//获取IoC容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取bean
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
System.out.println(bookDao);
BookService bookService = ctx.getBean(BookService.class);
System.out.println(bookService);
}
}
对于@Component注解,还衍生出了其他三个注解@Controller、@Service、@Repository
方便我们后期在编写类的时候能很好的区分出这个类是属于表现层、业务层还是数据层的类。
2.8.1 纯注解开发
Spring3.0开启了纯注解开发模式,使用Java类替代配置文件,开启了Spring快速开发赛道
Java类代替Spring核心配置文件
@Configuration注解用于设定当前类为配置类
@ComponentScan直接用于设定扫描路径
读取Spring核心配置文件初始化容器对象切换为读取Java配置类初始化容器对象
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
实验
① 创建类代替配置文件
package com.example.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("com.example")
public class SpringConfig {
}
② 初始化容器对象并使用
package com.example;
import com.example.config.SpringConfig;
import com.example.dao.BookDao;
import com.example.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
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);
}
}
2.8.2 注解开发bean作用范围与生命周期管理
bean作用范围
使用@Scope定义bean作用范围
package com.example.dao.impl;
import com.example.dao.BookDao;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;
@Repository
@Scope("prototype")
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
}
测试
package com.example;
import com.example.config.SpringConfig;
import com.example.dao.BookDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class AppForAnnotation {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
BookDao bookDao = ctx.getBean(BookDao.class);
BookDao bookDao2 = ctx.getBean(BookDao.class);
System.out.println(bookDao);
System.out.println(bookDao2);
}
}
bean生命周期
使用@PostConstruct,@PreDestroy定义bean生命周期
package com.example.dao.impl;
import com.example.dao.BookDao;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Repository
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
@PostConstruct
public void init(){
System.out.println("init...");
}
@PreDestroy
public void destroy(){
System.out.println("destroy...");
}
}
2.8.3 依赖注入——自动装配
使用@Autowired注解开启自动装配
注意:
- 自动装配基于反射设计创建对象并通过暴力反射为私有属性进行设值,因此无序提供setter方法
- 自动装配建议使用无参构造器方法创建对象(默认),如果不提供对应构造方法,请提供唯一的构造方法
使用@Qualifier注解指定开启指定名称装配bean
注意:@Qualifier注解无法单独使用,必须配合
使用@Value实现简单类型注入
实验
添加自动装配注解@Autowired注解使用
package com.example.service.impl;
import com.example.dao.BookDao;
import com.example.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
@Service
public class BookServiceImpl implements BookService{
@Autowired
private BookDao bookDao;
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
@Value简单类型注入
package com.example.dao.impl;
import com.example.dao.BookDao;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;
@Repository
public class BookDaoImpl implements BookDao {
@Value("test")
private String name;
public void save() {
System.out.println("book dao save ..." + name);
}
}
测试
package com.example;
import com.example.config.SpringConfig;
import com.example.service.BookService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class AppForAnnotation {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
BookService bookService = ctx.getBean(BookService.class);
bookService.save();
}
}
读取properties文件
创建需要读取的jdbc.Properties
name=test
修改配置
package com.example.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
@Configuration
@ComponentScan("com.example")
@PropertySource("jdbc.Properties")
public class SpringConfig {
}
使用jdbc.Properties中的内容
package com.example.dao.impl;
import com.example.dao.BookDao;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;
@Repository
public class BookDaoImpl implements BookDao {
@Value("${name}")
private String name;
public void save() {
System.out.println("book dao save ..." + name);
}
}
不支持*.properties,多文件使用数组的格式
2.8.4 管理第三方bean
使用@Bean配置第三方bean(创建独立配置文件)
package com.example.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import javax.sql.DataSource;
public class JdbcConfig {
//1.定义一个方法获得要管理的对象
//2.添加@Bean,表示当前方法的返回值是一个bean
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
ds.setUrl("jdbc:mysql://192.168.1.224:3306/spring_db");
ds.setUsername("root");
ds.setPassword("123456");
return ds;
}
}
将独立的配置文件导入核心配置
package com.example.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@Import({JdbcConfig.class})
public class SpringConfig {
}
测试
package com.example;
import com.example.config.SpringConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import javax.sql.DataSource;
public class App {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
DataSource dataSource = ctx.getBean(DataSource.class);
System.out.println(dataSource);
}
}
2.8.5 第三方bean注入资源
简单类型依赖注入和引用类型依赖注入
引用类型注入只需要为bean定义方法设置形参即可,容器会根据类型自动装在对象
package com.example.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.example.service.BookService;
import com.sun.javafx.binding.StringFormatter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import javax.sql.DataSource;
public class JdbcConfig {
//简单类型依赖注入
@Value("com.mysql.cj.jdbc.Driver")
private String drive;
@Value("jdbc:mysql://192.168.1.224:3306/spring_db")
private String url;
@Value("root")
private String username;
@Value("123456")
private String password;
//引用类型依赖注入
@Bean
public DataSource dataSource(BookService bookService){
System.out.println(bookService);
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(drive);
ds.setUrl(url);
ds.setUsername(username);
ds.setPassword(password);
return ds;
}
}
在核心配置中添加扫描注解
package com.example.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@ComponentScan("com.example")
@Import({JdbcConfig.class})
public class SpringConfig {
}