概述
Spring 体系概述
- Spring 是于2003年兴起的一个 full-stack 轻量级的 Java 开源框架,由 Rod Johnson 创建,使用 Spring 可以更快、更轻松、更安全地进行 Java 编程
- Spring 是一个生态体系,或一个超级粘合平台,常见的 Spring 项目有:Spring Boot,Spring Framework,Spring Data,Spring Cloud,Spring Cloud Data Flow,Spring Security,Spring GraphQL,Spring Session 和 Spring Web Services 等
- Spring 提供了展现层 Spring MVC、持久层 Spring JDBC、业务层事务管理等众多的企业级应用技术,Spring 还能整合开源世界众多的第三方框架和类库,逐渐成为使用最多的 Java EE企业应用开源框架
- Spring 并不等同于 Spring 框架(Spring Framework),这是常见的误区
Spring 框架(Spring Framework)
概述
- Spring 框架,即 Spring Framework 框架,是 Spring 生态的其中一个重要项目,也是其他 Spring 全家桶(SpringMVC、SpringBoot、SpringCloud、SpringData等)的基础和核心
- Spring 框架分为多个模块,应用程序可以选择需要的模块。Spring 框架的核心是 Core Container(核心容器)模块,包括配置模型和依赖注入机制
- Spring 框架为不同的应用程序架构提供基础支持,包括消息传递、事务数据和持久性以及 Web
- Spring 框架还包括基于 Servlet 的 Spring MVC Web 框架,以及并行的 Spring WebFlux 反应式 Web 框架
- Spring 框架是分层的JavaSE/EE一站式轻量级开源框架,以 IOC(控制反转)和 AOP (面向切面编程)为核心
Spring 框架的特点
- 方便解耦,简化开发:将所有对象的创建和依赖关系维护交给Spring管理
- 方便集成各种优秀框架:Spring内部提供了对各种优秀框架(Struts2、Hibernate、MyBatis)的直接支持
- 降低了Java EE API 使用难度:对 JAVA EE开发中一些API( JDBC、JavaMail、远程调用)都提供了封装
- 方便程序测试:支持 JUnit4,可以通过注解方便地测试 Spring 程序
- AOP变成支持:面向切面编程,可以方便地实现对程序进行权限拦截和运行监控等功能
- 声明式事务:通过配置就可以完成对事务的管理,无需编程
Spring 框架的架构和模块说明
Spring 框架的主要模块
Core Container(核心容器)
是其他模块建立的基础,由 Beans 模块、Core 核心模块、Context 上下文模块和 SpEL 表达式语言模块组成
Core(spring-core):封装了Spring框架的底层部分,包括资源访问、类型转换以及Spring 框架基本的核心工具类
Spring 其它组件要都要使用到这个包里的类,是其它组件的基本核心,也可以在自己的应用系统中使用这些工具类
- 外部依赖:Commons Logging, (Log4J)
- jar包:org.springframework spring-core 4.3.7.RELEASE
Beans(spring-beans):提供了框架的基础部分,包括访问配置文件、控制反转(IOC)和依赖注入(DI)
- 外部依赖:spring-core
- jar包:org.springframework spring-beans 4.3.7.RELEASE
SpEL(spring-expression):提供了强大的表达式语言支持,用于在运行时查询和处理对象图。该语言支持设置和获取属性值;属性赋值,方法调用,访问数组的内容,收集和索引器,逻辑和算术运算,命名变量,并从Spring的IOC容器的名字对象检索,它也支持列表选择和投影以及常见的列表聚合
- jar包:org.springframework spring-expression 4.3.7.RELEASE
Context(spring-context):上下文模块,建立在 Core 和 Beans 模块的基础之上,集成Beans模块并添加资源绑定、数据验证、国际化、Java EE支持、容器生命周期、事件传播等
为Spring 核心提供了大量扩展。可以找到使用Spring ApplicationContext特性时所需的全部类,JDNI 所需的全部类,instrumentation组件以及校验Validation 方面的相关类。
- 外部依赖:spring-core,spring-beans,spring-expression,spring-aop
- jar包:org.springframework spring-context 4.3.7.RELEASE
依赖关系:
Data Access/Integration(数据访问与集成)
包含模块:JDBC、ORM、OXM、JMS、Transaction
JDBC(spring-jdbc):包含对Spring 对JDBC 数据访问进行封装的所有类
- jar包:org.springframework spring-jdbc 4.3.7.RELEASE
- ORM(spring-orm):提供了与“对象-关系”映射框架集成的API,包括 JPA、JDO、Hibernate、MyBatis等。
- OXM(spring-oxm):提供了 Object/XML 映射的抽象层实现,如 JAXB、Castor、XMLBean、JiBX、XStream
将 java对象映射成为XML数据,或者将 XML 数据映射成java对象
- JMS(spring-jms):java消息服务,提供了一套“消息生产者、消息消费者”模板,JMS用于两个应用程序之间,或者分布式系统中发送消息,进行异步通信
Transaction(spring-tx):事务控制,为JDBC、Hibernate、JDO、JPA、Beans等提供的一致的声明式和编程式事务管理支持
- jar包:org.springframework spring-tx 4.3.7.RELEASE
依赖关系:
Web
包括模块:Web、servlet、websocket、portlet
Web(spring-web):提供了基本web集成特性,例如:多文件上传、使用 Servlet 监听器的 IOC 容器初始化以及 web 应用上下文
包含Web 应用开发时,用到Spring 框架时所需的核心类,包括自动载入Web ApplicationContext 特性的类、Struts 与JSF 集成类、文件上传的支持类、Filter 类和大量工具辅助类
- jar包:org.springframework spring-web 4.3.7.RELEASE
servlet(spring-webmvc):提供了 SpringMVC Web 框架实现。SpringMVC 提供了基于注解的请求资源注入、更简单的数据绑定、数据验证等以及一套非常简易的 JSP 标签
包含Spring MVC 框架相关的所有类,包括框架的Servlets,Web MVC框架,控制器和视图支持
如果应用使用了独立的MVC 框架,则无需这个JAR 文件里的任何类
- jar包:org.springframework spring-webmvc 4.3.7.RELEASE
- WebSocket:提供了简单的接口,用户只需要实现接口就可以快速搭建 websocket server,从而实现双向通讯
- Portlet(spring-webmvc-portlet):提供了Portlet环境中MVC实现
依赖关系:
AOP、aspects、spring-instrument 、messaging
aop部分包含4个模块
AOP(spring-aop):提供了面向切面编程,提供了比如日志记录、权限控制、性能统计等通用功能和业务逻辑分离的技术,并且能动态把这些功能添加到需要的代码中
- jar包:org.springframework spring-aop 4.3.7.RELEASE
Aspects(spring-aspects):提供与AspectJ的集成,是一个功能强大且成熟的面向切面编程框架
以便可以方便的将面向方面的功能集成进IDE中,比如Eclipse AJDT
- jar包:org.springframework spring-aspects 4.3.7.RELEASE
- InStrumentation(spring-instrument):检测,提供了类工具的支持和类加载器的实现
- Messaging(消息处理):提供了对消息传递体系结构和协议的支持
依赖关系:
- Test:Spring 支持 Junit 和 TestNG 测试框架,而且还额外提供了一些基于 Spring 的测试功能。
Spring 框架 的 API 体系
Spring Framework 的API体系异常庞大,暂时只介绍 BeanFactory 和 ApplicationContext:
BeanFactory
- BeanFactory 是 Spring 的"心脏",IOC 容器的核心接口,定义了IOC的基本功能
- Spring 使用它来配置文档,管理bean的加载,实例化并维护bean之间的依赖关系,负责bean的声明周期
ApplicationContext
- ApplicationContext 由 BeanFactory 派生而来,可以比喻为Spring的躯体
ApplicationContext 在 BeanFactory 的基础上添加了很多功能:
- 支持了 aop 功能和 web 应用
- MessageSource,提供国际化的消息访问
- 通过配置来实现 BeanFactory 中很多编码才能实现的功能
ApplicationContext 的常用实现类:
- ClassPathXmlApplicationContext:从classpath目录读取配置文件
- FileSystemXmlApplicationContext:从文件系统或者url中读取配置文件
- AnnotationConfigApplicationContext:读取注解。当使用注解配置容器对象时,需要使用此类来创建 spring
容器
BeanFactory 和 ApplicationContext 的区别:
- beanFactory 主要是面向 Spring 框架的基础设施,也就是供 spring 自身内部调用
Applicationcontext 主要面向 Spring 的使用者
- BeanFactroy 是在第一次使用到某个Bean(调用getBean()方法)时,才对该Bean进行加载实例化
ApplicationContext 是在容器启动时,一次性创建并加载了所有的Bean
Spring Boot 框架概述
- Spring Boot 也是 Spring 生态中一个极其重要的项目,Spring Boot 是对 Spring Framework 的扩展,也可以说它是一个服务于框架的框架,其设计目的是用来简化新 Spring 应用的初始搭建以及开发过程
- Spring Boot 的服务范围是简化配置文件,它消除了设置 Spring 应用程序所需的XML配置,即尽可能的自动配置 Spring 应用
- Spring Boot 直接嵌入了 Tomcat、Jetty 或 Undertow(无需部署WAR文件),并且提供生产就绪功能,例如指标、运行状况检查和外部化配置等等,为更快和更高效的开发应用程序铺平了道路
IOC(控制反转)
IOC概述、IOC 容器工作原理
IOC(控制反转)是一种设计思想,目的是指导设计出更加松耦合的程序:
- 控制:指的是对象控制权,在 java 中可以简单理解为对象的控制权限(比如对象的创建、销毁等权限)
- 反转:指的是将对象的控制权由原来的程序员在类中主动控制反转到由 Spring 容器来控制
- 主要功能:解耦
Spring IOC 容器 是对 IOC 思想的一种实现:
- 对象的创建交由 Spring 框架管理,需要对象时从 Spring IOC 容器中获取即可
- 底层原理:反射
Spring 的 IOC容器 工作原理:
- 当 Spring 的 IOC 容器加载时,会读取配置文件中的诸多 bean 配置
- 根据 bean 的 class 的值寻找对应的 Class 字节码文件
- 通过反射技术,创建出一个个对象
- 创建的对象会被存放到内部的一个 Map 结构中,等待被使用
- 当需要使用具体的对象时就无须手动创建,而是直接从 Spring 的IOC容器中
Spring IOC 的入门案例(xml)
案例:通过Spring中内置的容器获取对象
操作步骤:
- 创建工程导入依赖
- 配置接口和实现类
- 编写Spring的配置文件
- 测试:从容器中获取对象
创建工程导入依赖
<dependencies>
<!--spring的坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<!--单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
创建Dao接口和实现类(略)
创建Spring配置文件
- spring配置文件约定俗称:applicationContext.xml
- spring配置文件放置到:resource目录下
- spring配置文件,需要引入名称空间(约束)
- 在spring的配置文件中通过
<bean>
标签,定义对象id和实现类全类名
在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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--
定义配置信息
id:唯一标志(获取的时候,调用容器的getBean("id"))
class:实现类的全限定类名
-->
<!--把数据库连接池对象放入IOC容器-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql:///spring"/>
<property name="user" value="root"/>
<property name="password" value="root"/>
</bean>
<!--把QueryRunner放入到IOC容器中-->
<bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner">
<constructor-arg name="ds" ref="dataSource"/>
</bean>
<!--把dao对象交给IOC容器-->
<bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
<property name="queryRunner" ref="queryRunner"/>
</bean>
<!--把service交给IOC容器-->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
</bean>
</beans>
测试
import cn.test.dao.UserDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* 测试从容器中获取对象
*/
public class UserDaoTest {
public static void main(String[] args) {
//1、根据配置文件获取容器
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
//2、调用容器的方法,获取对象
UserDao userDao = (UserDao)ac.getBean("userDao");
//3、测试
userDao.save();
}
}
执行过程分析
初始化 Spring Bean 对象(xml)
方式1:默认无参构造函数
IOC容器通过反射调用,根据默认无参构造函数来创建类对象。如果 bean 中没有默认无参构造函数,将会创建失败。
<bean id="userDao" class="cn.test.dao.impl.UserDaoImpl"></bean>
方式2:工厂模式创建对象
在Spring中还可以通过工厂模式来创建对象。工厂模式又分两种:
- 静态工厂:不产生工厂的实例,直接调用工厂的静态方法创建对象
- 实例工厂:先产生工厂的实例,再调用工厂实例的方法创建对象
(1)java代码编写工厂类
public class FactroyCreateBean {
// 静态工厂
public static UserDao createUserDao(){
return new UserDaoImpl();
}
// 实例工厂
public UserDao createUserDaoSimple(){
return new UserDaoImpl();
}
}
(2)xml配置文件配置
<!--使用静态工厂创建对象-->
<bean id="userDao1" class="cn.test.factory.FactroyCreateBean" factory-method="createUserDao"/>
<!--使用实例工厂创建对象-->
<bean id="factroyCreateBean" class="cn.test.factory.FactroyCreateBean"/>
<bean id="userDao2" factory-bean="factroyCreateBean" factory-method="createUserDaoSimple"/>
Spring Bean 的生命周期
概述、生命周期流程图
Bean对象生命周期指的是Bean创建到销毁的这么一段时间。
粗粒度生命周期:
- spring中单例对象的生命周期为:
出生:IOC容器加载时出生
存活:IOC容器运行时存活
死亡:IOC容器销毁时死亡
- spring中多例对象的生命周期为:
出生:使用对象时出生
存活:一直存活
死亡:由java垃圾回收器负
细粒度生命周期:
出生过程
- 实例化bean对象【IOC】
- 为对象属性赋值【DI】
- 处理实现的Aware接口
① 如果这个Bean已经实现了 BeanNameAware 接口,会调用它实现的 setBeanName(String beanId) 方法,此处传递的就是Spring配置文件中Bean的id值。
② 如果这个Bean已经实现了 BeanFactoryAware 接口,会调用它实现的 setBeanFactory() 方法,传递的是Spring工厂自身。
③ 如果这个Bean已经实现了 ApplicationContextAware 接口,会调用 setApplicationContext(ApplicationContext) 方法,传入Spring上下文。
- 通过 BeanPostProcessor 接口的 postProcessBeforeInitialization 方法对bean对象进行预处理
- 通过 InitializingBean 接口的 afterPropertiesSet 方法对bean对象进行处理
- 通过指定 init-method 方法对bean对象进行处理
- 通过 BeanPostProcessor 接口的 postProcessAfterInitialization 方法对bean对象进行后处理,这一步bean对象已经彻底创建成功了,可以做一些类似缓存的工作
死亡过程
- 如果Bean实现了 DisposableBean 接口,会调用其实现的 destroy() 方法。
- 如果指定 destroy-method 方法,可以在bean对象销毁前自动执行。
生命周期流程图
测试案例:
public class UserDaoImpl implements UserDao, BeanNameAware, BeanFactoryAware,ApplicationContextAware, InitializingBean, DisposableBean {
public UserDaoImpl() {
System.out.println("IOC");
}
private Integer id;
public void setId(Integer id) {
System.out.println("DI");
this.id = id;
}
@Override
public void setBeanName(String s) {
System.out.println("BeanNameAware:"+s);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("BeanFactoryAware");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("ApplicationContextAware");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean的afterPropertiesSet");
}
public void initMethod(){
System.out.println("init-method");
}
@Override
public void save() {
System.out.println("保存成功!");
}
@Override
public void destroy() throws Exception {
System.out.println("DisposableBean的destroy");
}
public void destroyMethod(){
System.out.println("destroy-method");
}
}
public class MyBeanProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeanPostProcessor的before");
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeanPostProcessor的after");
return 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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl" init-method="initMethod" destroy method="destroyMethod">
<property name="id" value="1"/>
</bean>
<bean class="com.itheima.processor.MyBeanProcessor"/>
</beans>
// 测试类
public class UserDaoImplTest {
@Test
public void save() {
ClassPathXmlApplicationContext ac = new
ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = ac.getBean(UserDao.class);
userDao.save();
ac.close();
}
}
Spring Bean 的作用域
参考:https://blog.csdn.net/weixin_38676276/article/details/90382350
- singleton:单例。在Spring IOC容器中仅存在一个共享的Bean实例。默认值
当spring创建applicationContext容器的时候,spring会初始化所有的该作用域实例,加上lazy-init则可以避免预处理
- prototype:原型(多例)
每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()相当于执行new XxxBean()
创建后spring将不再对其管理
(下面是在web项目下才用到的作用域)
- request:仅在当前HTTP request内有效
每次HTTP请求都会创建一个新的Bean
spring创建后会继续监听,当处理请求结束后销毁实例
- session:仅在当前HTTP Session内有效
同一个HTTP Session共享一个Bean,不同Session使用不同Bean
spring创建后会继续监听,当HTTP Session最终被废弃时,在该HTTP Session作用域内的bean也会被废弃掉
- global-session:全局的web域。类似于servlet中的application。一般用于Portlet应用环境
定义 Bean 的配置信息(xml)
- id:唯一标志(获取的时候,调用容器的getBean("id"))
- class:实现类的全限定类名
- scope:对象作用域(singleton(默认) | prototype | request | session | global-session)
- init-method:对象创建成功之后,指定的初始化方法
- destroy-method:容器关闭对象销毁之前,执行的销毁方法
只有在scope=singleton(单例)的时候,才有效
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl" scope="prototype"
init-method="init" destroy-method="destroy"/>
依赖注入(xml)
依赖注入:Dependency Injection(DI)。 它是 spring 框架核心 IOC 的具体实现。在编写程序时, 通过控制反转,把对象的创建交给了 spring,然后在代码中需要对象时,进行依赖对象的注入。
IOC 具有两个功能:依赖查找,依赖注入
本质:向对象中的私有属性赋值
- 构造方法
- set方法调用
构造方法注入
- 向对象中添加有参构造方法
public class UserServiceImpl implements UserService {
private String name;
private Integer age;
public UserServiceImpl(String name, Integer age) {
this.name = name;
this.age = age;
}
@Override
public void save() {
System.out.println(name + age);
}
}
- 在spring的配置文件中,通过bean标签配置对象创建(需要添加构造方法参数)
<!--
constructor-arg 设置对象的构造方法参数 (一个参数配置一个constructor-arg标签)
name:构造参数名
type:构造参数类型
index:构造参数,参数索引位置(从0开始)
以上三个属性,用于定位构造方法参数位置(三选一即可)
value: 对基本数据类型的参数赋值(8大数据类型 + String)
ref: 对对象属性的参数赋值。即必须得是在配置文件中配置过的bean
以上两个属性,用于对构造参数赋值
-->
<bean id="userService" class="cn.test.service.impl.UserServiceImpl">
<constructor-arg name="age" value="12"></constructor-arg>
<constructor-arg name="name" value="王者荣耀"></constructor-arg>
</bean>
set 方法注入
- 提供属性的set方法
在spring配置文件中,通过bean结合property配置set方法调用
<bean id="book" class="com.itheima.spring.Book"> <!-- name:找的是类中 set 方法后面的部分 ref:给属性赋值(其他bean类型) value:给属性赋值(8大基本数据类型 + string类型) --> <property name="name" value="程序员" /> <property name="price" value="1" /> <property name="publishDate" ref="date" /> </bean>
注入复杂类型(集合)
给类中的集合成员传值,它用的也是 set方法注入的方式,只不过变量的数据类型都是集合。 这里介绍注入数组、List、Set、Map、Properties。
(1) 注入数组数据
配置set方法
public class UserServiceImpl implements UserService {
/**
* 注入数组(array数组,list集合,set集合)
*/
private String [] names;
private List<String> lists;
private Set<String> sets;
public void setNames(String[] names) {
this.names = names;
}
public void setLists(List<String> lists) {
this.lists = lists;
}
public void setSets(Set<String> sets) {
this.sets = sets;
}
@Override
public void save() {
}
}
spring配置文件
<bean id="book" class="com.itheima.spring.Book">
<!-- List -->
<property name="list">
<list>
<value>1</value>
<value>2</value>
</list>
</property>
<!--Set-->
<property name="set">
<set>
<value>3</value>
<value>4</value>
</set>
</property>
<!--数组-->
<property name="array">
<array>
<value>5</value>
<value>6</value>
</array>
</property>
<!--Map-->
<property name="map">
<map>
<entry key="7" value="7-1" />
<entry key="8" value="8-1" />
</map>
</property>
<!--Properties-->
<property name="properties">
<props>
<prop key="9">9-1</prop>
<prop key="10">10-1</prop>
</props>
</property>
</bean>
Spring 框架中的注解配置
介绍、注解和 xml 配置对应关系
- 注解和 xml 是Spring提供的两种配置形式,二者的功能是完全一样的,都是要降低程序间的耦合
- 注解的好处是配置简单,xml的好处是修改配置不用改动源码,企业开发中两种方式灵活使用
Spring中注解配置
- 注解 + xml 配置(开启注解的功能支持)
- 纯注解(Spring Boot + cloud))
- 注意:在spring中使用注解开发,需要开启注解的功能支持(ioc注解,aop注解,事务注解)
注解和xml配置对应关系:
xml配置 | 注解配置 | 说明 |
---|---|---|
< bean id="" class="" > | @Component @Controller @Service @Repository | 将类的实例化对象放入Spring容器管理 |
< property name="" ref=""> | @Autowired @Qualifier @Resource | 从Spring容器中获取对象注入属性 |
< property name="" value=""> | @Value | bean的简单属性注入 |
< bean scope=""> | @Scope | 控制bean的作用范围 |
< bean init-method="init" destroy method="destory" /> |
@PostConstruct @PreDestroy | bean创建之后和销毁之前分别调用的方法 |
开启包扫描(开启 IOC 注解支持)
开启包扫描(即 开启对 IOC 注解的支持):
- 扫描指定包下的所有 java 类中的 Spring 注解
- 如果扫描到类上有 IOC 注解,就会把当前类交给 IOC 容器管理,当容器启动时,自动创建对象存入容器
- 如果扫描到属性上有 DI 注解,则依据依赖注入的规则,给属性注入值
方式1:xml配置方式 开启包扫描
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
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">
<!-- 开启包扫描
- base-package:包名(自动扫描此包以及此包下的所有子包)
-->
<context:component-scan base-package="cn.test"></context:component-scan>
</beans>
方式2:配置类注解方式 开启包扫描
/**
* 1、声明配置类:@Configuration
* 2、开启包扫描:@ComponentScan
*/
@Configuration
@ComponentScan(basePackages = "cn.test")
public class SpringConfig {
}
IOC 注解(对象创建的注解)
IOC 注解(对象创建的注解)说明:
- 标注在想要被 IOC 容器管理的类上,表明创建对象交给容器管理
- 当 Spring 容器启动时,根据包扫描配置自动的扫描到 IOC 注解,反射创建注解标注的对象,存入容器,委托容器管理
- 默认存入容器的 id(唯一标识)为当前类名首字母小写。可以通过 value 属性自定义存入容器中对象的 id
一共有四个:
- @Controller:一般标注在表现层(web层)的类上
- @Service: 一般标注在业务层(service层)的类上
- @Repository: 一般标注在持久层(dao层)的类上
- @Component:组件, 非三层模式范围的类上使用
相当于xml中的如下配置
<bean id="userDaoImpl" class="cn.test.dao.impl.UserDaoImpl"></bean>
生命周期的相关注解
- @Scope : 在类上配置对象的作用域
通过value属性指定作用范围(singleton|prototype),默认为 singleton(单例)
- @PostConstruct : 配置对象创建后的触发动作
当对象创建完成之后,自动执行的方法。相当于 xml 配置文件中的 init-method
- @PreDestroy :配置对象销毁前的触发动作(仅在 Scope = singleton 时有效)
容器关闭,对象销毁之前执行的方法。相当于 xml 配置文件中的destory-method
示例:
@Repository
@Scope(value="singleton")
public class UserDaoImpl implements UserDao {
public UserDaoImpl() {
System.out.println("创建UserDaoImpl");
}
@Override
public void save() {
System.out.println("调用dao保存数据");
}
//初始化方法:在对象创建完成之后执行
@PostConstruct
public void init() {
System.out.println("执行init方法");
}
//销毁方法:在容器关闭对象销毁之前执行
@PreDestroy
public void destory() {
System.out.println("执行destory方法");
}
}
DI 注解(依赖注入的注解)
DI 注解都相当于直接给属性赋值,而无需借助于 set 方法或构造方法
@Autowired
使用方式1:标注在属性上
- 直接给属性赋值(通过 @Autowired 依赖注入,不需要配置 set 方法)
- 默认是通过 by Type(根据类型,即接口类型)的形式从 IOC 容器中查找对象并给属性注入值
如果 IOC 容器中存在多个与属性同类型的对象(一个接口有多个实现类),
- 则会按照属性名(by Name)作为唯一标志从容器中查找对象并给属性注入值
也可以和 @Qualifier 注解共同使用,指定唯一标志从容器中查找对象并给属性注入值
- value:指定 IOC 容器中对象唯一标志(id)
注意:@Qualifier 只能结合 @Autowired 一起使用
使用方式2:标注在方法上
- 表示自动执行当前方法,如果方法有参数,会自动从IOC容器中寻找同类型的对象给参数传值
- 也可以在参数上添加 @Qualifier("IOC容器中对象id") 注解按照名称寻找对象给参数传值
@Autowired 使用注意事项
- 只能在被 Spring 容器托管(标注了 @Controller 等 IOC 注解)的类中使用 @Autowired 注解
- 自动注入与权限修饰符无关,即使是 private 修饰的字段也可以自动注入
- 默认情况下,使用 @Autowired 注解进行自动注入的属性一定要被装配( Spring 容器托管)
如果在容器中找不到该类型的bean 进行注入,就会报错
如果允许不被装配,可以将 @Autowired 的 required 属性为 false
- @Autowired 是基于类型的注入,如果当前类型属性在容器中只有一个 Bean,那么属性名不限制,但一般建议遵循类名首字母小写的规则
- 如果当前属性类型在容器中有个多个Bean,那么必须要通过属性名或者同时标注 @Qualifier 注解指定 Bean name
示例:
@Service
public class UserServiceImpl implements UserService {
@Autowired
@Qualifier(value = "userDao2") // 从容器中获取指定唯一标志的对象
private UserDao userDao;
@Override
public void save() {
userDao.save();
}
}
@value
配置在属性上。可用于简单数据类型的注入,相当于 < property name="" value="" >
,但通常不这么使用
一般用于解析 properties 配置文件或注册中心的配置文件中的内容
- 根据key值获取对应的 value,语法规则: @Value("${key}")
使用步骤:
- properties 配置文件交给Spring容器管理
- 通过 @Value,从容器中得到配置项,并注入
示例:
(1) 配置jdbc.properties文件
jdbc.username=root
jdbc.password=root
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///heima23
(2) 配置文件交给Spring
修改spring配置文件applicationContext.xml
<!--将properties文件,交给spring管理-->
<context:property-placeholder location="jdbc.properties"></context:property-placeholder>
(3) 属性注入
@Repository(value = "userDao")
public class UserDaoImpl implements UserDao {
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
public void save() {
System.out.println(username);
System.out.println(password);
System.out.println(driver);
System.out.println(url);
System.out.println("调用dao11111完成保存");
}
}
@Reource(了解)
jdk提供的依赖注入的注解,此注解在jdk9及以上版本已经移除
- 只能放在属性上
- 表示先按照属性名匹配 IOC 容器中对象id给属性注入值【by name】
- 若没有成功,会继续根据当前属性的类型匹配IOC容器中同类型对象来注入值 【by type】
- 若指定了 name 属性 @Resource(name = "对象id"),则只能按照对象 id 注入值
示例:
@Service
public class UserServiceImpl implements UserService {
@Resource(name = "userDao1")
private UserDao userDao;
@Override
public void save() {
userDao.save();
}
}
Configuration 配置类(注解)
配置类中的常用注解:
- @Configuration:标注在类上,声明该类为 Spring 配置类
Spring 在启动的时候会自动扫描并加载所有配置类,配置 Spring 容器(应用上下文),将配置类中的 Bean 放入容器管理
@Bean:标注在 Spring 配置类中的方法上,注册 bean 对象到 IOC 容器
- name 属性:给生成的bean指定唯一标志
在 Spring 容器启动的时候,自动的扫描并执行所有配置了 @Bean 的方法,并将返回值存入Spring容器
注意:
- 被标注的方法,需要返回某个实例
- 被标注的方法,可以配置依赖的属性参数,Spring 会自动从容器中获取到依赖的对象,自动调用方法
@ComponentScan:开启包扫描(Spring IOC注解支持),默认扫描当前包及子包下所有类
- basePackage 属性:指定扫描的包路径。可以减少加载时间
如果扫描到类上有 IOC 注解,就会把当前类交给 IOC 容器管理,当容器启动时,自动创建对象存入容器
如果扫描到属性上有 DI 注解,则依据依赖注入的规则,给属性注入值
@PropertySource:加载本地 properties 文件交给 Spring 容器管理
- value 属性:指定本地 properties 路径
@Import:在一个配置类中导入其它配置类的内容
- value 属性:指定其他的配置类的 class 类路径
Spring 支持多配置类(配置类的模块),若配置类臃肿,可以拆分配置类,然后在主配置类中引入子配置类(子配置类上不用配置注解)
示例:
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import javax.sql.DataSource;
@Configuration // 声明配置类
@ComponentScan(basePackages = "cn.test") // 开启包扫描,并指定包扫描路径
@PropertySource(value="jdbc.properties") // 通过注解将此文件交给spring容器管理
@Import(value=DataSourceConfig.class) // 引入其他的配置类
public class SpringConfig {
@Bean
public QueryRunner getQueryRunner(DataSource dataSource) {
QueryRunner qr = new QueryRunner(dataSource);
return qr;
}
}
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import javax.sql.DataSource;
// 子配置类
public class DataSourceConfig {
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.driver}")
private String driver;
@Bean
public DataSource getDataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setUrl(url);
dataSource.setDriverClassName(driver);
return dataSource;
}
}
# properties文件
jdbc.username=root
jdbc.password=root
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///heima23