这是我参与11月更文挑战的第11天,活动详情查看:2021最后一次更文挑战
Spring
Spring简介
Spring就是一个java语言开发的轻量级的开源的框架,可以在java项目中是用来简化开发 spring的核心是IOC和AOP,控制反转和依赖注入,Spring作为容器装的是java对象,可以创建对象给对象赋值,实现解耦,解决java对象与对象之间,模块与模块之间的耦合
Spring体系结构
左上角数据访问的模块,右边是web开发模块,后边我写的SpringMvc就在这一块,下来时Aop,核心容器,再就是测试,核心的妹妹一个模块对应一个jar包。。
spring优点
- 轻量
- 解耦
- AOP
- 可以集成各种优秀框架
IoC控制反转
概述
控制反转用来指导开发人员如何管理对象,把对象的生成,赋值,全生命周期交给容器来管理。分为两大部分,控制和反转,,我们可以使用容器来使用容器中的对象。Spring就是个容器
- 控制是对象创建,属性赋值,对象的整个生命周期管理
- 反转就是把对象的管理权限给spring容器管理
IOC的技术实现
DI依赖注入,是IoC的一种技术实现,程序只需要提供需要使用的对象的名称就可以了,其余的都是帮我们实现好了。Spring就是使用DI实现的IOC,我们只需要提供名称就可以了,Spring底层通过反射来创建对象
Spring第一个程序
Spring的配置文件
Spring配置文件的跟标签是beans beans后面是是约束文件说明beans里边是用来声明被Spring管理的java对象
配置文件声明一个对象
声明对象
1) id:自定义对象名,唯一值,重复会报错
2) class:类的全限定名称Spring通过反射创建对象
3) Spring根据Id和Class创建对象放到Spring容器里
<bean id="UserServiceImpl" class="org.example.Service.impl.UserServiceImpl"></bean>
获取bean对象
public interface UserService {
public void SelectUser();
}
public class UserServiceImpl implements org.example.Service.UserService {
@Override
public void SelectUser() {
System.out.println("实现了查询");
}
}
测试获取对象,跟我们之前new一个对象好像更复杂了过程是
public class appmain {
public static void main(String[] args) {
//UserServiceImpl userService = new UserServiceImpl();
//userService.SelectUser();
//配置文件地址
String configPath="beans.xml";
//2创建对象容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(configPath);
//从容器里获取指定名称的对象
UserService userService = (UserService) applicationContext.getBean("UserServiceImpl");
//使用对象的方法
userService.SelectUser();
}
}
结果
我们都走了哪些呢??
- 指定Spring文件的地址,
- 创建容器对象,读取配置文件,遇到bean标签,通过反射创建对象,把对象放到容器里
- 在容器里根据对象名获取对象
- 调用对象的方法
那么Spring创建对象调用的是哪个方法
我们写一个无参构造打印一句话
public UserServiceImpl(){
System.out.println("无参构造");
}
运行看一下结果可以看出Spring创建对象调用的是无参构造方法
Spring在什么时候创建对象的
创建容器的售后,读取配置,创建文件中的对象,获取对象的速度快,
容器创建对象一次创建几个对象
在创建容器时,把配置文件中的bean都创建出来
容器中bean个数和名字
@Test
public void Test(){
//配置文件地址
String configPath="beans.xml";
//2创建对象容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(configPath);
//从容器里获取指定名称的对象
UserService userService = (UserService) applicationContext.getBean("UserServiceImpl");
int beanDefinitionCount = applicationContext.getBeanDefinitionCount();
System.out.println("容器中对象的数量"+beanDefinitionCount);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
//使用对象的方法
//userService.SelectUser();
}
创建非自定义对象
我们来创建Util包里的Date对象,有class文件Spring就能创建对象
@Test
public void TestDate(){
//配置文件地址
String configPath="beans.xml";
//2创建对象容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(configPath);
//从容器里获取指定名称的对象
Date myDate = (Date)applicationContext.getBean("myDate");
System.out.println(myDate);
}
无接口的对象创建
public class StudentService {
public void SeleStudent(){
System.out.println("学生类查询");
}
}
<bean id="myStudent" class="org.example.Service.StudentService"></bean>
@Test
public void TestStudent(){
//配置文件地址
String configPath="beans.xml";
//2创建对象容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(configPath);
//从容器里获取指定名称的对象
StudentService myStudent = (StudentService)applicationContext.getBean("myStudent");
myStudent.SeleStudent();
}
给属性赋值
Spring调用类的无参构造。创建对象,创建对象后给参数赋值。给属性赋值可以使用xml配置文件中的标签和属性还有使用注解
DI的分类
- set注入,也可以叫设值注入
- 构造注入
基于Xml的DI
在xml配置文件中使用标签和属性,完成对象创建和属性赋值
- set注入也叫设值注入,就是Spring调用类中的set方法,在set方法中完成属性赋值
简单类型
public class Student {
private String name;
private Integer age;
//getset和toStirng自己写上
public void setAddress(String address) {
System.out.println("setAddress"+ address);
}
}
<!--
DI 给属性赋值
1.set注入: Spring调用类的set方法,通过se方法给属性赋值
简单类型的set注入:
语法<bean id ="xx" calss="xx>
<property name="属性名" value="属性值"></property>
。。。。。。。。。。。
</bean>
-->
<bean id="Mystudent" class="org.example.S01.Student">
<property name="age" value="20"></property>
<property name="name" value="张三"></property>
<property name="address" value="科技城管委会"></property>
</bean>
<bean id="MyDate" class="java.util.Date">
<property name="time" value="23131231231"></property>
</bean>
运行结果,yi定要加set方法 ,否则报错无法赋值,有set方法就行,和属性名无关,还可以对非自定义属性赋值,只要set开头。
对象类型
public class Student {
private String name;
private Integer age;
private Grade grade;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Grade getGrade() {
return grade;
}
public void setGrade(Grade grade) {
this.grade = grade;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + ''' +
", age=" + age +
", grade=" + grade +
'}';
}
}
public class Grade {
private String GradeName;
private Integer gradeId;
public String getGradeName() {
return GradeName;
}
public void setGradeName(String gradeName) {
GradeName = gradeName;
}
public Integer getGradeId() {
return gradeId;
}
public void setGradeId(Integer gradeId) {
this.gradeId = gradeId;
}
@Override
public String toString() {
return "Grade{" +
"GradeName='" + GradeName + ''' +
", gradeId=" + gradeId +
'}';
}
}
<!--
2.set注入对象类型
<bean id="XXX" class="XXXX">
<property name="属性" ref="bean的id"></property>
</bean>
-->
<bean id="Mystudent" class="org.example.S01.Student">
<property name="name" value="张三"></property>
<property name="age" value="20"></property>
<property name="grade" ref="MyGrade"></property>
</bean>
<bean id="MyGrade" class="org.example.S01.Grade">
<property name="gradeId" value="1"></property>
<property name="gradeName" value="一年级"></property>
</bean>
测试
有参构造下标赋值
public Student(String name, Integer age, Grade grade) {
this.name = name;
this.age = age;
this.grade = grade;
}
<bean id="Mystudent1" class="org.example.S01.Student">
<constructor-arg index="0" value="李四"></constructor-arg>
<constructor-arg index="1" value="20" ></constructor-arg>
<constructor-arg index="2" ref="MyGrade" ></constructor-arg>
</bean>
省略index
<bean id="Mystudent1" class="org.example.S01.Student">
<constructor-arg value="李四"></constructor-arg>
<constructor-arg value="20" ></constructor-arg>
<constructor-arg ref="MyGrade" ></constructor-arg>
</bean>
引用类型的自动注入
Spring可以根据某些规则给应用类型赋值
- byName 按名称注入,java中引用类型的数据名称和Spring中的bean的id是一样的,数据类型也一样,这些bean能个偶赋值给应用类型
- ByType 按类型注入 java类中引用类型的数据类型与Spring中bean的class值是同源关系,可以赋值
byName
<!--
1。ByName按名称注入 java类中引用类型的属性名称heSpring容器中bean的id名称一样且数据类型一样
<bean id="XXXX" class="XXXX" autowire="byName">
简单类型赋值
</bean>
-->
<bean id="Mystudent" class="org.example.S04.Student" autowire="byName">
<property name="name" value="张三"></property>
<property name="age" value="20"></property>
</bean>
<bean id="grade" class="org.example.S04.Grade">
<property name="gradeId" value="3"></property>
<property name="gradeName" value="三年级"></property>
</bean>
ByType
2.byTypean 按类型注入;java类中引用类型的数据类型和bean的class是同源的
同源古纳西
1.java中引用类型的数据类型和bean的class值是一样的
2.java中引用类型的数据类型和bean的class值是父子类关系
3.java中引用类型的数据类型和bean的class值是接口和实现类的关系
-->
<bean id="Mystudent" class="org.example.S04.Student" autowire="byType">
<property name="name" value="张三"></property>
<property name="age" value="20"></property>
</bean>
<bean id="Mygrade" class="org.example.S04.Grade">
<property name="gradeId" value="4"></property>
<property name="gradeName" value="四年级"></property>
</bean>
Spring怎么工作的
Spring先生成一个容器,然后根据配置文件创建对象,放在容器里然后管理对象,我们的要是用时从spring容器中获取即可
使用多个配置文件
bean越多配置文件越长,Spring管理多个配置文件。常用的是包含文件的配置文件,有一个总的文件,里边inport其他多个文件
- 按功能模块分
- 按类的功能分
总的文件
<import resource="其他文件地址">
<import resource="其他文件地址">
关键字classpathL表示类路径,Spring在类路径中加载文件
Appliction.xml总的文件
<import resource="Grade-Application.xml"></import>
<import resource="Student-Application.xml"></import>
<import resource="*-Application.xml"></import>
Grade-Application.xml
<bean id="Mygrade" class="org.example.S04.Grade">
<property name="gradeId" value="4"></property>
<property name="gradeName" value="四年级"></property>
</bean>
Student-Application.xml
<bean id="Mystudent" class="org.example.S04.Student" autowire="byType">
<property name="name" value="张三"></property>
<property name="age" value="20"></property>
</bean>
基于注解的DI
@Component
基于主键的DI: 使用Spring提供的注解完成属性赋值。注解的使用步骤
- 在代码里加上注解@Component
- 在Spring配置文件中加入组件扫描,并加上扫描路径
和@Component功能相似的有
- @Repository :放在Dao接口的实现类上,表示创建Dao对象,持久层访问数据库的对象
- @Service :放在业务层接口的实现类上 表示创建业务层对象
- @Controller :放在控制器类的上边,表示创建控制器对象,在表现层
/*
* @Component表示创建对象,方到Spring容器里作用和Bean标签一样 value表示对象名称,跟Bean标签的id一样
* 使用在类上,表示此类要是用spring创建对象
可以省略value,也可以省略括号里的内容,默认类名首字母小写
和
* */
@Component(value = "Mystudent")
public class Student {
private String name;
private Integer age;
}
扫描多个包
- 使用多个自检扫描器
- 使用分隔符: ,
- 适用父包
<!--
声明组件扫描器: 使用逐渐必须加上
component-scan组件扫描器
属性base-package 包含注解项目的包名,Sprin回去扫描这个包的所有类,找到所有的注解,遇到逐渐,按照注解功能差创建对象
-->
<context:component-scan base-package="org.example.S01"></context:component-scan>
@Value
@Component(value = "Mystudent")
public class Student {
/*
* 简单类型赋值 @Value
* 属性: value 简单类型属性值
* 放在属性定义上边无需set方法,或者放在set方法上
* */
@Value(value = "张三")
private String name;
@Value(value = "12")
private Integer age;
}
value使用外部文件
@Value("${myname}")
private String name;
@Value("${myage}")
private Integer age;
<context:property-placeholder location="Student.properties"></context:property-placeholder>
@Autowired
给引用类型赋值,自动注入支持 ByName,ByType,默认ByType,位置在属性上边无需Set方法 他的required属性默认为真,回去检查是否赋值成功,false不检查
@Component
public class Student {
@Value("李四")
private String name;
@Value("22")
private Integer age;
@Autowired
private Grade grade;
@Override
public String toString() {
return "Student{" +
"name='" + name + ''' +
", age=" + age +
", grade=" + grade +
'}';
}
}
public class Grade {
private Integer Id;
private String name;
public void setId(Integer id) {
Id = id;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Grade{" +
"Id=" + Id +
", name='" + name + ''' +
'}';
}
}
<bean id="grade" class="org.example.S02.Grade">
<property name="name" value="五年级"></property>
<property name="id" value="5"></property>
</bean>
ByName自动注入也是使用 @Autowired加 @Qualifer
@Autowired
@Qualifier(value = "grade1")
private Grade grade;
@Resource
来自jdk,默认ByName,找不到就使用ByType