Spring
文章目录
1. Spring框架
1.1 概述
Spring 是于2003 年兴起的一个轻量级的Java 开发框架,它是为了解决企业应用开发的复杂性而创建的。Spring的核心是控制反转(IoC)和面向切面编程(AOP)。Spring是可以在Java SE/EE中使用的轻量级开源框架。
Spring的主要作用就是为代码“解耦”,降低代码间的耦合度。就是让对象和对象(模块和模块)之间关系不是使用代码关联,而是通过配置来说明。即在Spring中说明对象(模块)的关系。
Spring根据代码的功能特点,使用Ioc降低业务对象之间耦合度。IoC使得主业务在相互调用过程中,不用再自己维护关系了,即不用再自己创建要使用的对象了。而是由Spring 容器统一管理,自动“注入”,注入即赋值。而AOP使得系统级服务得到了最大复用,且不用再由程序员手工将系统级服务“混杂”到主业务逻辑中了,而是由Spring容器统一完成“织入”。
1.2 优点
- 轻量:Spring的所需要的jar包都非常小,一般1M以下,几百kb。核心功能所需要的jar包总共3M左右。
Spring框架运行占有资源少,运行效率高,不依赖其他jar。、 - 针对接口编程,解耦合
- AOP 编程的支持
- 方便集成各种优秀框架
1.3 Spring体系架构
Spring 由 20 多个模块组成,它们可以分为数据访问/集成(Data Access/Integration)、 Web、面向切面编程(AOP, Aspects)、提供JVM的代理 (Instrumentation)、消息发送(Messaging)、 核心容器(Core Container)和测试(Test)。
2. IoC控制反转
2.1 概述
控制反转(IoC,Inversion of Control):是一个概念,是一种思想。指将传统上由程序代码直接操控的对象调用权交给容器,通过容器来实现对象的装配和管理。控制反转就是对对象控制权的转移,从程序代码本身反转到了外部容器。通过容器实现对象的创建,属性赋值,依赖的管理。
控制:创建对象,对象的属性赋值,对象之间的关系管理。
反转:把原来的开发人员管理,创建对象的权限转移给代码之外的容器实现。 由容器代替开发人员管理对象。创建对象,属性赋值。
正转:由开发人员在代码中,使用new 构造方法创建对象, 开发人员主动管理对象。
public static void main(String args[]){
Student student = new Student(); // 在代码中, 创建对象。--正转。
}
容器:是一个服务器软件, 一个框架(spring)
使用 ioc 目的: 减少对代码的改动,也能实现不同的功能。 实现解耦合。
java中创建对象有哪些方式:
- 构造方法 , new Student()
- 反射
- 序列化
- 克隆
- ioc :容器创建对象
- 动态代理
IoC的技术实现:
依赖注入(DI,Dependency Injection):依赖注入, 只需要在程序中提供要使用的对象名称就可以, 至于对象如何在容器中创建,赋值,查找都由容器内部实现。
spring是使用的di实现了ioc的功能, spring底层创建对象,使用的是反射机制。
spring是一个容器,管理对象,给属性赋值, 底层是反射创建对象。
2.2 创建一个Spring项目
2.2.1 创建maven项目,并导入spring依赖
导入依赖:
<dependencies>
<!--单元测试:通过单元测试可以测试每一个方法-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--Spring的依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
</dependencies>
2.2.2 创建业务接口与实现类
接口:
public interface SomeService {
void doSome();
}
实现类:
public class SomeServiceImpl implements SomeService {
@Override
public void doSome() {
System.out.println("====SomeServiceImpl业务方法doSome=====");
}
}
ps:spring默认调用无参数构造方法创建对象
2.2.3 创建Spring配置文件
在 src/main/resources/目录下创建一个 xml 文件,文件名随意,但Spring 建议的名称为 applicationContext.xml。 IDEA已经设计好了Spring配置文件的模板:
右击resources–>new–>XML configuration file–>Spring Config
配置配置文件:
<?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 id="someService" class="com.sqt.service.impl.SomeServiceImpl" />
<bean id="someService1" class="com.sqt.service.impl.SomeServiceImpl" scope="prototype"/>
<!--
spring创建一个非自定义类的对象, 创建一个存在的某个类的对象。
-->
<bean id="mydate" class="java.util.Date" />
</beans>
<!--
spring的配置文件
1.beans : 是根标签,spring把java对象成为bean。
2.spring-beans.xsd 是约束文件,和mybatis指定 dtd是一样的。
-->
声明bean ,告诉spring要创建某个类的对象:
-
id:对象的自定义名称,唯一值。 spring通过这个名称找到对象
-
class:类的全限定名称(不能是接口,因为spring是反射机制创建对象,必须使用类)
-
scope:指定bean对象的作用域(对象的存在范围和可见性)。可取值:
- 单例:singleton , 默认值,表示叫这个名称的对象在spring容器中只有一个。
- 原型:prototype , 表示每次使用getBean()都创建一个新的对象。
spring就完成 SomeService someService = new SomeServiceImpl();
spring是把创建好的对象放入到map中, spring框架有一个map存放对象的。
springMap.put(id的值, 对象);
例如 :springMap.put("someService", new SomeServiceImpl());
一个bean标签声明一个对象。
2.2.4 创建测试类
@Test
public void test01(){
//定义Spring的配置文件, 配置文件是在类路径的根目录之下
String config = "applicationContext.xml";
//创建Spring的容器对象.根据Spring配置文件的位置,使用接口的不同实现类
//1.如果Spring的配置文件是在类路径(classpath),使用ClassPathXmlApplicationContext
//2.如果Spring的配置文件是放在项目的根之下(与src、target同级目录),使用FileSystemXmlApplicationContext
//创建Spring容器,会读取配置文件中的bean标签,并创建对应的对象。
ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
//从容器中获取对象 使用getBean("<bean>的id")
SomeService service = (SomeService) ctx.getBean("someService");
//调用业务方法
service.doSome();
}
2.3 基于XML的DI
通过在xml配置文件对对象的属性进行赋值。
di的实现有两种:
-
在spring的配置文件中, 使用标签和属性完成,叫做基于XML的di实现
-
使用spring中的注解,完成属性赋值, 叫做基于注解的id实现
di的语法分类:
-
set注入(设置注入): spring调用类的set方法,在set方法可以实现属性的赋值。
80左右都是使用的set注入 -
构造注入,spring调用类的有参数构造方法,创建对象。在构造方法中完成赋值。
2.3.1 set注入
set注入也叫设值注入是指,通过setter方法传入被调用者的实例。这种注入方式简单、直观,因而在Spring的依赖注入中大量使用。
简单类型(Java中的基本类型和String类型)
实体类:
public class Student {
private String name;
private int age;
/*
需要有set方法,没有set方法是报错的。
Bean property 'name' is not writable or has an invalid setter method
*/
public void setName(String name) {
this.name = name.toUpperCase();
}
public void setAge(int age) {
this.age = age;
}
public void setEmail(String email){
System.out.println("setEmail="+email);
}
}
applicationContext.xml:
<!--声明student对象
<bean id="xx" class="yyy">
<property name="属性名字" value="此属性的值"/>
一个property只能给一个属性赋值
<property.sqt..sqt.>
</bean>
-->
<bean id="myStudent" class="com.sqt.ba01.Student" >
<property name="name" value="李四lisi" /><!--setName("李四")-->
<property name="age" value="22" /><!--setAge(21)-->
<property name="email" value="lisi@qq.com" /><!--setEmail("lisi@qq.com")-->
</bean>
引用类型:
当指定 bean 的某属性值为另一 bean 的实例时,通过 ref 指定它们间的引用关系。ref 的 值必须为某 bean 的 id 值。
实体类:(都有set方法)
public class School {
private String name;
private String address;
}
public class Student {
private String name;
private int age;
//声明一个引用类型
private School school;
}
applicationContext.xml:
<bean id="xxx" class="yyy">
<property name="属性名称" ref="bean的id(对象的名称)" />
</bean>
<bean id="myStudent" class="com.sqt.ba02.Student" >
<property name="name" value="李四" />
<property name="age" value="26" />
<!--引用类型-->
<property name="school" ref="mySchool" /><!--setSchool(mySchool)-->
</bean>
<!--声明School对象-->
<bean id="mySchool" class="com.sqt.ba02.School">
<property name="name" value="北京大学"/>
<property name="address" value="北京的海淀区" />
</bean>
2.3.2 构造注入(了解)
构造注入是指,在构造调用者实例的同时,完成被调用者的实例化。即,使用构造器设置依赖关系。
给实体类添加构造器:
//定义有参数构造方法
public Student(String myname, int myage, School mySchool){
System.out.println("Student有参数构造方法");
//给属性完成赋值
this.name = myname;
this.age = myage;
this.school = mySchool;
}
applicationContext.xml:
标签:一个表示构造方法一个参数。
标签属性:
- name:表示构造方法的形参名
- index:表示构造方法的参数的位置,参数从左往右位置是 0 , 1 ,2的顺序
- value:构造方法的形参类型是简单类型的,使用value
- ref:构造方法的形参类型是引用类型的,使用ref
<!--使用name属性实现构造注入-->
<bean id="myStudent" class="com.sqt.ba03.Student" >
<constructor-arg name="myage" value="20" />
<constructor-arg name="mySchool" ref="myXueXiao" />
<constructor-arg name="myname" value="周良"/>
</bean>
<!--使用index属性-->
<bean id="myStudent2" class="com.sqt.ba03.Student">
<constructor-arg index="1" value="22" />
<constructor-arg index="0" value="李四" />
<constructor-arg index="2" ref="myXueXiao" />
</bean>
<!--省略index-->
<bean id="myStudent3" class="com.sqt.ba03.Student">
<constructor-arg value="张强强" />
<constructor-arg value="22" />
<constructor-arg ref="myXueXiao" />
</bean>
<!--声明School对象-->
<bean id="myXueXiao" class="com.sqt.ba03.School">
<property name="name" value="清华大学"/>
<property name="address" value="北京的海淀区" />
</bean>
2.3.3 引用类型的自动注入
对于引用类型属性的注入,也可不在配置文件中显示的注入。可以通过为标签 设置 autowire 属性值,为引用类型属性进行隐式自动注入(默认是不自动注入引用类型属 性)。根据自动注入判断标准的不同,可以分为两种:
- byName:根据名称自动注入
- byType: 根据类型自动注入
byName
当配置文件中被调用者 bean 的 id 值与代码中调用者 bean 类的属性名相同时,可使用 byName 方式,让容器自动将被调用者 bean 注入给调用者 bean。容器是通过调用者的 bean 类的属性名与配置文件的被调用者 bean 的 id 进行比较而实现自动注入的。
java类中引用类型的属性名和spring容器中(配置文件)的id名称一样,且数据类型是一致的,这样的容器中的bean,spring能够赋值给引用类型。
<bean id="xx" class="yyy" autowire="byName">
简单类型属性赋值
</bean>
<!--byName-->
<bean id="myStudent" class="com.sqt.ba04.Student" autowire="byName">
<property name="name" value="李四" />
<property name="age" value="26" />
<!--引用类型-->
<!--<property name="school" ref="mySchool" />-->
</bean>
<!--声明School对象-->
<bean id="school" class="com.sqt.ba04.School">
<property name="name" value="清华大学"/>
<property name="address" value="北京的海淀区" />
</bean>
byType
byType(按类型注入) :java类中引用类型的数据类型和spring容器中(配置文件)的class属性是同源关系的,这样的bean能够赋值给引用类型.
同源就是一类的意思:
- java类中引用类型的数据类型和bean的class的值是一样的。
- java类中引用类型的数据类型和bean的class的值父子类关系的。
- java类中引用类型的数据类型和bean的class的值接口和实现类关系的
<bean id="xx" class="yyy" autowire="byType">
简单类型属性赋值
</bean>
注意:在byType中, 在xml配置文件中声明bean只能有一个符合条件的,多余一个是错误的
<!--byType-->
<bean id="myStudent" class="com..ba05.Student" autowire="byType">
<property name="name" value="张飒" />
<property name="age" value="26" />
<!--引用类型-->
<!--<property name="school" ref="mySchool" />-->
</