1、Spring

1.1、简介

  • 2002年,首次推出了Spring的雏形:interface21框架
  • 2004年3月24日,Spring框架以interface21框架为基础,经过重新设计,发布了1.0正式版本。
  • Rod Johnson,Spring框架的创始人,同时也是SpringSource的联合创始人。他是悉尼大学的博士,然而他的专业不是计算机,而是音乐学。
  • Spring是面向切面编程(AOP)和控制反转(IoC)的容器框架。
  • Spring:使现有的技术更加容易使用,它本身是一个大杂烩,整合了现有的技术框架
  • SSH:Struct2 + Spring + Hibernate
  • SSM:SpringMVC + Spring + Mybatis

依赖

  1. <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
  2. <dependency>
  3. <groupId>org.springframework</groupId>
  4. <artifactId>spring-webmvc</artifactId>
  5. <version>5.3.19</version>
  6. </dependency>

1.2、优点

  • Spring是一个开源的免费的框架(容器)!
  • Spring是一个轻量级的、非入侵式的框架!
  • 控制反转(IOC),面向切面编程(AOP)!
  • 支持事务的处理,对框架整合的支持!

总结一句话:Spring就是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架!

1.3、拓展

现代化的Java开发!说白就是基于Spring的开发!

  • Spring Boot
    • 一个快速开发的脚手架。
    • 基于SpringBoot可以快速的开发单个微服务。
    • 约定大于配置。
  • Spring Cloud
    • SpringCloud是基于SpringBoot实现的。

因为现在大多数公司都在使用SpringBoot进行快速开发,学习SpringBoot的前提,需要完全掌握Spring及SpringMVC!承上启下的作用!

弊端:发展了太久之后,违背了原来的理念!配置十分繁琐,人称:“配置地狱!”

2、IOC理论推导

  1. UserDao接口
    1. public interface UserDao {
    2. void getUser();
    3. }
  1. UserDaoImpl实体类
    1. public class UserDaoImpl implements UserDao{
    2. public void getUser(){
    3. System.out.println("默认获取UserDaoImpl的数据");
    4. }
    5. }
  1. UserService业务接口

    1. public class UserServiceImpl implements UserService {
    2. private UserDao userDao;
    3. public void getUser() {
    4. userDao.getUser();
    5. }
    6. }
  1. UserServiceImpl业务实现
    1. public interface UserService {
    2. void getUser();
    3. }

在我们之前的业务中,用户的需求可能会影响我们原来的代码,我们需要根据用户的需求去修改源代码!如果程序代码量十分大,修改一次的成本代价十分昂贵!

我们在UserService业务接口中使用一个Set接口实现

  1. public class UserServiceImpl implements UserService {
  2. private UserDao userDao;
  3. // 利用set进行动态实现值的注入!
  4. public void setUserDao(UserDao userDao) {
  5. this.userDao = userDao;
  6. }
  7. public void getUser() {
  8. userDao.getUser();
  9. }
  10. }

测试

  1. public class MyTest {
  2. public static void main(String[] args) {
  3. // 用户实际调用的是业务层,dao层他们不需要接触
  4. UserServiceImpl userService = new UserServiceImpl();
  5. userService.setUserDao(new UserDaoMysqlImpl()); // 通过new 不同的实现类达到调不同的方法
  6. userService.getUser();
  7. }
  8. }
  • 之前,程序是主动创建对象!控制权在程序猿手上!
  • 使用了set注入后,程序不再具有主动性,而是变成了被动的接收对象!

这种思想,从本质上解决了问题,我们程序猿不用再去管理对象的创建了。系统的耦合性大大降低~,可以更加专注的在业务的实现上!这是IOC的原型!

3、HelloSpring

  1. 创建一个maven项目,编写实体类

    1. public class Hello {
    2. private String str;
    3. public String getStr() {
    4. return str;
    5. }
    6. public void setStr(String str) {
    7. this.str = str;
    8. }
    9. @Override
    10. public String toString() {
    11. return "Hello{" +
    12. "str='" + str + '\'' +
    13. '}';
    14. }
    15. }
  1. 编写xml配置文件 ```xml <?xml version=”1.0” encoding=”UTF-8”?>
  1. <!--使用Spring来创建对象,在Spring这些都称为Bean
  2. 类型 变量名 = new 类型();
  3. Hello hello = new Hello();
  4. id = 变量名
  5. class = new的对象
  6. property 相当于给对象中的属性设置一个值!
  7. -->
  8. <bean id="hello" class="com.shuai.pojo.Hello">
  9. <property name="str" value="Spring"/>
  10. </bean>

  1. 3. 测试
  2. ```java
  3. public class MyTest {
  4. @Test
  5. public void test(){
  6. // 获取Spring的上下文对象!(获取ApplicationContext:拿到Spring的容器)
  7. ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
  8. // 我们的对象现在都在Spring中的管理了,我们要使用,直接去里面取出来就可以!
  9. Hello hello = (Hello) context.getBean("hello");
  10. System.out.println(hello.toString());
  11. }
  12. }

