1、什么是Spring

Spring是分层的Java EE的一个轻量级开源框架,它以IoC和AOP为内核,提供了表现层Spring MVC和持久层Spring JDBC以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的Java EE企业应用开源框架。

  • IoC:Inversion of Control(控制反转)
  • AOP:Aspect Oriented Programming(面向切面编程)
  1. <dependency>
  2. <groupId>org.springframework</groupId>
  3. <artifactId>spring-webmvc</artifactId>
  4. <version>5.2.0.RELEASE</version>
  5. </dependency>

2、构成

1219227-20170930225010356-45057485.gif

3、IOC理论推导

  1. UserDao接口

  2. UserDaoImpl实现类

  3. UserService业务接口

  4. UserServiceImpl业务实现类

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

我们使用一个Set接口实现

  1. private UserDao dao;
  2. //利用set实现动态值注入
  3. public void setUserDao(UserDao dao) {
  4. this.dao = dao;
  5. }
  • 之前,程序是主动创建对象,控制权在程序员手上。
  • 使用了set注入后,程序不再具有主动性,而是变成了被动的接收对象!

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

4、IOC本质

控制反转IOC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IOC的一种方法,也有人认为DI只是IOC的另一种说法。没有IOC的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。
20200702151016907.png

采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。

控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。

5、HelloSpring

创建一个实体类 Hello.java

  1. package pojo;
  2. public class Hello {
  3. private String str;
  4. public String getStr() {
  5. return str;
  6. }
  7. public void setStr(String str) {
  8. this.str = str;
  9. }
  10. @Override
  11. public String toString() {
  12. return "Hello{" +
  13. "str='" + str + '\'' +
  14. '}';
  15. }
  16. }

编写配置文件 beans.xml
注意,在property里面:
ref:引用Spring容器中创建好的对象
value:具体的值,基本数据类型!

  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. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. https://www.springframework.org/schema/beans/spring-beans.xsd">
  6. <!-- 使用Spring来创建对象,在Spring中,这些都是Beans-->
  7. <bean id="hello" class="pojo.Hello">
  8. <property name="str" value="Spring"/>
  9. </bean>
  10. </beans>

测试

@Test
    public void test(){
        //获取Spring的上下文对象
        ClassPathXmlApplicationContext contex = new ClassPathXmlApplicationContext("beans.xml");
        //我们的对象现在都在Spring中的管理了,我们要使用,直接去里面取出来就可以了
        Hello hello = (Hello) contex.getBean("hello");
        System.out.println(hello.getStr());
    }

控制台输出
Snipaste_2021-07-17_16-59-21.jpg

6、IOC创建对象的方式

  1. 使用无参构造,默认!!!
  2. 假设我们要使用有参构造创建对象

01- 下标赋值

<!--使用下标赋值-->
    <bean id="user" class="pojo.User">
        <constructor-arg index="0" value="刘老师"/>
    </bean>

02-通过类型创建(不建议使用)

  <!--通过类型创建(不建议使用)-->
    <bean id="user" class="pojo.User">
        <constructor-arg type="java.lang.String" value="刘老师"/>
    </bean>

03-通过参数名来设置

 <!--直接通过参数名来设置-->
    <bean id="user" class="pojo.User">
        <constructor-arg name="name" value="牛老师"/>
    </bean>

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

7、Spring配置说明

01-别名(alias)

    <!--直接通过参数名来设置-->
    <bean id="user" class="pojo.User">
        <constructor-arg name="name" value="牛老师"/>
    </bean>

    <!--给user取个别名“user2”-->
    <alias name="user" alias="user2"/>

02-Bean的配置

  • id:bean的唯一标识符,也就是我们所学的对象名
  • class:bean对象所对应的全限命名
  • name:也是别名,而且更高级,可以同时取多个别名
      <bean id="user" class="pojo.User" name="我是别名,我也是别名">
          <constructor-arg name="name" value="牛老师"/>
      </bean>
    

03-import

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

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

  • 张三
  • 李四
  • 王五
  • applicationContext.xml(总的)
    <import resource="beans1.xml"/>
    <import resource="beans2.xml"/>
    <import resource="beans3.xml"/>
    
    使用的时候,直接用总的配置就可以了

8、DI依赖注入

