Spring
文章目录
- Spring
- Spring Framework 系统架构
- Spring学习路线
- 核心概念
- IoC(Inversion of Control)控制反转
- IoC入门案例思路分析
- DI入门案例思路分析
- Bean
- bean基础配置
- bean实例化
- bean是如何创建出来的
- 实例化bean的三种方式
- bean的生命周期
- 依赖注入方式DI
- setter注入:简单类型与引用类型
- 构造器注入:简单类型与引用类型
- 依赖注入方式选择
- 依赖自动装配
- 集合注入
- 数据源对象管理
- 第三方资源配置管理
- 容器
- 创建容器
- 获取bean
- 容器类层次结构
- BeanFactory
- 小结
- 注解开发
- 注解开发定义bean
- 纯注解开发
- bean作用范围,生命周期
- 依赖注入
- 自动装配
- 小结
- 管理第三方bean
- 第三方bean依赖注入
- 注解开发小结
- Spring Framework 是Spring生态圈中最基础的项目,是其他项目的根基。
Spring Framework 系统架构
- Data Access:数据访问
- Data Integration:数据集成
- Web:web开发
- AOP:面向切面编程
- Aspects:AOP思想实现
- Core Container:核心容器
- Test:单元与集成测试
Spring学习路线
核心概念
IoC(Inversion of Control)控制反转
- 目前代码书写现状:自己new对象,每次改动都需要动源代码,重新编译,导致耦合度偏高。
- 解决方案:在使用对象时,在程序中不要主动使用new产生对象,转换为,由外部提供对象
- IoC:控制反转,对象的创建控制权,给到外部,这种思想称为控制反转。(解耦)
- Spring技术对IoC思想进行了实现:
- Spring提供了一个容器,称为IoC容器,用来充当IoC思想中的外部,来提供对象。
- IoC容器负责对象的创建,初始化,等一系列工作,被创建或被管理的对象在IoC容器中统称为Bean.
- DI(Dependency Injection):依赖注入
- 在容器中建立bean与bean之间依赖关系的整个过程称为依赖注入。
- 目标:充分解耦
- 使用Ioc容器管理Bean(IoC)
- 在IoC容器内将有依赖关系的bean进行关系绑定(DI)
- 最终效果
- 使用对象时,不仅可以直接从IoC容器中获取,并且获取到的bean已经绑定了所有的依赖关系
IoC入门案例思路分析
- 管理什么?(service 与 Dao)
- 如何将被管理的对象告知IoC容器?(配置)
- 被管理的对象交给IoC容器,如何获取到IoC容器?(接口)
- IoC容器得到后,如何从容器中获取Bean?(接口方法)
- 使用Spring导入哪些坐标?(pom.xml)
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
DI入门案例思路分析
1.基于IoC管理bean
2.Service中使用new形式创建的Dao对象是否保留? (否)
3.Service中需要的Dao对象如何进入到Service中?(提供方法,往里传对象)
4.Service与Dao间的关系如何描述?(配置)
<bean id="bookDao" class = "com.ityc.dao.impl.BookDaoimpl"/>
<bean id="bookService" class = "com.ityc.service.impl.BookServiceImpl">
<!--7.配置service与Dao关系-->
<!--
property标签,表示配置当前bean的属性
name表示配置哪一个具体的属性
ref表示参照哪一个bean
-->
<property name="bookDao" ref="bookDao"/>
</bean>
Bean
注:
NoSuchBeanDefinitionException: No bean named 'serviceEbi1' available
没有名为“serviceEbi1”的bean可用,需要检查bean id 与 name是否
bean基础配置
<!--配置bean-->
<!--bean标签表示配置bean-->
<!--id 属性标签表示给bean起名字-->
<!--class 属性表示给bean定义类型-->
<!--scope 属性默认单例模式singleton, 需要非单例时需要给一个prototype,-->
<bean id="bookDao" name="dao" class = "com.ityc.dao.impl.BookDaoimpl" scope="prototype"/>
<bean id="bookService" name="service service2 serviceEbi" class = "com.ityc.service.impl.BookServiceImpl">
<!--7.配置service与Dao关系-->
<!--
property标签,表示配置当前bean的属性
name表示配置哪一个具体的属性
ref表示参照哪一个bean
-->
<property name="bookDao" ref="bookDao"/>
</bean>
- 思考为什么bean默认单例?
害怕造出无限多个bean,防止用一次造一个 - spring帮我们管理对象时,实际上就是帮我们管理我们可以复用的对象,来提高效率
- 适合交给容器管理的bean
- 表现层对象
- 业务层对象
- 数据层对象
- 工具对象
- 不适合交给bean管理的对象
- 封装实体的域对象
bean实例化
bean是如何创建出来的
- bean本质就是对象,创建bean使用构造方法完成
实例化bean的三种方式
使用构造方法实例化bean(常用)
- 提供可访问的构造方法
public class BookServiceImpl implements BookService {
public BookServiceImpl(){
System.out.println("book Service is running");
}
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
- 配置
<bean id="bookService" class = "com.ityc.dao.impl.BookServiceimpl" />
注:如果无参构造方法不存在,则抛出BeanCreationException:Bean创建异常
通过工厂的方式:早些年常用,通过工厂进行一定程度上的解耦。(了解)
<!--方式二:使用静态工厂实例化bean-->
//吊创建对象的方法factory-method
<bean id="orderDao" class="com.itheima.factory.OrderDaoFactory" factory-method="getOrderDao"/>-->
<!--方式三:使用实例工厂实例化bean-->
//首先获得工厂bean,获得 工厂bean,但是工厂bean并不能直接调实例对象的方法
<bean id="userFactory" class="com.itheima.factory.UserDaoFactory"/>
<bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>
方式四:经常使用, FactoryBean实用
public class UserDaoFactoryBean implements FactoryBean<UserDao> {
//代替原始实例工厂中创建对象的方法
//得到bean实例
public UserDao getObject() throws Exception {
return new UserDaoImpl();
}
//得到bean类型
public Class<?> getObjectType() {
return UserDao.class;
}
//控制是否单例
public boolean isSingleton() {
//true即位单例,false为非单例
return true;
}
//注scope与isSingleton()同时使用时以 isSingleton()为主
}
}
<!--方式四:使用FactoryBean实例化bean-->
<bean id="userDao" class="com.itheima.factory.UserDaoFactoryBean"/>
//注这里造出来的对象实际上不是factory对象,因为factory对象是无法直接调用创建兑现方法的
//所以这里的对象应该是工厂类中实际创建对象的getObject()方法的对象
bean的生命周期
- 生命周期:从创建到消亡的过程
- bean生命周期,bean从创建到销毁的整体过程
- bean生命周期控制:在bean创建后到销毁前做的一些事情
配置
<!--init-method:设置bean初始化生命周期回调函数-->
<!--destroy-method:设置bean销毁生命周期回调函数,仅适用于单例对象-->
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" init-method="init" destroy-method="destroy"/>
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
<property name="bookDao" ref="bookDao"/>
</bean>
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...");
}
}
public class AppForLifeCycle {
public static void main( String[] args ) {
//ClassPathXmlApplicationContext,整个实现类中有close关闭容器的方法
ClassPathXmlApplicationContext ctx =ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
//注册关闭钩子函数,在虚拟机退出之前回调此函数,关闭容器
ctx.registerShutdownHook();
//关闭容器,暴力关闭,遇到此方法容器直接关闭,此行代码后不能继续进行容器操作
//ctx.close();
}
}
spring的要求:
- 根据提供的接口
InitializingBean, DisposableBean
- 覆盖接口中的需要的方法
public void destroy() throws Exception {
System.out.println("service destroy");
}
//属性设置以后才去运行的操作
public void afterPropertiesSet() throws Exception {
System.out.println("service init");
}
- 配置
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
<property name="bookDao" ref="bookDao"/>
</bean>
- 初始化容器:
- 创建对象,分配内存
- 执行构造方法
- 执行属性注入,set操作
- 执行bean初始化方法
- 使用bean
- 执行业务操作
- 关闭销毁容器
- 执行bean销毁方法(容器关闭前出发bean的销毁)
- 关闭容器的方式:两种
public static void main( String[] args ) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
//注册关闭钩子函数,在虚拟机退出之前回调此函数,关闭容器
//ctx.registerShutdownHook();
//关闭容器
ctx.close();
}
依赖注入方式DI
- 思考:向一个类中传递数据的方式有几种?
- 普通方法(set方法)
- 构造方法
- 思考:依赖注入描述了在容器中建立bean与bean之间依赖关系的过程,如果bean运行需要的是数字或字符串呢?
- 引用类型
- 简单类型(基本数据类型与String)
setter注入:简单类型与引用类型
- 在bean中定义简单类型属性。并提供可访问的set方法
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标签,vulue属性注入简单类型数据-->
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
<!--property标签:设置注入属性-->
<!--name属性:设置注入的属性名,实际是set方法对应的名称-->
<!--value属性:设置注入简单类型数据值-->
<property name="connectionNum" value="100"/>
<property name="databaseName" value="mysql"/>
</bean>
- 在bean中定义引用类型属性。并提供对应set方法
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属性注入引用类型对象
<!--注入引用类型-->
<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>
构造器注入:简单类型与引用类型
- 简单类型
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);
}
}
- 引用类型
public class BookServiceImpl implements BookService{
private BookDao bookDao;
private UserDao userDao;
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();
}
}
- 配置文件:改动处:constructor-arg
<!--
标准书写
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
根据构造方法参数名称注入
<constructor-arg name="connectionNum" value="10"/>
<constructor-arg name="databaseName" 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>
-->
<!--
解决形参名称的问题,与形参名不耦合
<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>-->
<!--解决参数类型重复问题,使用位置解决参数匹配-->
<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方法就必须使用构造器注入。
- 自己开发的模块推荐使用setter注入。
依赖自动装配
- IoC容器根据bran所依赖的资源在容器中自动查找并注入到bran中的过程称为自动装配
- 自动装配的方式:
- 按类型(常用)
- 按名称
- 按构造方法
- 不启用自动装配
public 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();
}
}
<bean class="com.itheima.dao.impl.BookDaoImpl"/>
<!--autowire属性:开启自动装配,通常使用按类型装配-->
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl" autowire="byType"/>
注意:
- 自动装配用于引用类型依赖注入,不能对简单类型进行操作。
- 使用按类型装配时(byType)必须保障容器中相同类型的bean唯一,推荐使用
- 使用按名称装配时,(byName)必须保证容器中具有指定名称的bean,因变量名与配置耦合,不推荐使用。
- 自动装配优先级低于stter注入与构造器注入,同时出现时,自动装配失效。
集合注入
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.itheima.dao.impl.BookDaoImpl">
<!--数组注入-->
<property name="array">
<array>
<value>100</value>
<value>200</value>
<value>300</value>
</array>
</property>
<!--list集合注入-->
<property name="list">
<list>
<value>ityc</value>
<value>gityc</value>
<value>hub</value>
</list>
</property>
<!--set集合注入-->
<property name="set">
<set>
<value>YC</value>
<value>ityc</value>
<value>gityc</value>
<value>hub</value>
<value>hub</value>
<value>hub</value>
</set>
</property>
<!--map集合注入-->
<property name="map">
<map>
<entry key="country" value="china"/>
<entry key="province" value="ShanXi"/>
<entry key="city" value="YC"/>
</map>
</property>
<!--Properties注入-->
<property name="properties">
<props>
<prop key="country">Chian</prop>
<prop key="province">ShanXi</prop>
<prop key="city">YC</prop>
</props>
</property>
</bean>
数据源对象管理
第三方资源配置管理
//pom.xml
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
//applicationContext.xml
<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>
- 管理c3p0
<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.47</version>
</dependency>
<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.我们的配置c3p0或druid时会出现在配置中将用户名密码等写死的情况,所以我们可以使用spring中加载properties文件,在properties中写用户名密码等等。
- 步骤一:在spring配置文件中开启一个新的命名空间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
">
- 步骤二:使用context空间加载properties文件
<!-- 1.开启context命名空间-->
<!-- 2.使用context空间加载properties文件-->
<!-- <context:property-placeholder location="jdbc.properties" system-properties-mode="NEVER"/>-->
<!-- <context:property-placeholder location="jdbc.properties,jdbc2.properties" system-properties-mode="NEVER"/>-->
<!-- classpath:*.properties : 设置加载当前工程类路径中的所有properties文件-->
<!-- system-properties-mode属性:是否加载系统属性-->
<!-- <context:property-placeholder location="*.properties" system-properties-mode="NEVER"/>-->
<!-- classpath:*.properties : 设置加载当前工程类路径中的所有properties文件-->
<!--classpath*:*.properties : 设置加载当前工程类路径和当前工程所依赖的所有jar包中的所有properties文件-->
<context:property-placeholder location="classpath*:*.properties" system-properties-mode="NEVER"/>
- 步骤三:使用属性占位符${}读取properties文件中的属性
<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>
容器
创建容器
- 方式一:类路径加载配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
- 方式二:文件路径加载配置文件
ApplicationContext ctx = new FileSystemXmlApplicationContext("D:\\workspace\\spring\\spring_10\\src\\main\\resources\\applicationContext.xml");
- 加载多个配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("bean1.xml","bean2.xml");
public class App {
public static void main(String[] args) {
//1.加载类路径下的配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//2.从文件系统下加载配置文件
// ApplicationContext ctx = new FileSystemXmlApplicationContext("D:\\workspace\\spring\\spring_10_container\\src\\main\\resources\\applicationContext.xml");
// BookDao bookDao = (BookDao) ctx.getBean("bookDao");
// BookDao bookDao = ctx.getBean("bookDao",BookDao.class);
// BookDao bookDao = ctx.getBean(BookDao.class);
// bookDao.save();
}
}
获取bean
- 方式一:使用bean的名称获取
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
- 方式二:使用bean名称获取指定类型
BookDao bookDao = ctx.getBean("bookDao",BookDao.class);
- 方式三:使用bean类型获取,前提是容器中整个类型的bean只能有一个
BookDao bookDao = ctx.getBean(BookDao.class);
容器类层次结构
BeanFactory
最早期的spring创建容器方式,是所有容器类的顶层接口。
小结
- 容器相关
- BeanFactory是IoC容器的顶层接口,初始化BeanFactory对象时,加载bean延迟加载。
- ApplicationContext接口是Spring容器的核心接口,初始化时bean立即加载。
- ApplicationContext接口提供基础的bean操作相关方法,通过其他接口扩展其功能。
- ApplicationContext接口常用初始化类
- ClassPathXmlApplicationContext:类加载配置文件(常用)
- FileSystemXmlApplictionContext:绝对路径加载配置文件
- bean相关
- 依赖注入相关
注解开发
注解开发定义bean
- Spring提供@Component注解的三个衍生注解
- @Controller:用于表现层bean定义
- @Service:用于业务层bean定义
- @Repository:用于数据层bean定义
- 注注解开发需要配合扫描使用
<context:component-scan base-package="com.itheima"/>
例:
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
}
@Service
public 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();
}
}
public class AppForAnnotation {
public static void main(String[] args) {
//AnnotationConfigApplicationContext加载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);
}
}
纯注解开发
- Spring3.0升级了纯注解开发模式,使用Java类替代配置文件,开启了Spring快速开发赛道
- Java类代替Spring核心配置文件
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 {
}
public class AppForAnnotation {
public static void main(String[] args) {
//AnnotationConfigApplicationContext加载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作用范围,生命周期
@Repository
//@Scope设置bean的作用范围
//@Scope("singleton")单例 @Scope("prototype")非单例
@Scope("singleton")
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
//@PostConstruct设置bean的初始化方法
@PostConstruct
public void init() {
System.out.println("init ...");
}
//@PreDestroy设置bean的销毁方法,和之前一样,因为java虚拟机直接退出,会导致我们的bean销毁方法来不及执行,所以要有关闭钩子
@PreDestroy
public void destroy() {
System.out.println("destroy ...");
}
}
public class App {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
BookDao bookDao1 = ctx.getBean(BookDao.class);
BookDao bookDao2 = ctx.getBean(BookDao.class);
System.out.println(bookDao1);
System.out.println(bookDao2);
ctx.close();//销毁方法,先当于关闭钩子,暴力,会不管之后的方法直接结束
}
}
依赖注入
自动装配
//Dao层
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
//@Value:注入简单类型(无需提供set方法)
@Value("${name}")
private String name;
public void save() {
System.out.println("book dao save ..." + name);
}
}
//Service层
@Service
public 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();
}
}
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
//Spring配置;类
@Configuration
@ComponentScan("com.itheima")
//@PropertySource加载properties配置文件
//这不支持使用通配符*
@PropertySource({"jdbc.properties","jdbc.properties2","jdbc.properties3+"})
public class SpringConfig {
}
//也可以
@PropertySource({"classpath:jdbc.properties","classpath:jdbc.properties2","classpath:jdbc.properties3"})
public class SpringConfig {
}
小结
- 自动装配
- @Autowired:注入引用类型,自动装配模式,默认按类型装配
- @Qualifier:自动装配bean时按bean名称装配
- @Value:注入简单类型,无需提供set方法
- 读取properties文件
- @PropertySource加载properties配置文件
- 注意:
- 自动装配基于反射设计创建对象并暴力反射对应属性为私有属性初始化数据,因此无需提供setter方法.
- 注意:自动装配建议使用无参构造方法创建对象(默认),如果不提供对应构造方法,请提供唯一的构造方法.
管理第三方bean
在Spring配置文件中
@Configuration
@ComponentScan("com.itheima")
public class SpringConfig {
//1.定义一个方法获得要管理的对象
//2.添加 @Bean注解,表示当前方法的返回值是一个bean
@Bean("dataSource")
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("root");
return ds;
}
}
产生问题:这个是我Spring的配置文件,我jdbc有关的配置都写在这里不太好,会写爆
- 所以在Spring中这些配置类都由专门的类来管理
在config中再建一个专门用于jdbc等第三方bean的类
public class JdbcConfig {
//2.添加@Bean,表示当前方法的返回值是一个bean
//@Bean修饰的方法,形参根据类型自动装配
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName();
ds.setUrl();
ds.setUsername();
ds.setPassword(;
return ds;
}
}
再spring配置类中加载我们建立的第三方配置类@Import({JdbcConfig.class})
@Configuration
//@Import:导入配置信息
@Import({JdbcConfig.class})
public class SpringConfig {
}
第三方bean依赖注入
- 引用类型:用方法形参,非常简单,再@Bean注解的方法中注入对应的形参,就ok。
- 简单类型用成员变量
public 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(BookDao bookDao){
System.out.println(bookDao);
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);
ds.setPassword(password);
return ds;
}
}
注解开发小结