思考问题?

  • Hello对象是谁创建的?
    Hello对象是由Spring创建的。
  • Hello对象的属性是怎么设置的?
    Hello对象的属性是由Spring容器设置的。

这个过程就叫控制反转:

控制:谁来控制对象的创建,传统应用程序的对象是由程序本身控制创建的,使用Spring后,对象是由Spring来创建的。

反转:程序本身不创建对象,而变成被动的接收对象。

依赖注入:就是利用set方法来进行注入的。

IOC是一种编程思想,由主动的编程变成被动的接收。

可以通过new ClassPathXmlApplicationContext去浏览一下底层源码。

OK,到了现在,我们彻底不用在程序中去改动了,要实现不同的操作,只需要在xml配置文件中进行修改,所谓的IOC,一句话搞定:对象由Spring来创建,管理,装配!

4、IOC创建对象的方法

  1. 使用无参构造创建对象,默认!
  2. 假设我们要使用有参构造创建对象。
    1. 下标赋值
      1. <!--第一种,下标赋值!-->
      2. <bean id="user" class="com.shuai.pojo.User">
      3. <constructor-arg index="0" value="无敌最俊朗"/>
      4. </bean>
  1. 类型
    1. <!--第二种方式:通过类型创建,不建议使用-->
    2. <bean id="user" class="com.shuai.pojo.User">
    3. <constructor-arg type="java.lang.String" value="shaoshuai"/>
    4. </bean>
  1. 参数名
    1. <!--第三种方式:直接通过参数名来设置-->
    2. <bean id="user" class="com.shuai.pojo.User">
    3. <constructor-arg name="name" value="帅帅"/>
    4. </bean>

    总结:在配置文件加载的时候,容器中管理的对象就已经初始化了

5、Spring配置

5.1、别名

  1. <!--别名,如果添加了别名,我们就可以是别名获取到这个对象-->
  2. <alias name="userT" alias="userNew"/>

5.2、Bean的配置

  1. <!--
  2. id : bean 的唯一标识符,也就相当于我们学的对象名
  3. class : bean 对象所对应的全限定名: 包名 + 类型
  4. name : 也是别名,而且name 可以同时取多个别名
  5. -->
  6. <bean id="userT" class="com.shuai.pojo.UserT" name="user2 u2,u3;u4">
  7. <property name="name" value="每天努力一点点"/>
  8. </bean>

5.3 import

这个import。一般用于团队开发使用,它可以将多个配置文件,导入合并为一个。

假设,现在项目中有多个人开发,这三个人负责不同的类开发,不同的类需要注册在不同的bean中,我们可以利用import将所有人的beans.xml合并为一个总的!

  • 张三
  • 李四
  • 王五
  • applicationContext.xml
  1. <import resource="bean.xml"/>
  2. <import resource="bean2.xml"/>
  3. <import resource="bean3.xml"/>

使用的时候,直接使用总的配置就可以了

6、依赖注入

6.1、构造器注入

前面已经说过了

6.2、Set方式注入【重点】

  • 依赖注入:Set注入!
    • 依赖:bean对象的创建依赖于容器!
    • 注入:bean对象中的所有属性,有容器来注入!

【环境搭建】

  1. 复杂类型
    1. public class Student {
    2. private String name;
    3. private Address address;
    4. private String[] books;
    5. private List<String> hobbys;
    6. private Map<String,String> card;
    7. private Set<String> games;
    8. private String wife;
    9. private Properties info;
    10. }
  1. 真实测试对象 ```xml

  1. <!--第二种,Bean注入,ref-->
  2. <property name="address" ref="address"/>
  3. <!--数组-->
  4. <property name="books">
  5. <array>
  6. <value>红楼梦</value>
  7. <value>水浒传</value>
  8. <value>三国演义</value>
  9. <value>西游记</value>
  10. </array>
  11. </property>
  12. <!--List-->
  13. <property name="hobbys">
  14. <list>
  15. <value>听歌</value>
  16. <value>健身</value>
  17. <value>妹子</value>
  18. <value>看电影</value>
  19. </list>
  20. </property>
  21. <!--Map-->
  22. <property name="card">
  23. <map>
  24. <entry key="学号" value="200054070459"/>
  25. <entry key="手机号" value="110"/>
  26. </map>
  27. </property>
  28. <!--Set-->
  29. <property name="games">
  30. <set>
  31. <value>王者荣耀</value>
  32. <value>天天酷跑</value>
  33. <value>穿越火线</value>
  34. </set>
  35. </property>
  36. <!--null-->
  37. <property name="wife">
  38. <null/>
  39. </property>
  40. <!--properties-->
  41. <property name="info">
  42. <props>
  43. <prop key="driver">mysql</prop>
  44. <prop key="url"></prop>
  45. <prop key="username">root</prop>
  46. <prop key="password">123456</prop>
  47. </props>
  48. </property>

  1. <a name="1132543b"></a>
  2. ### 6.3、拓展方式注入
  3. 我们可以使用p命名空间和c命名空间进行注入<br />使用:
  4. ```xml
  5. <?xml version="1.0" encoding="UTF-8"?>
  6. <beans xmlns="http://www.springframework.org/schema/beans"
  7. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  8. xmlns:p="http://www.springframework.org/schema/p"
  9. xmlns:c="http://www.springframework.org/schema/c"
  10. xsi:schemaLocation="http://www.springframework.org/schema/beans
  11. https://www.springframework.org/schema/beans/spring-beans.xsd">
  12. <!--p命名空间注入,可以直接注入属性的值:property-->
  13. <bean id="user" class="com.shuai.pojo.User" p:name="帅哥" p:age="18"/>
  14. <!--c命名空间注入, 通过构造器注入:construct-args-->
  15. <bean id="user2" class="com.shuai.pojo.User" c:age="21" c:name="少帅"/>
  16. </beans>

