全文来自于https://itbaima.net/document
Spring
基于xml的快速配置
-
文件结构
-
xml
xml 中扫描JavaBean 并配置到容器中
<?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">
<!-- 扫描的bean-->
<bean name="ArtStudent" class="org.example.bean.ArtStudent"/>
</beans>
- JavaBean
JavaBean 中仅仅定义属性和方法 并不赋值
public class ArtStudent extends Student{
public void art(){
System.out.println("我爱画画");
}
}
- App
在App界面加载配置文件(new ClassPathXmlApplicationContext("spring.xml")
),并进行操作
public class App {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
ArtStudent artStudent = (ArtStudent) context.getBean("ArtStudent");
}
}
bean的几种创建方式
// 通过接口获取
ArtStudent artStudent = (ArtStudent) context.getBean("ArtStudent");
artStudent.art();
// 通过类获取
ArtStudent artStudent1 = context.getBean(ArtStudent.class);
artStudent1.art();
// 通过bean name 获取
ArtStudent artStudent2 = context.getBean("ArtStudent", ArtStudent.class);
artStudent2.art();
}
单例和多例
配置
<!-- 单例-->
<bean name="ArtStudent" class="org.example.bean.ArtStudent" scope="singleton"/>
<!-- 多例-->
<bean name="ArtStudent" class="org.example.bean.ArtStudent" scope="prototype"/>
<!--懒加载 到调用的时候才加载-->
<bean name="ArtStudent" class="org.example.bean.ArtStudent" lazy-init="true"/>
区别
- 单例:在容器中只有一个实例,每次获取的都是同一个实例
- 多例:每次获取的都是一个新的实例
- 默认是单例
- 当Bean的作用域为单例模式时,那么它会在一开始(容器加载配置时)就被创建,我们之后拿到的都是这个对象。而处于多例模式下,只有在获取时才会被创建,也就是说,单例模式下,Bean会被IoC容器存储,只要容器没有被销毁,那么此对象将一直存在,而原型模式才是相当于在要用的时候直接new了一个对象,并不会被保存。
依赖注入
什么是依赖注入
依赖注入
- 依赖注入(Dependency Injection, DI)是一种设计模式,也是Spring框架的核心概念之一。
- 比如现在有一个教师接口:
public interface Teacher {
void teach();
}
- 具体的实现有两个:
public class ArtTeacher implements Teacher{
@Override
public void teach() {
System.out.println("我是美术老师,我教你画画!");
}
}
public class ProgramTeacher implements Teacher{
@Override
public void teach() {
System.out.println("我是编程老师,我教你学Golang!");
}
}
- 我们的学生一开始有一个老师教他,比如美术老师:
public class Student {
private Teacher teacher = new ArtTeacher();
//在以前,如果我们需要制定哪个老师教我们,直接new创建对应的对象就可以了
public void study(){
teacher.teach();
}
}
- 传统修改
- 类内部new对象
public class Student {
private Teacher teacher = new ProgramTeacher();
...
- 通过依赖注入修改变量
- 需要提供setter 或者构造器
- 不再需要类内部定义变量
- 直接改xml文件即可
<bean name="teacher" class="com.test.bean.ProgramTeacher"/>
<bean name="student" class="com.test.bean.Student">
<property name="teacher" ref="teacher"/>
</bean>
- 依赖注入注入基础类型
<bean name="student" class="com.test.bean.Student">
<property name="name" value="卢本伟"/>
</bean>
依赖注入的要求
如果我们需要用依赖注入 要么提供setter方法 要么提供构造器
1. setter
我们还需要修改一下Student类,依赖注入要求对应的属性必须有一个set方法:
public class Student {
private Teacher teacher;
//要使用依赖注入,我们必须提供一个set方法(无论成员变量的访问权限是什么)命名规则依然是驼峰命名法
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
2. 指定构造器
当我们移除了无参构造器以后 我们需要在xml
中指定构造器
- 目标注入类
public class Student {
private final Teacher teacher; //构造方法中完成,所以说是一个final变量
public Student(Teacher teacher){ //Teacher属性是在构造方法中完成的初始化
this.teacher = teacher;
}
...
- xml
<bean name="teacher" class="com.test.bean.ArtTeacher"/>
<bean name="student" class="com.test.bean.Student">
<constructor-arg name="teacher" ref="teacher"/>
</bean>
指定构造器的方式
public class Student {
private final String name;
public Student(String name){
System.out.println("我是一号构造方法");
this.name = name;
}
public Student(int age){
System.out.println("我是二号构造方法");
this.name = String.valueOf(age);
}
}
- 给标签添加类型:
<constructor-arg value="1" type="int"/>
- 指定为对应的参数名称:
<constructor-arg value="1" name="age"/>
集合这些的依赖注入
- 集合类型:
public class Student {
private List<String> list;
public void setList(List<String> list) {
this.list = list;
}
}
- 对于这种集合类型,有着特殊的支持:
<bean name="student" class="com.test.bean.Student">
<!-- 对于集合类型,我们可以直接使用标签编辑集合的默认值 -->
<property name="list">
<list>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</list>
</property>
</bean>
List
,Map
、Set
这类常用集合类包括数组在内,都是支持这样编写的,比如Map类型,我们也可以使用entry
来注入:
<bean name="student" class="com.test.bean.Student">
<property name="map">
<map>
<entry key="语文" value="100.0"/>
<entry key="数学" value="80.0"/>
<entry key="英语" value="92.5"/>
</map>
</property>
</bean>
bean的生命周期
bean开启生命周期
- xml 配置init-method 和 destroy-method
- 在对应的bean中添加对应的方法(init 和 destroy,名字只要能对应xml上的配置就行)
<bean name="ArtStudent" class="org.example.bean.ArtStudent" init-method="init" destroy-method="des"/>
public class ArtStudent extends Student{
public void init(){
System.out.println("初始化");
}
public void des(){
System.out.println("销毁");
}
}
单例和多例的生命周期
- 单例的创建开始
- 关闭容器的时候结束
//当容器创建时,默认情况下Bean都是单例的,那么都会在一开始就加载好,对象构造完成后,会执行init-method
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("test.xml");
//我们可以调用close方法关闭容器,此时容器内存放的Bean也会被一起销毁,会执行destroy-method
context.close();
- 多例调用时才会创建对象,销毁时不会调用destroy-method
工厂bean 和继承bean(了解)
工厂模式和工厂Bean
- 目标bean
public class Student {
Student() {
System.out.println("我被构造了");
}
}
- 工厂bean
public class StudentFactory {
public static Student getStudent(){
System.out.println("欢迎光临电子厂");
return new Student();
}
}
- 工厂bean的配置
<bean class="com.test.bean.StudentFactory" factory-method="getStudent"/>
- 工厂bean的返回值和使用
- 工厂bean的返回值是目标bean
- 调用的时候就是对目标bean 进行了一些前置操作
Student bean = (Student) context.getBean("studentFactory");
// 欢迎光临电子厂 工厂bean加的
// 我被构造了 目标bean自身的
bean的继承(parent)
- 几个bean之间有共同的属性,可以使用继承的方式(
继承不一定需要开abstract
) - 如果设置成abstract,那么这个bean就不能被实例化
<bean name="student" class="com.test.bean.Student" abstract="true">
<property name="name" value="卢本伟"/>
<!-- 因为开了abstract 所以不能直接实例化 也可以不写abstrac-->
</bean>
<bean name="artStudent" class="com.test.bean.ArtStudent" parent="student">
<!-- 这里可以直接复用上面的属性-->
</bean>