文章目录
Spring基础知识了解
Spring官网:https://spring.io/
什么是Spring?
Spring是与2003年新奇的一个轻量级的java开发框架,它是为了解决企业引用开发的复杂新二创建的。Spring的核心是控制反转(IOC)和面向切面编程(AOP)。
Spring的主要作用是为代码“解耦”,降低代码间的耦合度。就是让对象和对象、模块和模块之间不是使用代码关联,而是通过配置来说明。即在Spring中说明对象或者模块的关系。
Spring根据代码的功能特点,使用IOC降低业务之间耦合度。IOC是的主业务在相互调用过程中,不用自己维护关系了,即不用自己创建需要使用的对象了。而是由Spring容器统一管理,自动“注入”,即就是自动赋值。使用AOP使得系统级服务得到最大的复用,且不用再由程序员手动将系统服务“混杂”到主业务逻辑中了,而是有Spring容器统一完成。
总之:Spring是一个容器,它是整合其他框架的框架,它的核心是IOC和AOP,它是由20多个模块组成。
耦合度:事物之间的关联程度。比如一块布耦合度非常高,用这块布做的衣服,耦合度就相对低一点。
Spring的特点
- 轻量级。由20多个模块构成,每个jar包都很小,核心包就3M左右
- 面向接口编程。使用接口,项目的可维护性,可扩展性都高。接口不关心实现类的类型,使用接口指向实现类,切换实现类即可换整个功能。
- AOP:面向切面编程。三层式开发:界面层、业务逻辑层、数据访问层会有公共的逻辑或者业务处理,重复的代码,我们会提出来单独写,谁用谁取。那些公共的代码就是切面。公共的提取出来,需要的时候反置回去,就是面向切面编程,底层的原理是动态代理。
- 整合其他框架。整合后使其他框架更易用。
Spring的体系结构
Data Access(数据库整合):
JDBC, ORM, OXM, JMS, Transaction
Web(MVC Web 开发):
Web, Servlet, Portlet, Struts
AOP(切面编程)
AOP 框架: Aspects
JVM的代理:Instrumentation;
发送消息:Messaging;
Core Container(核心容器):
Beans: 管理 Beans
Core: Spring 核心
Context: 配置文件
ExpressionLanguage: SpEL 表达式
Test(Junit 整合)
什么是IOC?
控制反转IOC(Inversion of Control)是一种思想。由于Spring容器进行对象的创建和依赖注入。程序员取出直接使用。
正转:由程序员创建对象和依赖注入称为正转。
Student student = new Student();
student.setName("张三");
反转:由Spring容器创建对象和依赖注入称为反转,将控制权从程序员手中夺走。
<bean id="student" class="com.www.spring.demo.Student">
<property name="id" value="100"/>
<property name="account" value="张三"/>
</bean>
项目搭建
- 搭建项目
- 更改pom.xml文件。添加spring核心依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
- 创建实体类。
public class Admin {
private Integer id;
private String name;
private String num;
private String account;
public Admin(Integer id, String name, String num) {
this.id = id;
this.name = name;
this.num = num;
}
public Admin() {
}
public void doSome() {
System.out.println("执行此方法");
}
}
- 添加applicationContext.xml文件,用于创建对象。
- 在applicationContext.xml文件中添加bean标签。
<?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">
<!--告诉spring创建对象
声明bean , 就是告诉spring要创建某个类的对象,一个bean只能声明一个对象
id:对象的定义名称,惟一的.spring通过这个id找到对象
class:类的全限定名称(不能是接口,因为spring是反射机制创建对象的)
scope:bean的作用域
singleton(默认):单例的只创建一个对象,在spring启动时就会创建好
prototype:原型的 ,每次都会创建一个对象,在获取时才创建
spring框架有一个map集合存放对象
springMap.put(id值,对象)
-->
<bean id="admin" class="com.www.spring.modle.Admin"/>
</beans>
<!--
spring 的配置标签
1.beans: 跟标签,spring吧java对象称为bean
2.spring-beans.xsd是约束文件,和Mybatis指定 dtd是一样的 用来控制文件中出现的标签.
-->
- 测试
public void test1(){
//使用Spring容器创建的对象 默认调用无参构造
//1.指定spring配置文件的名称
String config = "applicationContext.xml";
//2.创建表示spring容器的对象 ApplicationContext
//ApplicationContext 表示spring的容器
//ClassPathXmlApplicationContext:表示从类路径中加载spring的配置文件
ApplicationContext ac = new ClassPathXmlApplicationContext(config);//此时构造方法执行,创建对象
//在创建spring对象时会创建配置文件中所有的对象
//从容器中获取某个对象,要调用对象的方法
//getBean("配置文件中的bean的id值")
Admin admin = (Admin) ac.getBean("admin");
admin.doSome();
}
以上创建对象的过程虽然看起来过程复杂,且漫长,但是有没有发现此过程中我们是没有new过的,直接通过配置文件以及名字就创建对象了。
spring中常用到的方法:
public void test2(){
String config = "applicationContext.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(config);
//getBeanDefinitionCount():容器中定义的对象的个数
int nums = ac.getBeanDefinitionCount();
System.out.println("容器中定义的对象的个数"+nums);
//getBeanDefinitionNames():容器中定义的每个对象的名字
String names[] = ac.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
}
创建非自定的对象:
<bean id="mydate" class="java.util.Date"/>
<!--
只要知道全类名就好了
-->
依赖注入(di)
di:创建对象并给属性赋值。
两种实现方法:
- 在spring的配置文件中,使用标签和属性完成,叫做基于XML的di实现
- 使用spring中的注解,完成属性赋值,叫做基于注解的di实现
基于XML的di
- set注入(设值注入):spring调用类的set方法,在set方法可以实现属性的赋值。
<!--
简单类型的注入 value
-->
<bean id="student" class="com.www.spring.modle.Student">
<property name="name" value="张三"/>
<property name="id" value="1"/>
<property name="num" value="1001"/>
</bean>
<!--
引用类型的注入 ref
-->
<bean id="student1" class="com.www.spring.modle.Student">
<property name="name" value="张四"/>
<property name="id" value="2"/>
<property name="num" value="1002"/>
<property name="admin" ref="admin"/>
</bean>
<bean id="admin" class="com.www.spring.modle.Admin">
<property name="name" value="admin"/>
<property name="id" value="1"/>
</bean>
<!--
set注入时,调用实体类中的set方法
-->
- 构造注入,spring调用类的有参构造方法,创建对象,在构造方法中完成赋值。
使用constructor-arg标签
一个constructor-arg标签表示构造方法的一个参数
name:属性表示构造方法的形参名
index:表示构造方法的参数的位置,从左往右 0 1 2 3…
ref:构造方法的形参是引用类型
value:构造方法的形参是简单类型
<!--使用name方式-->
<bean id="student2" class="com.www.spring.modle.Student">
<constructor-arg name="name" value="张武"></constructor-arg>
<constructor-arg name="num" value="1003"></constructor-arg>
<constructor-arg name="admin" ref="admin"></constructor-arg>
</bean>
<!--使用index方式 -->
<bean id="student3" class="com.www.spring.modle.Student">
<constructor-arg index="1" value="1004"></constructor-arg>
<constructor-arg index="0" value="张流"></constructor-arg>
<constructor-arg index="2" ref="admin"></constructor-arg>
</bean>
<!--省略index的方式-->
<bean id="student4" class="com.www.spring.modle.Student">
<constructor-arg value="张流"></constructor-arg>
<constructor-arg value="1004"></constructor-arg>
<constructor-arg ref="admin"></constructor-arg>
</bean>
引用类型的自动注入
引用类型的自动注入:Spring框架根据某些规则给引用类型赋值。不用自己给引用类型赋值使用的规则常用的是byName,byType。
byName(按名称注入)
- byName(按名称注入):java类中引用类型的属性名和spring容器中(配置文件中)bean的id名称一样,且数据类型是一致的,这样的容器中的bean,spring能够赋值给引用类型。
<bean id="student5" class="com.www.spring.modle.Student" autowire="byName">
<property name="name" value="张其"/>
<property name="id" value="7"/>
<property name="num" value="1007"/>
</bean>
byType(按类型注入)
2.byType(按类型注入):java类中引用类型的数据类型和spring容器中(配置文件)bean的class属性是同源关系的,这样的bean可以赋值给引用类型
同源的意思:
- java类中引用类型的数据类型和bean的class的值是一样的
- java类中引用类型的数据类型和bean的class的值是父子类关系的。
- java类中引用类型的数据类型和bean的class的值是接口和实现类的关系
注 : byType中, 在xml中声明的bean只能有有一个符合条件的
<bean id="student6" class="com.www.spring.modle.Student" autowire="byName">
<property name="name" value="张其"/>
<property name="id" value="7"/>
<property name="num" value="1007"/>
</bean>
使用多配制文件
当类的声明非常多的时候,将所有的声明都放在一个配置文件中是不可取的;在做项目的时候,多人使用同一个配置文件时,是及其容易出现错误的;
多配制文件的优势:
- 每个文件的大小比一个文件小得多,易操作,效率高。
- 避免多人竞争带来的冲突。
多文件的分配方式:
- 如果项目由多个模块构成,建议一个模块一个配置文件。
- 按类的功能,数据库相关配置一个文件,做事务的功能一个配置文件,做service功能一个配置文件。
具体操作:
<!--student配置文件-->
<bean id="student" class="com.www.spring.modle.Student" autowire="byType">
<property name="name" value="张其"/>
<property name="id" value="7"/>
<property name="num" value="1007"/>
</bean>
<!--admin配置文件-->
<bean id="admin" class="com.www.spring.modle.Admin">
<property name="name" value="admin"/>
<property name="id" value="1"/>
</bean>
<!--主配置文件-->
<!--
关键字classpath:表示类路径(class文件所在的目录),
在spring的配置文件中要指定其他文件的位置,需要使用classpath,
告诉spring到哪去加载读取文件。
注意:classpath后面不要随意添加空格,容易出现错误
-->
<import resource="classpath:be01/spring-Student.xml"/>
<import resource="classpath:be01/spring-Admin.xml"/>
public void test4(){
//加载总文件
String config = "be01/spring-Total.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(config);
Student student = ac.getBean("student",Student.class);
System.out.println(student);
}
以上主配置文件中import可以使用通配符
<!--
使用通配符时,注意文件需要在一级(如:be01)目录下,否则将不能加载到主文件;
还有主配置文件的名字不能与其他问价前缀相同。
-->
<import resource="classpath:be01/spring-*.xml"/>
基于注解的di
使用注解的步骤:
- 加入maven的依赖;早在加入spring-context时就已经间接加入了spring-aop,所以不需要再添加。
- 在类中加入spring的注解;
- 在spring的配置文件中,加入一个组件扫描的标签,说明注解的位置。
<context:component-scan base-package="com.www.spring"/>
添加完component-scan标签后配置文件会多出:
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
- 使用注解
常用的注解:
- @component:创建对象的,相当于bean标签的功能,属性value就是对象的名称,也就是bean中的id值,value的值时惟一的,创建的对象在整个spring容器中是惟一的,创建对象时调用构造方法,注解的位置:类的上面。
//写法1:
//@component(value = “admin)
//等同于<bean id="admin" class="com.ffyc.spring.modle.Admin"></bean>
//写法2:省略value
//@component(指定对象的名称)
//写法3:不指定对象的名称,由spring默认名称:首字母小写的类名。
//@component
@Component(value = "admin")//等同于<bean id="admin" class="com.ffyc.spring.modle.Admin"></bean>
public class Admin {
private Integer id;
private String name;
private String num;
private String account;
public Admin(String name, String num, String account) {
this.name = name;
this.num = num;
this.account = account;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNum() {
return num;
}
public void setNum(String num) {
this.num = num;
}
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
public Admin(Integer id, String name, String num) {
this.id = id;
this.name = name;
this.num = num;
}
public Admin() {
System.out.println("无参构造方法");
}
public void doSome() {
System.out.println("执行此方法");
}
@Override
public String toString() {
return "Admin{" +
"id=" + id +
", name='" + name + '\'' +
", num='" + num + '\'' +
", account='" + account + '\'' +
'}';
}
}
-
@Respotory:(用在持久层上面的)与@component功能一致,创建的是dao对象,dao对象是能访问数据库的。
-
@service:(用在业务逻辑层类上面的) 与@component功能一致,放在service的实现类上面,创建service对象,service对象是做业务处理,可以有事务功能的。
-
@controller:(用在控制器上面的)与@component功能一致,放在控制器(处理器)类的上面,创建控制器对象的,控制器对象,能够接受用户提交的参数,显示请求结果。
以上注解与@component功能一致,语法相同,但是各自还有额外功能,他们是给项目分层的。
- @value:为简单类型赋值,使用此注解时,必须已经创建对象
/*
可以写在属性定义的上面,无需set方法,比较常用
也可以写在set方法上面
*/
@Component("student")
@Data
public class Student {
private Integer id;
@Value( "张吧")
private String name;
@Value(value = "1008")
private String num;
private Admin admin;
public Student() {
}
public Student(String name, String num, Admin admin) {
this.name = name;
this.num = num;
this.admin = admin;
}
}
- @Autowired:spring框架提供的注解,实现引用类型的赋值。spring中通过注解给引用类型赋值,使用的是自动注入原理,支持byType,byName。默认使用byTy自动注入。
@Autowired
private Admin admin;
如果使用byName的方式:需要借助@Qualifier(value = “对象名称”)
@Autowired
@Qualifier(value = "admin")//这里的admin是Admin类创建对象的名称,相当于bean的id
private Admin admin;//这里的admin是Student类中属性名
//两个注解不分先后
@Autowired中有一个属性:required
required=true :表示引用类型赋值失败,程序终止,程序报错
required=false:表示引用类型赋值失败,程序不终止,引用类型为null
- @Resource:来之jdk中的注解,spring提供了jdk中@Resource注解的支持,该注解可以支持byType、byName方式,默认是byName。
先使用byName自动注入,如果byName赋值失败,再改用byType自动注入。
只想使用byName一种方式时:
@Resource(name = "admin")
private Admin admin;
注解与xml配置文件对比
配置文件:
优点:代码和值是完全分开的,对于经常改值的,可以用配置文件;
缺点:语法繁杂,与代码完全分开,浏览源代码时,不知道对应的值。
注解:
优点:快捷方便,速度快,代码简洁;不经常改变的用注解比较方便
缺点:硬编入java代码中,修改后需要重新编译