注意点:p命名和c命名空间不能直接使用,需要导入xml约束!

  1. xmlns:p="http://www.springframework.org/schema/p"
  2. xmlns:c="http://www.springframework.org/schema/c"

6.4、Bean的作用域

单例模式(Spring默认机制)

  1. <bean id="user2" class="com.shuai.pojo.User" c:name="少帅" c:age="22" scope="singleton"/>

原型模式:每次从容器中get的时候,都会产生一个新对象!

  1. <bean id="user2" class="com.shuai.pojo.User" c:name="小帅" c:age="22" scope="prototype"/>

其余的request、session、application、这些只能在web开发中使用到!

7、Bean的自动装配

  • 自动装配是Spring满足bean依赖的一种方式!
  • Spring会在上下文中自动寻找,并自动给bean装配属性!

在Spring中有三种装配的方式

  1. 在xml中显示的配置
  2. 在java中显示配置
  3. 隐式 的自动装配bean 【重要】

7.1、测试

7.2、ByName自动装配

  1. <bean id="cat" class="com.shuai.pojo.Cat"/>
  2. <bean id="dog" class="com.shuai.pojo.Dog"/>
  3. <!--
  4. byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的bean id!
  5. -->
  6. <bean id="people" class="com.shuai.pojo.People" autowire="byName">
  7. <property name="name" value="少帅"/>
  8. </bean>

7.3、ByType自动装配

  1. <bean id="cat" class="com.shuai.pojo.Cat"/>
  2. <bean id="dog" class="com.shuai.pojo.Dog"/>
  3. <!--
  4. byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的bean后面的id=的值!
  5. byType:会自动在容器上下文中查找,和自己对象属性类型相同的bean!
  6. -->
  7. <bean id="people" class="com.shuai.pojo.People" autowire="byType">
  8. <property name="name" value="少帅"/>
  9. </bean>

小结:

  • ByName的时候,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致!
  • ByType的时候,需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致!

7.4、使用注解实现自动装配

要使用注解须知:

  1. 导入约束:context约束
  2. 配置注解的支持: context:annotation-config/ 【重点】

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xmlns:context="http://www.springframework.org/schema/context"
    5. xsi:schemaLocation="http://www.springframework.org/schema/beans
    6. https://www.springframework.org/schema/beans/spring-beans.xsd
    7. http://www.springframework.org/schema/context
    8. https://www.springframework.org/schema/context/spring-context.xsd">
    9. <!--开启注解的支持 -->
    10. <context:annotation-config/>
    11. </beans>

@Autowired

直接在属性上使用即可!也可以在set方法上使用!

使用Autowired我们就可以不用编写set方法了,前提是你这个自动配置的属性在IOC(Spring)容器中存在,且符合名字ByName!

科普:

  1. @Nullable 字段标记了了这个注解,说明这个字段可以为null;

测试代码

  1. public class People {
  2. //如果显式定义了Autowired的required属性为false,说明这个对象可以为null,否则不允许为空
  3. @Autowired(required = false)
  4. private Cat cat;
  5. @Autowired
  6. private Dog dog;
  7. private String name;
  8. }

如果@Autowired自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired】完成的时候,我们可以使用@Qualifier(value = “xxx”)去配置@Autowired的使用,指定一个唯一的bean对象注入!

  1. public class People {
  2. @Autowired
  3. @Qualifier(value = "cat111")
  4. private Cat cat;
  5. @Autowired
  6. @Qualifier(value = "dog222")
  7. private Dog dog;
  8. private String name;
  9. }

@Resource注解

  1. public class People {
  2. @Resource(name = "cat111")
  3. private Cat cat;
  4. @Resource
  5. private Dog dog;
  6. private String name;
  7. }

小结:

@Resource和@Autowired的区别:

  • 都是用来自动装配的,都可以放在属性字段上
  • @Autowired通过byType的方式实现,而且必须要求这个对象存在!【常用】
  • @Resource默认通过byName的方式实现,如果找不到名字,则通过byType实现!如果两个都找不到的情况下,就报错!【常用】
  • 执行顺序不同:@Autowired通过byType的方式实现。