Spirng
1、了解Spring
1.1、简介
-
Spring:春天------->给软件行业带来了春天
-
2002,首次推出了Spring框架的雏形:interface21框架!
-
Spring框架即以interface21框架为基础,经过重新设计,并不断丰富其内涵,于2004年3月24日,发布了1.0正式版。
-
Rod Johnson ,Spring Framework创始人,著名作者。很难想象Rod Johnson的学历,真的让好多人大吃一惊,他是悉尼大学的博士,然而他的专业不是计算机,而是音乐学。
-
spring理念:使现有的技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架!
-
SSH:Struct2+Spring+Hibernate
-
SSM:SpringMvc+Spring+Mybatis
官网:https://spring.io/projects/spring-framework
官方下载地址:https://repo.spring.io/release/org/springframework/spring/
GItHub:https://github.com/spring-projects/spring-framework
<!-- 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>
1.2、优点
- Spring是一个开源的免费的框架!
- Spring是一个轻量级的、非入侵时的框架!
- 控制反转(IOC),面向切面编程(AOP)
- 支持事务的处理,对框架整合的支持!
总结:Spring就是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架
1.3、组成
1.4、扩展
在Spring的官网有这个介绍:现代化的Java开发!说白就是基于Spring的开发
- Spring Boot
- 一个快速开发的脚手架。
- 基于Spring Boot可以快速的开发单个微服务
- 约定大于配置
- Spring Cloud
- Spring Cloud是基于SpringBoot实现的
因为现在大多数公司都在使用SpringBoot进行快速开发,学习SpringBoot的前提,需要完全掌握Spring及
SpringMVC!呈上启下的作用
弊端:发展太久之后违背了原来的理念!配置十分繁琐,人称"配置地狱"
2、IOC理论推导
1.UserDao Dao接口
2.UserDaoImpl Dao实现类
3.UserService 业务接口
4.UserServiceImpl 业务实现类
在我们之前的业务中,用户的需求可能会影响我们原来的代码,我们需要根据用户的需求取修改源代码!如果
程序代码量十分大,修改一次的成本代价十分昂贵
我们使用一个Set接口实现,已经发生了革命性的变化!
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
- 之前,程序是主动创建对象!控制权在程序猿手上!
- 使用了set注入后,程序不再具有主动性,而是变成了被动接受对象
这种思想,从本质上解决了问题,我们程序猿不用再去管理对象的创建了!系统的耦合性大大降低~可以更加的专注业务的实现!
这事IOC的原型!
IOC本质
控制反转IOC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IOC的一种方式,也有人认为DI只是
Ioc的另一种说法。没有Ioc的程序中,我们使用面向对象编程,对象的创建与对象间的依赖关系完全硬编码在程序中,
对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式
反转了。
采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者和为一体,
Bean的定义信息直接以注解的形式定义在实现类中,从而达到零配置的目的
控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反
转的是Ioc容器,其实现方法是依赖注入(Dependency Injection,DI).
3、HelloSpring
@Test
public void test() {
//获取Spring的上下文对象
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//我们的对象现在都在Spring中的管理了,我们要使用,直接去里面取出来就可以
Hello hello = (Hello) context.getBean("hello");
System.out.println(hello.toString());
}
控制:谁来控制对象的创建,传统应用程序的对象是由程序本身控制创建的,使用Spring后,对象是由Spring来创建的
反转:程序本事不创建对象,而变成被动的接受队形
依赖注入:就是利用set方法进行注入的
IOC是一种编程思想,由主动变成被动的接受
OK,到了现在,我们彻底不用在程序中去改动了,要实现不同的操作,只需要在xml配置文件中进行修改,所谓的
ioc,一句话搞定:对象由Spring来创建,管理,装配
4、IOC创建对象的方式
-
使用无参构造方法创建对象 默认
<bean id="user" class="com.wen.pojo.User"> <property name="name" value="温嘉璐"/> </bean>
-
使用有参构造方法创建对象
-
下标赋值
<bean id="user" class="com.wen.pojo.User"> <constructor-arg index="0" value="温嘉璐"/> </bean>
-
类型
<bean id="user" class="com.wen.pojo.User"> <!--第二种通过类型创建,不建议使用--> <constructor-arg type="java.lang.String" value="温嘉璐"/> </bean>
-
参数名
<!--第三种,直接通过参数名--> <bean id="user" class="com.wen.pojo.User"> <constructor-arg name="name" value="温嘉璐"/> </bean>
-
总结:在配置文件加载的时候,容器中管理的对象就已经初始化了
5、Spring配置
5.1、别名
<!-- 别名,如果添加了别名,我们也可以是使用别名获取到这个对象-->
<alias name="user" alias="user2"/>
5.2、Bean的配置
<!--
id:bean 的唯一标识符,也就是相当于我们学的对象名
class:bean 对象所对应的全限定名 :包名+类型
name:也是别名,而且name 可以同时取多个别名
-->
<bean id="userT" class="com.wen.pojo.UserT" name="t,t1">
<property name="name" value="温嘉璐"/>
</bean>
5.3、import
这个import,一般用于团队开发使用,它可以将多个配置文件,导入合并为一个
假设,现在项目中有多个人开发,这三个人负责不同的类开发,不同的类需要注册在不同的bean中,
我们可以利用import将所有人的beans.xml合并为一个总的!
-
张三
-
李四
-
王五
-
applicationContext.xml
<import resource="beans1.xml"/> <import resource="beans.xml"/>
使用的时候,直接使用总的配置就好了
6、依赖注入
6.1、构造器注入
-
使用无参构造方法创建对象 默认
<bean id="user" class="com.wen.pojo.User"> <property name="name" value="温嘉璐"/> </bean>
-
使用有参构造方法创建对象
-
下标赋值
<bean id="user" class="com.wen.pojo.User"> <constructor-arg index="0" value="温嘉璐"/> </bean>
-
类型
<bean id="user" class="com.wen.pojo.User"> <!--第二种通过类型创建,不建议使用--> <constructor-arg type="java.lang.String" value="温嘉璐"/> </bean>
-
参数名
<!--第三种,直接通过参数名--> <bean id="user" class="com.wen.pojo.User"> <constructor-arg name="name" value="温嘉璐"/> </bean>
-
6.2、Set方式注入【重点】
-
依赖注入:Set注入!
- 依赖:bean对象的创建依赖于容器!
- 注入:bean对象中的所有属性,有容器注入
-
Student类
@Data public class Student { private String name; private Address address; private String[] books; private List<String> hobbys; private Map<String, String> card; private Set<String> games; private Properties info; private String wife; }
-
Address类
@ToString public class Address { @Getter @Setter private String address; }
-
普通值注入
<property name="name" value="温嘉璐"/>
-
引用类型注入
<bean id="address" class="com.wen.pojo.Address"> <property name="address" value="黑龙江省大庆市x"/> </bean> <bean id="student" class="com.wen.pojo.Student"> <property name="address" ref="address"/> </bean>
-
数组
<bean id="student" class="com.wen.pojo.Student"> <property name="books"> <array> <value>红楼梦</value> <value>西游记</value> <value>三国演义</value> <value>水浒传</value> </array> </property> </bean>
-
List
<bean id="student" class="com.wen.pojo.Student"> <property name="hobbys"> <list> <value>听歌</value> <value>敲代码</value> <value>看电影</value> </list> </property> </bean>
-
Map
<bean id="student" class="com.wen.pojo.Student"> <property name="card"> <map> <entry key="身份证" value="454542543437347"/> <entry key="银行卡" value="1451221454512212"/> </map> </property> </bean>
-
Set
<bean id="student" class="com.wen.pojo.Student"> <property name="games"> <set> <value>LOL</value> <value>Cf</value> </set> </property> </bean>
-
null
<bean id="student" class="com.wen.pojo.Student"> <property name="wife"> <null/> </property> </bean>
-
properties
<bean id="student" class="com.wen.pojo.Student"> <property name="info"> <props> <prop key="学号">0306190266</prop> <prop key="性别">男</prop> </props> </property> </bean>
6.3、扩展方式注入
我们可以使用p命名空间和c命名空间进行注入
-
p命名空间
-
先引入p命名空间
xmlns:p="http://www.springframework.org/schema/p"
-
<!--p 命名空间注入,可以注入属性的值:property--> <bean id="user" class="com.wen.pojo.User" p:name="温嘉璐" p:age="18"/>
-
-
c命名空间
-
先引入c命名空间
xmlns:c="http://www.springframework.org/schema/c"
-
<!--c命名空间注入,通过构造器注入:construct-args--> <bean id="user2" class="com.wen.pojo.User" c:name="温嘉璐" c:age="18"/>
-
测试:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:beans.xml")
public class MyTest {
@Autowired
private User user2;
@Autowired
private User user;
@Test
public void test() {
System.out.println(user2);
}
@Test
public void test1() {
System.out.println(user);
}
}
注意点:p命名和c命名不能直接使用需要导入xml约束
6.4、bean作用域
Scope | Description |
---|---|
singleton | (默认)将每个 Spring IoC 容器的单个 bean 定义范围限定为单个对象实例。 |
prototype | 将单个 bean 定义的作用域限定为任意数量的对象实例。 |
request | 将单个 bean 定义的范围限定为单个 HTTP 请求的生命周期。也就是说,每个 HTTP 请求都有一个在单个 bean 定义后面创建的 bean 实例。仅在可感知网络的 Spring ApplicationContext 中有效。 |
session | 将单个 bean 定义的范围限定为 HTTP Session 的生命周期。仅在可感知网络的 Spring ApplicationContext 上下文中有效。 |
application | 将单个 bean 定义的范围限定为ServletContext 的生命周期。仅在可感知网络的 Spring ApplicationContext 上下文中有效。 |
websocket | 将单个 bean 定义的范围限定为WebSocket 的生命周期。仅在可感知网络的 Spring ApplicationContext 上下文中有效。 |
-
单例模式 (Spring默认机制)
<bean id="user" class="com.wen.pojo.User" p:name="温嘉璐" p:age="18" scope="singleton"/>
-
原型模式:每次从容器中get的时候,都会产生一个新的对象
<bean id="user" class="com.wen.pojo.User" p:name="温嘉璐" p:age="18" scope="prototype"/>
-
其余的request、session、application、这些只能在web开发中使用到!
测试:单例和原型
单例模式下返回true
原型模式下返回false
7、Bean的自动装配
- 自动装配是Spring满足bean依赖一种方式!
- Spring会在上下文中自动寻找,并自动给bean装配属性
在Spring中有三种装配的方式
- 在xml中显示的配置
- 在java中显示配置
- 隐式的自动装配bean【重要】
7.1、测试
环境搭建:一个人有两个宠物!
Dog类:
/**
* @author 20212
*/
public class Dog {
public void shout(){
System.out.println("汪汪汪....");
}
}
Cat类:
/**
* @author 20212
*/
public class Cat {
public void shout(){
System.out.println("喵喵喵....");
}
}
People类
@Data
public class People {
private Dog dog;
private Cat cat;
private String name;
}
配置bean
<bean id="cat" class="com.wen.pojo.Cat"></bean>
<bean id="dog" class="com.wen.pojo.Dog"></bean>
<bean id="people" class="com.wen.pojo.People">
<property name="name" value="温嘉璐"/>
<property name="cat" ref="cat"/>
<property name="dog" ref="dog"/>
</bean>
测试类
@Test
public void test1() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
People people = context.getBean("people", People.class);
people.getDog().shout();
people.getCat().shout();
}
7.2、byName自动装配
<bean id="cat" class="com.wen.pojo.Cat"></bean>
<bean id="dog" class="com.wen.pojo.Dog"></bean>
<!--
byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的 bean id!
-->
<bean id="people" class="com.wen.pojo.People" autowire="byName">
<property name="name" value="温嘉璐"/>
</bean>
7.2、byType自动装配
<bean class="com.wen.pojo.Cat"></bean>
<bean class="com.wen.pojo.Dog"></bean>
<!--
byName:会自动在容器上下文中查找,和自己对象属性类型相同的 bean
-->
<bean id="people" class="com.wen.pojo.People" autowire="byType">
<property name="name" value="温嘉璐"/>
</bean>
小结:
- byname的是偶,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致
<bean id="cat" class="com.wen.pojo.Cat"></bean>
<bean id="dog" class="com.wen.pojo.Dog"></bean>
<!--
byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的 bean id!
-->
<bean id="people" class="com.wen.pojo.People" autowire="byName">
<property name="name" value="温嘉璐"/>
</bean>
7.2、byType自动装配
<bean class="com.wen.pojo.Cat"></bean>
<bean class="com.wen.pojo.Dog"></bean>
<!--
byName:会自动在容器上下文中查找,和自己对象属性类型相同的 bean
-->
<bean id="people" class="com.wen.pojo.People" autowire="byType">
<property name="name" value="温嘉璐"/>
</bean>
小结:
- byname的时候,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致
- bytype的时候,需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致