01-构造器注入

前面已经说过了

02-Set注入

【环境搭建】

复杂类型

package pojp;
import lombok.Data;
@Data
public class Address {
    private Address address;
}

真实测试对象

package pojp;
import lombok.Data;
import java.util.*;
@Data
public class Student {
    private String name;
    private Address address;
    private String[] books;
    private List<String> hobbies;
    private Map<String, String> card;
    private Set<String> games;
    private String wife;
    private Properties properties;
}

beans.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 http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="student" class="pojp.Student">
        <!--第一种,普通值注入,使用value-->
       <property name="name" value="老王"/>
    </bean>
</beans>

测试

 @Test
    public void test(){
        ApplicationContext context=new ClassPathXmlApplicationContext("beans.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 http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="address" class="pojp.Address">
        <property name="address" value="江西省"/><!--设置值-->
    </bean>
    <bean id="student" class="pojp.Student">
        <!--第一种,普通值注入,value-->
       <property name="name" value="老王"/>

        <!--第二种,Bean注入,ref-->
        <property name="address" ref="address"/>

        <!--第三种,数组注入,ref-->
        <property name="books">
            <array>
                <value>红楼梦</value>
                <value>三国演义</value>
                <value>水浒传</value>
                <value>西游记</value>
            </array>
        </property>

        <!--第四种,List注入-->
        <property name="hobbies">
            <list>
                <value>打篮球</value>
                <value>敲代码</value>
            </list>
        </property>

        <!--第五种,Map注入-->
        <property name="card">
            <map>
                <entry key="身份证" value="123"/>
                <entry key="银行卡" value="456"/>
            </map>
        </property>

        <!--第六种,Set注入-->
        <property name="games">
            <set>
                <value>LOL</value>
                <value>DNF</value>
                <value>CSGO</value>
            </set>
        </property>

        <!--第七种,null注入-->
        <property name="wife">
            <null/>
        </property>

        <!--第八种,Properties注入-->
        <property name="properties">
            <props>
                <prop key="name">老帅比</prop>
                <prop key="password">1234</prop>
            </props>
        </property>
    </bean>
</beans>

03-拓展注入

我们可以使用p命名空间和c命名空间注入
需要导入约束:
p命名空间—>xmlns:p=”http://www.springframework.org/schema/p
c命名空间—>xmlns:c=”http://www.springframework.org/schema/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 http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--p命名空间注入,可以直接注入属性的值:property-->
    <bean id="user" class="pojp.User" p:name="刘某" p:password="123"/>

    <!--c命名空间注入,通过构造器注入:construct-args-->
    <bean id="user2" class="pojp.User" c:name="徐某" c:password="456"/>
</beans>

04-Bean的作用域

1、单例模式(Spring默认机制)
一个类只实例化一次,通过方法得到的对象,即使对象的名字不同,本质还是同一个

<bean id="" class="" scope="singleton"/>


2、多例模式:每次从容器中get时,都会产生一个新对象,适用于多线程

<bean id="" class="" scope="prototype"/>

3、其余的request,session,application,只能在web开发中使用到,表示对象的生存周期

9、Bean的自动装配

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

在Spring中有三种装配的方式

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

01-环境搭建

Dog.java

package pojo;
public class Dog {
    public void shout(){
        System.out.println("汪汪汪!");
    }
}

Cat.java

package pojo;
public class Cat {
    public void shout(){
        System.out.println("喵喵喵!");
    }
}

People.java

package pojo;
import lombok.Data;
@Data
public class People {
    private Cat cat;
    private Dog dog;
    private String name;
}

02-ByName自动装配

byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的beanid!!!

<?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="cat" class="pojo.Cat"/>
    <bean id="dog" class="pojo.Dog"/>
    <bean id="people" class="pojo.People" autowire="byName">
        <property name="name" value="老帅比呀"/>
     </bean>
</beans>

03-ByType自动装配

byType:会自动在容器上下文中查找,和自己对象属性类型相同的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">
    <bean id="cat" class="pojo.Cat"/>
    <bean id="dog" class="pojo.Dog"/>
    <bean id="people" class="pojo.People" autowire="byType">
        <property name="name" value="老帅比呀"/>
     </bean>
</beans>

小结:

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