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