02 Spring IoC
2022-11-20 04:46:14 4 举报
02 Spring IoC
作者其他创作
大纲/内容
IoC(Inversion of Control):控制反转
IoC 是一种设计思想 --> 将对象交给容器控制,而不是显式的进行创建(解耦)
具体的:
1. 把创建和查找依赖对象的控制权交给IoC容器
2. IoC 容器进行注入,组合对象之间的关系
这样的优势:
对象与对象之间是松耦合(解耦)
集中管理
功能可复用(减少对象的创建和内存消耗)
使得程序的整体体系结构可维护、灵活性、扩展性变好
所谓IoC,简短的说:对象由Spring来创建、管理、装配
为什么要用IoC呢?
问题1:更换件复杂问题且其导致系统BUG的可能性问题,即具体类强耦合
问题2:热插拔问题,即实现类换了还是需要去变更代码
这里涉及到2个原则:
1、接口分离原则 ISP(the Interface Segregation Principle ISP)
模块间通过抽象接口隔离开,而不是具体的类强耦合起来
2、依赖倒置原则 DIP(the Dependency Inversion Principle DIP)
具体 --> 抽象,下层 --> 上层 (分离)
依赖倒置原则,是DI的一种原理,IoC就是实现了DI的一种实现方式
IoC是从容器角度描述
DI是从应用程度角度描述
换句话说:
IoC是依赖倒置原则的设计思想
而DI是具体的实现方式
通过对比(非IoC):对象A获得依赖对象B的过程,由主动行为变为了被动行为,控制权颠倒过来了,这就是“控制”
IoC代码实现
搭建基于IoC的Spring应用,这里有三种方式:
1、导入jar包 + xml
2、Maven + 注解 + xml
3、Springboot + javaconfig
搭建方式一:导入jar包 + 配置xml
1、导入jar包(Core Container + Aop + Aspects)
Spring 仓库(jar):repo.spring.io --> 搜索Spring5
切换视图:Navitbrower
下载dist.zip ,包含:
docs.zip,文档
schema.zip,约束
点击树可展开历史版本jar
下载jar包后,使用不以docs.jar和source.jar结尾的jar
idea导入jar包(较Eclipse复杂):File -> ProjectStructure -> projectSettings -> Libraies -> +(添加)
2、添加Spring配置xml文件
3、加载Spring上下文、加载IoC容器
4、在运行时会报错:NotClassDefoundError:org/apache/commons/logging/LogFactory
百度上查询,会提示你导入一下这个jar包
Spring5只需要把jcl的jar导入即可
搭建方式二:Maven + 注解 + xml
1、需要导入jar -> 配置maven依赖
依赖 spring-context
找jar包maven坐标,mvn.repository.com或其他仓库
在pom.xml文件配置依赖:
2、添加Spring配置xml文件
3、编写测试类:
IoC容器概述
ApplicationContext
是 Spring IoC 容器实现的代表
它是Srping顶层核心接口
它负责实例化,配置和组装Bean
它通过读取配置元数据获取有关实例化、配置和组装哪些对象的说明
配置元数据
使用xml配置
简单、直观、适合入门
基于注解的配置
@Component @Service @Controller @Repository @Autowride
Spring 2.5 支持基于注解的元数据配置
SSM框架开发中的使用
基于Java的配置
@Confiration @Bean @Import
从Spring 3.0 开始,由Spring JavaConfig项目提供的功能已经成为Spring核心框架的一部分,因此可以使用Java配置来代替XML配置定义外部bean
从Spring 4.0 开始,支持Springboot1.0之后,完全采用JavaConfig的方式进行开发
容器的实例化及使用
实例化(3种方式)
ClassPathXmlApplicationContext
FileSystemXmlApplicationContext
AnnotationConfigApplicationContext
使用
ApplicationContext是能够创建bean定义(后续javaconfig实现中会详细说明)以及处理相互依赖关系的高级工厂接口
使用方法T getBean(String name, Class<T> requiredType)获取容器实例
IoC容器的使用(基于xml使用)
命名Bean、获取Bean
命名Bean
bean的加载方式是:由上向下
获取Bean
通过 id、name、类型 获取Bean
通过 别名 获取Bean
引入其他XML
使用import可以导入其他spring的xml配置文件
依赖注入
基于setter方法的依赖注入
xml配置
IoCTest
基于构造函数的依赖注入
xml配置
IoCTest
复杂数据类型的依赖注入
直接值(基本类型、String等)
null值
空的字符串值
引用外部bean(装配)
使用内部bean 依赖注入其他bean
list 注入
map 注入
IoCTest
p命名空间
简化基于setter属性注入XML配置
xml配置
IoCTest
c命名空间
使用c命名空间简化基于构造函数的XML
xml配置
控制Bean加载顺序
当一个bean想让另一bean在它之前加载可以设置depends-on
懒加载
在使用的时候才会加载该bean
Bean的作用域
单例(Singleton):默认同一个id只加载一次bean,减少内存消耗
多例/原型(prototype):加载多次,每使用一次bean加载一次
request:一个请求中加载一次
session:一个客户端加载一次
application:一个应用中加载一次
websocket:一个长连接加载一次
实例化Bean
使用构造器实例化(默认)
使用静态工厂方法实例化,factory-method="xxxFactory"
java代码
xml配置
使用实例工厂方法实例化,factory-bean="personFacotry" + factory-method="createPersonFacotryMethod"
java代码
xml配置
自动注入
之前的配置中都是通过property标签来进行手动配置的,Spring还提供了强大的自动装配功能,通过autowire属性可以按照我们指定的规则进行配置
autowire属性
autowire="default/no"(默认):不自动装配
autowire="byName":根据set方法的名字去自动匹配
autowire="byType":根据类型去自动匹配 当出现多个类型或者匹配到类型则会报错
autowire="constructor":根据构造器去匹配
优先会根据参数名字去匹配
假如参数名字没有匹配到,会根据参数类型去匹配
会根据构造函数的参数进行完整的匹配注入
假如根据类型匹配到多个bean,会注入失败但是不会报错
当根据类型匹配到多个bean,可以使用:
1.设置某个bean为主要bean,primary="true"
2.设置不需要自动注入的bean,autowire-candidate="false":忽略自动注入
xml配置
IoC感知Bean的生命周期回调
方式1:实现InitializingBean 和 DisposableBean 回调接口
java代码
方式2:自定义 init() 和 destroy() 方法 + xml配置
java代码
xml配置
方式3:@PostConstruct 和 @PreDestroy 注解.
你也可以在bean上同时使用这些机制
如果bean配置了多个生命周期机制
如果配置了不同的方法名字时,方法执行顺序如下:
初始化方法:
1、包含@PostConstruct注解的方法
2、在InitializingBean 接口中的afterPropertiesSet() 方法
3、自定义的init() 方法
Destroy方法:
1、包含@PreDestroy注解的方法
2、在DisposableBean接口中的destroy() 方法
3、自定义的destroy() 方法
如果配置了相同的方法名字时,方法只会执行一次
配置第三方bean
引入第三方bean
xml配置
引入外部属性资源文件
属性资源文件
xml配置
Spring SpEL 的使用
Spring的表达式语言,支持运行时查询操作对象
使用#{...}作为语法规则,所有的大括号中的字符都认为是SpEL.
几种使用方式:
xml
注解
代码
xml中使用举例:
运算表达式、引用外部bean、调用bean的属性、调用bean的方法、调用静态方法
IoC容器的使用(基于注解使用)
Spring 4种注册Bean注解
Spring提供了4种注解来创建Bean
@Controller :标记在控制层的类注册为Bean组件
@Service :标记在业务逻辑层的类注册为Bean组件
@Repository :标记在数据访问层的类注册为Bean组件
@Component :标记非三层的普通的类注册为Bean组件
每种注解,不是必须每个层对应相应的注解,而是:
1 增强可读性
2 利于spring管理
注册Bean、获取Bean:
1.设置扫描包 context:component-scan
base-package 设置需要扫描的包
exclude-filter 设置需要排除扫描的选项
include-filter 设置需要包含扫描的选项
type 设置需要排除/包含扫描规则
1.annotation 默认 根据注解的完整限定名设置排除\包括
2.assignable 根据类的完整限定名设置排除\包括
3.aspectj org.example..*Service+ 根据切面表达式设置排除\包括,一般不会使用
4.regex org\.example\.Default.* 根据正则表达式设置包括\排除,一般不会使用
5.custom org.example.MyTypeFilter 根据接口org.springframework.core.type .TypeFilter 设置排除\包括 ,一般不会使用
use-default-filters 设置是否扫描4种注解
true(默认):会默认包含扫描 @Controller @Service @Repository @Component
false:不会扫描 @Controller @Service @Repository @Component
xml配置示例:
2.在对应的类(非接口)加上对应的注解
自定义bean名字
@Service(value="xxx")
@Service(value={"xxx1","xxx2"})
java代码
xml配置
依赖注入
使用@Value("${xxx}")或@Value("#{}") 指定依赖注入
使用@Autowired自动注入
自动注入
Autowired
在需要自动注入的属性变量上,使用@Autowired
注意:当使用AutoWired注解的时候,自动装配的时候是根据类型实现的。
1、如果只找到一个,则直接进行赋值
2、如果没有找到,则直接抛出异常
3、如果找到多个,那么会按照变量名(为类名称的首字母小写)作为id继续匹配:
a、如果匹配上直接进行装配
b、如果匹配不上则直接报异常
使用@Service(value="xxx") 可指定bean的名字
使用@Qualifier("xxx") 告诉bean用这个名字自动注入(覆盖原默认名)
使用@Primary 设置自动注入的主要Bean
使用泛型作为自动注入限定符
代码示例
UserController
BaseService
UserService
UserServiceImpl
UserDao
UserDaoImpl
IoCTest
在方法上面也可以使用@Autowired
此方法在bean创建的时候会自动调用
这个方法的每一个参数都会自动注入值
默认通过参数类型进行注入
也可以在参数上使用@Qualifier注解,用来被当作id去匹配容器中的对象
Autowired 和 Resource 的区别:
Autowired:
是spring中提供的注解
默认是按照类型进行装配
默认情况下要求依赖的对象必须存在
只适合spring框架
Resource :
是jdk中定义的注解,依靠的是java的标准
默认是按照名字进行匹配的
同时可以指定name属性
扩展性更好
注解自动加载顺序
bean的顺序(默认)
使用@DependsOn:控制bean加载的顺序。指定先加载@DependsOn对应的Bean
懒加载
使用@Lazy,默认true,在使用时进行加载
Bean的作用域
使用@Scope(value="prototype") 多例
使用@Scope(value="singleton") 单例
注解式生命周期回调
在方法上使用@PostConstruct,生命周期回调- 初始化回调
在方法上使用@PreDestroy,生命周期回调- 销毁回调
代码示例:
配置第三方bean
引入外部属性资源文件
IoC容器的使用(基于JavaConfig使用)
定义一个IoCJavaConfig代替Spring.xml
使用@Configuration
用户标记一个spring配置类,之前是根据xml启动spring上下文
相当于 xml文件 <beans></beans>
使用@ComponentScan(basePackages = "cn.tulingxueyuan")
相当于xml文件 <context:component-scan base-package="cn.tulingxueyuan" ></context:component-scan>
使用AnnotationConfigApplicationContext初始化Spring容器
代码示例:
使用@Bean
将一个类的实例注册到容器里
可以干预类的实例化过程
代码示例:
怎么自动依赖外部Bean?
直接在方法中加入相应的参数
怎么自动依赖内部Bean?
直接调用相应的方法
使用@PropertySource("classpath:db.properties")
使用@PropertySource 引入外部属性资源文件
配合@Value使用
代码示例:
使用@Import(MyImportBeanDefinitionRegistrar.class)
1 导入其他的配置类@Import(SecondJavaConfig.class)
2.导入类注册为Bean@Import(Role.class)
3.导入ImportSelector实现类,可以注册多个bean
只能通过类型来获取,不能通过name获取
定义一个具体类实现ImportSelector接口,并重写selectImports方法
使用@Import(MyImportSelector.class)注解
4.导入ImportBeanDefinitionRegistrar实现类,可以注册多个BeanDefinition
定义一个具体类实现ImportBeanDefinitionRegistrar接口,并重写registerBeanDefinitions方法
使用@Import(MyImportBeanDefinitionRegistrar.class)注解
扩展:Bean 的实例化过程
↓ 元数据 (注解@Component、@Bean 或 xml <bean/>,正好呼应上边的元数据组装)
↓ 定义态 (类似于图纸或概念产品,由元数据解析得来)
↓ Bean (根据BeanDefinition来创建Bean对象)
题外话:当编译时,出现代码不识别或运行时Java编译失败问题,需要先保证jdk版本是否正确(idea)
Build -> compilter -> Java Compiler -> 修改JDK版本
Project Structure -> Project Settings -> modules -> 修改JDK版本
0 条评论
下一页