Spring简介
Spring 意为 春天,指的是给软件行业带来春天。在2002 年,首次推出了Spring框架的雏形interface21框架。Spring框架以interface21框架为基础,经过重新设计,并不断丰富其内涵,于2004年3月24日,发布了1.0正式版。
Spring 是个Java企业级应用的开源开发框架。Spring主要用来开发Java应用,但是有些扩展是针对构建J2EE平台的web应用。
Spring 框架目标是:简化Java企业级应用开发,并通过pojo为基础的编程模型促进良好的编程习惯。
Spring理念是:使现有的技术更加容易使用,它整合了现有的技术框架。
有关Spring的网址:
官网:https://spring.io/projects/spring-framework#overview
官方下载地址: http://repo.spring.io/release/org/springframework/spring
GitHub:https://github.com/spring-projects/spring-framework
Spring的依赖:
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
Spring的优点:
- Spring是一个开源的免费的框架(容器),支持事务的处理,支持框架整合。
- Spring是一个轻量级的、非入侵式的框架,基本的版本大约2MB。
- 控制反转(IOC),Spring通过控制反转实现了松散耦合,对象们给出它们的依赖,而不是创建或查找依赖的对象们。
- 面向切面编程(AOP),Spring支持面向切面的编程,并且把应用业务逻辑和系统服务分开。
- 容器,Spring 包含并管理应用中对象的生命周期和配置。
- MVC框架,Spring的WEB框架是个精心设计的框架,是Web框架的一个很好的替代品。
- 事务管理,Spring 提供一个持续的事务管理接口,可以扩展到上至本地事务下至全局事务。
- 异常处理,Spring 提供方便的API把具体技术相关的异常转化为一致的unchecked 异常。
Spring就是一个轻量级的控制反转(IOC) 和面向切面编程(AOP)的框架
Spring的组成:
IOC
IOC思想
搭建环境并测试:
- 编写User实体类
- 编写UserMapper接口
- 编写UserMapperImpl实现类
- 编写UserService业务接口
- 编写UserServiceImpl 业务实现类
- 编写测试类
在业务中,用户的需求可能会发生改变,此时我们的代码就需要对应地进行修改。如果程序的代码量很大的话,修改一次的成本代价则会什么昂贵。
在业务层处理时,是由程序员创建对象的,可以说主动权在程序员手中,程序员决定了程序调用什么。
但是当使用一个set方法时,会发生革命性的变化。
利用set可以动态地实现值的注入。
对比:
- 没使用set之前,程序是主动创建对象,控制权掌握在程序员手中。
- 使用set注入后,程序不再具有主动性,而是被动地接受对象。
动态的注入这种思想,从本质上解决了问题,我们不用管对象的创建了,同时系统的耦合性大大降低了。我们可以更加专注地在业务的实现上,这就是IOC 的原型。
IOC本质
IOC(Inverse of Control),控制反转,是一种设计思想;DI(Dependency Injection),依赖注入则是显示IOC的一种方法。在没有IOC的程序中,我们使用面向对象编程,对象的创建和对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后则将对象的创建转移给第三方,所谓控制反转可以理解为:获得依赖对象的方式反转了。
采用xml方式配置bean的时候,bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。
控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。
第一个Spring程序
1. 导入Spring相关的jar包
Spring需要导入commons-logging进行日志记录 。我们使用maven , 他会自动下载对应的依赖项。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
2. 编写相关的代码
编写一个Hello实体类
package com.llx.pojo;
public class Hello {
private String name;
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("Hello,"+name);
}
}
编写我们的Spring文件,将其命名为applicationContext.xml
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd ">
<bean id="hello" name="hello2 hello3 hello4" class="com.llx.pojo.Hello">
<property name="name" value="Spring"/>
</bean>
</beans>
测试
@Test
public void testHello(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Hello hello = (Hello) context.getBean("hello");
hello.show();
}
进行测试完之后,我们可以理解:
- Hello对象是由Spring创建的
- Hello对象的属性是有Spring容器设置的
这个过程就叫做控制反转。
控制:谁来控制对象的创建?传统应用程序的对象是由程序本身控制创建的;使用Spring后,对象则是由Spring来创建的。
反转:程序本身不创建对象,而变成被动地接受对象。
依赖注入:利用set方法来进行注入。
IOC是一种编程思想,由主动编程变为被动接受。
理解了IOC之后,我们可以彻底不用再去程序中进行改动了,要实现不同的操作,只需要在xml配置文件中进行修改。所谓的IOC,即 对象由Spring来创建,管理和装配。
IOC创建对象的方式
使用无参构造创建对象
可以使用无参构造创建对象,这是默认的方式。
使用有参构造创建对象
如果要使用有参构造来创建对象,有以下几种方式:
-
下标赋值
<!--第一种,下标赋值!--> <bean id="user" class="com.llx.pojo.User"> <constructor-arg index="0" value="llx"/> </bean>
-
类型
<!--第二种方式:通过类型创建,不建议使用!--> <bean id="user" class="com.llx.pojo.User"> <constructor-arg type="java.lang.String" value="LLX"/> </bean>
-
参数名
<!--第三种,直接通过参数名来设置--> <bean id="user" class="com.kuang.pojo.User"> <constructor-arg name="name" value="LLX1"/> </bean>
在配置文件加载的时候,容器中管理的对象就已经初始化了!
Spring配置
别名
对对象设置别名,设置别名后,也可以通过别名获取到这个对象。
<alias name="user" alias="userNew"/>
Bean的配置
bean标签 中有几个常用的属性:
属性 | 含义 |
---|---|
id | id是bean的唯一标识符,即相当于我们学的对象名 |
class | class是bean对象所对应的全限定名即 包名+类名 |
name | name是别名,而且name可以同时取多个别名 |
<bean id="hello" name="hello2 hello3 hello4" class="com.llx.pojo.Hello">
<property name="name" value="Spring"/>
</bean>
import
import,一般用于团队开发,可以将多个配置文件导入合并为一个。
将多个配置文件,使用import标签,导入在applicationContext.xml中即可。
<import resource="user.xml"/>
<import resource="hello.xml"/>
<import resource="bean.xml"/>
在使用的时候,使用总的配置文件applicationContext.xml即可。
依赖注入
依赖注入的方式有好几种:
- 构造器注入
- set方式注入
- p命令空间和c命令空间
set方式注入
set注入:
- 依赖:bean对象的创建依赖于容器
- 注入:bean对象中的所有属性,由容器来注入
环境搭建
1、编写一个Address类,复杂类型:
package com.llx.pojo;
public class Address {
private String address;
private com.llx.pojo.Student student;
public void setAddress(String address) {
this.address = address;
}
public String getAddress() {
return address;
}
}
2、编写Student类,真实测试对象
package com.llx.pojo;
import java.util.*;
public class Student {
private String name;
private Address address;
private String[] books;
private List<String> list;
private Map<String,String> map;
private Set<String> set;
private String wife ;// null
private Properties info;
public void setName(String name) {
this.name = name;
}
public void setAddress(Address address) {
this.address = address;
}
public void setBooks(String[] books) {
this.books = books;
}
public void setList(List<String> list) {
this.list = list;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
public void setSet(Set<String> set) {
this.set = set;
}
public void setWife(String wife) {
this.wife = wife;
}
public void setInfo(Properties info) {
this.info = info;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", address=" + address.getAddress() +
", books=" + Arrays.toString(books) +
", list=" + list +
", map=" + map +
", set=" + set +
", wife='" + wife + '\'' +
", info=" + info +
'}';
}
}
3、编写student.xml配置文件,并将其导入applicationContext.xml中
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="student" class="com.llx.pojo.Student">
<property name="name" value="llx"/>
</bean>
</beans>
4、测试类
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Student student = (Student) context.getBean("student");
System.out.println(student.getName());
}
}
完整的注入信息如下:
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="addr" class="com.llx.pojo.Address">
<property name="address" value="西安"/>
</bean>
<bean id="student" class="com.llx.pojo.Student" scope="singleton">
<!--第一种,普通值注入,value-->
<property name="name" value="llx"/>
<!--第二种,Bean注入,ref-->
<property name="address" ref="addr"/>
<!--数组-->
<property name="books">
<array>
<value>西游记</value>
<value>红楼梦</value>
<value>水浒传</value>
</array>
</property>
<!--List-->
<property name="list">
<list>
<value>list1</value>
<value>list2</value>
<value>list3</value>
</list>
</property>
<!--Map-->
<property name="map">
<map>
<entry key="key1" value="v1"/>
<entry key="key2" value="v2"/>
<entry key="key3" value="v3"/>
</map>
</property>
<!--Set-->
<property name="set">
<set>
<value>set1</value>
<value>set2</value>
<value>set3</value>
</set>
</property>
<!--null-->
<property name="wife">
<null/>
</property>
<!--Properties-->
<property name="info">
<props>
<prop key="id">122</prop>
<prop key="name">llx</prop>
<prop key="sex">female</prop>
</props>
</property>
</bean>
</beans>
拓展方式注入
可以使用 p命名空间和c命名空间进行注入。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--p命名空间注入,可以直接注入属性的值:property-->
<bean id="user" class="com.llx.pojo.User" p:name="llx" p:age="20"/>
<!--c命名空间注入,通过构造器注入:construct-args-->
<bean id="user2" class="com.llx.pojo.User" c:age="20" c:name="llx2"/>
</beans>
测试:
@Test
public void test2(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = context.getBean("user2", User.class);
System.out.println(user);
}
需要注意的是,p命名和c命名空间不能直接使用,需要导入xml约束才可以。
xmlns:c="http://www.springframework.org/schema/c"
xmlns:p="http://www.springframework.org/schema/p"
bean的作用域
单例模式
单例模式是Spring的默认机制。
<bean id="student" class="com.llx.pojo.Student" scope="singleton">
<property name="name" value="刘丽侠"/>
</bean>
原型模式
原型模式,每次从容器中get的时候,都会产生一个新的对象
<bean id="student" class="com.llx.pojo.Student" scope="prototype">
<property name="name" value="刘丽侠"/>
</bean>
其余的 request、session、application,这些只能在web开发中使用到。
Bean的自动装配
自动装配是Spring满足bean依赖的一种方式。
Spring会在上下文中自动寻找,并自动给bean装配属性。
在Spring中有三中配置的方式:
- 在xml配置文件中显式地配置
- 在java中显式地配置
- 隐式地自动装配
自动装配有两种方式:ByName和ByType。
测试环境搭建:
以一个人有猫和狗两个宠物为例。
1、编写实体类:
Cat类
package com.llx.entity;
public class Cat {
public void shout(){
System.out.println("miao ~");
}
}
Dog类
package com.llx.entity;
public class Dog {
public void shout(){
System.out.println("wang ~");
}
}
User类
package com.llx.entity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import javax.annotation.Resource;
public class User {
private String name;
private Cat cat;
private Dog dog;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
@Override
public String toString() {
dog.shout();
cat.shout();
return "User{" +
"name='" + name + '\'' +
", cat=" + cat +
", dog=" + dog +
'}';
}
}
2、编写user.xml文件,并导入到applicationContext.xml中
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="cat" class="com.llx.entity.Cat"/>
<bean id="dog" class="com.llx.entity.Dog"/>
<bean id="user" class="com.llx.entity.User">
<property name="cat" ref="cat"/>
<property name="dog" ref="dog"/>
<property name="name" value="llx"/>
</bean>
</beans>
3、编写测试类
@Test
public void test4(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) context.getBean("user");
System.out.println(user.toString());
}
ByName自动装配
设置bean的autowire属性为byName。
byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的bean id。
<bean id="cat" class="com.llx.entity.Cat"/>
<bean id="dog" class="com.llx.entity.Dog"/>
<bean id="user" class="com.llx.entity.User" autowire="byName">
<property name="name" value="llx"/>
</bean>
ByType自动匹配
设置bean的autowire属性为byType。
byType:会自动在容器上下文中查找,和自己对象属性类型相同的bean
<bean id="cat" class="com.llx.entity.Cat"/>
<bean id="dog" class="com.llx.entity.Dog"/>
<bean id="user" class="com.llx.entity.User" autowire="byType">
<property name="name" value="llx"/>
</bean>
总结:
- 使用byname的时候,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致!
- 使用bytype的时候,需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致!
使用注解实现自动装配
使用注解的时候,需要导入约束(context约束);配置注解的支持<context:annotation-config/>
。
在xml文件中配置<context:annotation-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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
</beans>
@Autowired注解
@Autowired注解可以直接在属性上使用,也可以在set方法是使用。
@Autowired 通过byType的方式实现。
使用@Autowired注解,我们可以不用编写set方法,但是前提是自动装配的属性在 IOC(Spring)容器中存在,且符合名字byname。
package com.llx.entity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import javax.annotation.Resource;
public class User {
private String name;
@Autowired
private Cat cat;
@Autowired
private Dog dog;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Cat getCat() {
return cat;
}
public Dog getDog() {
return dog;
}
@Override
public String toString() {
dog.shout();
cat.shout();
return "User{" +
"name='" + name + '\'' +
", cat=" + cat +
", dog=" + dog +
'}';
}
}
如果显示定义了Autowired的required属性为false,说明这个对象可以为null,否则不允许为空。
如果 @Autowired 自动装配的环境比较复杂,自动装配无法通过一个注解(@Autowired)完成的时候,我们可以使用@Qualifier(value=“xxx”)去配合@Autowired的使用,指定一个唯一的bean对象注入!
@Autowired
@Qualifier("dog1") // 匹配指定对象,若没有,则会报红
private Dog dog;
<bean id="dog1" class="com.llx.entity.Dog"/>
<bean id="dog2" class="com.llx.entity.Dog"/>
@Resource注解
@Resource注解是java的注解,作用同 Autowired 和 Qualifier。
@ Resource 默认通过byname的方式实现。
@Resource(name = "cat2") // java 的注解 配置 作用同 Autowired 和 Qualifier
private Cat cat;
@Resource 和@ Autowired 的区别:
- 两者都是用来自动装配的,都可以放在属性字段上
- @ Autowired 通过byType的方式实现,而且必须要求这个对象存在! 【常用】
- @ Resource 默认通过byname的方式实现,如果找不到名字,则通过byType实现!如果两个都找不到的情况下,就报错! 【常用】
- 执行顺序不同:@ Autowired 通过byType的方式实现。@ Resource 默认通过byname的方式实现。