1. Spring Framework系统架构
- Spring Framework是Spring生态系统中最基本的项目是其他项目的基础
[外链图片存储失败,源站可能有防盗链机制,建议保存图片直接上传(img-8bekEkqq-1658766926507)(./image/spring-s.png)]
2. 核心概念
-
之前写的java-web在代码中,使用了动态代理的想法,但它们都是硬编码。一旦需要修改实现类,就需要重新编译、测试、部署和在线,成本更高
-
解决方案
- 不要在程序中主动使用对象new为了生成对象,转换由外部提供
-
对象的创建控制权
从程序转移到外部
,这种思想被称为控制反转 -
主动使用对象new在此过程中,对象的创建控制权从程序转移到外部,将对象转换为由外部提供的对象。
-
从内部关联转变为外部关联
-
Spring技术对IOC实现了思想
- Spring提供了一个叫做容器的容器IOC用于充当的容器IoC思想的外在
- 也就是说,我们的对象最初是通过的new来产生的,现在可以通过IoC来产生
- 那么产生对象,管理对象这件事情,就交给了IoC容器
- ,创建或管理的对象在IoC统称为容器
-
:建立在容器中bean与bean依赖关系的整个过程称为依赖注入
-
目标:
-
使用容器管理
-
在IOC容器中会有依赖关系。bean绑定关系
-
不仅可以直接使用对象IoC在容器中获得并获得bean所有的依赖关系都绑定了
-
3. 入门案例
3.1 配置Spring配置文件
<?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"> <!--配置beans--> <bean id="bookDaoImpl01" class="dao.impl.BookDaoImpl01"></bean> <bean id="serviceImpl02" class="service.impl.BookServiceImpl02"></bean> </beans>
3.2 编写IoC基础代码
public static void main(String[] args) {
//1.先拿容器(IoC) ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); //2bean BookDaoImpl01 bookDaoImpl01 = (BookDaoImpl01)ctx.getBean("bookDaoImpl01");
bookDaoImpl01.save();
}
3.3 基础Service类
package service.impl;
import dao.BookDao;
import service.BookService;
public class BookServiceImpl02 implements BookService {
//删除业务层中的使用new的方式创建的dao对象
private BookDao bookDao;
@Override
public void save() {
System.out.println("service");
}
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
}
3.4 编写配置
<?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"> <!--配置beans--> <bean id="serviceImpl02" class="service.impl.BookServiceImpl02"> <!--配置service与dao之间的关系--> <!--property:
标签表示配置当前bean的属性 name:表示配置哪一个具体的属性 ref属性表示参照哪一个bean --> <property name="bookDao" ref="bookDaoImpl01"></property> </bean> <bean id="bookDaoImpl01" class="dao.impl.BookDaoImpl01"></bean> </beans>
4. bean配置
4.1 bean别名配置
- name
- 定义bean的别名,可以定义多个,使用逗号(,)分号(;)空格( )分割
4.2 bean作用范围配置
-
Spring所创建的bean是单例的,如果想要产生非单例的,则需要进行配置
-
scope
- prototype:非单例
- singleton:单例(默认)
-
适合交给容器进行管理的bean
- 表现层对象
- 业务层对象
- 数据层对象
- 工具对象
-
不适合交给容器进行管理的bean
- 封装实体的域对象(记录状态)domain pojo等
5. bean实例化
5.1 bean的创建过程
-
bean本质上就是对象,创建bean使用构造方法完成
-
使用的是单例模式方法来创建的,底层原理是通过反射机制来完成的,调用的是newInstance(),调用无参构造函数
5.2 使用静态工厂实例化bean
- 编写工厂方法
package factory;
import dao.BookDao;
import dao.impl.BookDaoImpl01;
public class BookDaoFactory {
public static BookDao getBookDao(){
return new BookDaoImpl01();
}
}
- 编写配置文件
<bean id = "bookDao" class="factory.BookDaoFactory" factory-method="getBookDao"></bean>
5.3 使用实例工厂实例化bean
package factory;
import dao.BookDao;
import dao.impl.BookDaoImpl01;
public class BookDaoFactory {
public BookDao getBookDao(){
return new BookDaoImpl01();
}
}
<bean id = "bookDaoFactory" class="factory.BookDaoFactory"></bean>
<bean id = "bookDao" factory-bean="bookDaoFactory" factory-method="getBookDao"></bean>
5.4 FactoryBean
package factory;
import dao.BookDao;
import dao.impl.BookDaoImpl01;
import org.springframework.beans.factory.FactoryBean;
public class BookDaoFactoryBean implements FactoryBean<BookDao> {
@Override
public Class<?> getObjectType() {
return BookDao.class;
}
//代替原始实例工厂中创建对象的方法
@Override
public BookDao getObject() throws Exception {
return new BookDaoImpl01();
}
@Override
public boolean isSingleton() {
return FactoryBean.super.isSingleton();
}
}
<bean id= "bookDao" class="factory.BookDaoFactoryBean"></bean>
//1.先拿容器(IoC)
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//2.通过容器去拿bean
BookDao bookDao = (BookDao)ctx.getBean("bookDao");
bookDao.save();
}
5.5 bean生命周期控制
<bean id= "bookDao" class="factory.BookDaoFactoryBean" init-method="init" destroy-method="destroy"></bean>
//1.先拿容器(IoC)
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//2.通过容器去拿bean
BookDao bookDao = (BookDao)ctx.getBean("bookDao");
bookDao.save();
//3.注册一个函数,在关闭之前
ctx.registerShutdownHook();
//而close()方法是实时的,暴力关闭ctx
package factory;
import dao.BookDao;
import dao.impl.BookDaoImpl01;
import org.springframework.beans.factory.FactoryBean;
public class BookDaoFactoryBean implements FactoryBean<BookDao> {
@Override
public Class<?> getObjectType() {
return BookDao.class;
}
//代替原始实例工厂中创建对象的方法
@Override
public BookDao getObject() throws Exception {
return new BookDaoImpl01();
}
@Override
public boolean isSingleton() {
return FactoryBean.super.isSingleton();
}
//表示bean初始化对应的操作
public void init(){
System.out.println("init");
}
//bean销毁前的操作
public void destroy(){
System.out.println("destroy");
}
}
- 同时可以通过继承InitializingBean, DisposableBean接口来实现
package service.impl;
import dao.BookDao;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import service.BookService;
public class BookServiceImpl02 implements BookService , InitializingBean, DisposableBean {
//删除业务层中的使用new的方式创建的dao对象
private BookDao bookDao;
@Override
public void save() {
System.out.println("service");
bookDao.save();
}
//在属性设置之后,才会执行init函数
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
@Override
public void destroy() throws Exception {
System.out.println("destroy");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("init");
}
}
- 初始化容器
- 创建对象(内存的分配)
- 执行构造方法
- 执行属性注入(set操作)
- 执行bean自身的初始化方法
- 使用bean
- 执行业务操作
- 关闭/销毁容器
- 执行bean销毁方法
6. 依赖注入方式
- setter注入
- 简单类型
- 引用类型
- 构造器注入
- 简单类型
- 引用类型
6.1 setter注入
- 在bean中定义引用类型属性并提供可访问的set方法
- 配置中使用property标签ref属性注入引用类型对象
<bean id= "services" class="service.impl.BookServiceImpl02">
<property name="connectionNum" value="10"></property>
<property name="dbName" value="mysql"></property>
</bean>
public void setConnectionNum(int connectionNum) {
this.connectionNum = connectionNum;
}
public void setDbName(String dbName) {
this.dbName = dbName;
}
6.2 构造器注入
<bean id= "services" class="service.impl.BookServiceImpl02">
<constructor-arg name="connectionNum" value="10"></constructor-arg>
<constructor-arg name="bookDao" ref="bookDao"></constructor-arg>
<constructor-arg name="dbName" value="mysql"></constructor-arg>
</bean>
public BookServiceImpl02(BookDao bookDao, int connectionNum, String dbName) {
this.bookDao = bookDao;
this.connectionNum = connectionNum;
this.dbName = dbName;
}
- 强制依赖使用构造器执行,使用setter注入有概率不进行注入导致null对象的出现
- 可选依赖使用setter注入进行,可以灵活配置
- Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对比较严谨
- 如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用setter注入完成可选依赖的注入
- 实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注入
- 自己开发的模块推荐使用setter注入
6.3 依赖自动装配
-
IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配
-
自动装配方式
- 按类型(常用)
- 按名称
- 按构造方法
- 不启用自动装配
-
先为类提供setter方法,然后提供auto-wire注解
-
注意在用ByTye装配依赖bean的时候
- 首先第一个不能够没有注册所依赖的bean
- 第二个则是如果注册了多个不同id的同一类型bean的时候,也无法使用
<bean id="service" class="service.impl.BookServiceImpl02" autowire="byType"></bean>
-
按名装配的时候(ByName)
- 对于bean而言,则是id要与set后面接上去的对象名一致
-
自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效
7. Spring读取配置文件
- 开启context命名空间
<!--定义新的命名空间为context-->
<!--将bean修改为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/beans/spring-context.xsd ">
- 使用context空间加载配置文件
<context:property-placeholder location="classpath:*.properties" system-properties-mode="NEVER"></context:property-placeholder>
<!--只读取当前项目的配置文件-->
<!--若要读取jar包下的properties,则需要写为classpath*:*.properties-->
- 将配置字符串修改为属性占位符
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<!--必须使用setter注入-->
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
- 一些规范
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4KF5osji-1658766926508)(./image/spring-pzwj.png)]
8.容器相关总结
- BeanFactory是IoC容器的顶层接口,初始化BeanFactory对象时,加载的bean延迟加载
- ApplicationContext接口是Spring容器的核心接口,初始化时bean立即加载(饿汉式单例)
- ApplicationContext接口提供基础的bean操作相关方法,通过其他接口扩展功能
9. 注解开发
9.1 使用注解替代bean配置
@Component(value = "bookService")//在实体类头加上此注解,value是bean的id
<context:component-scan base-package="service.impl"></context:component-scan>
<!--使得spring感知到该bean的存在-->
- Spring提供@Component注解的三个衍生注解
- @Controller:用于表现层bean的定义
- @Service:用于业务层定义bean
- @Repository:用于数据层定义bean
9.2 纯注解开发
//用此类来代替xml文件,配置类
@Configuration
@@Configuration({
"service.impl","dao.impl"})//替代了<context:component-scan base-package="service.impl"></context:component-scan>这一行
public class SpringConfig {
}
//加载配置类
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
- @Configuration注解用于设定当前类为配置类
- @Configuration注解用于设定扫描路径,此注解只能添加一次,多个数据则用数组即可
9.3 bean管理
@Scope("prototype")//控制是否单例模式,singleton
@PreDestroy
public void destroy(){
System.out.println("destroy");
}
@Override
public void save() {
System.out.println("service");
bookDao.save();
}
9.4 依赖注入
@AutoWired//提供自动装配,暴力反射装配
//当存在多个实现类bean的时候
@Qualifier("beanId")//必须配合AutoWired使用
- 自动装配是基于反射设计创建对象并暴力反射对应属性为私有属性初始化数据,因此不需要提供setter方法
- 自动装配建议使用无参构造方法创建对象(默认的),如果不提供对应的构造方法,请提供唯一的构造方法
@Value 标签:
1832zj连接器绕线功率电感swcb1305