Spring入门学习二:控制反转IOC

控制反转IOC

Spring环境搭建

本章节将在IDEA中开发,在Eclipse(STS)中创建项目基本是一样的,无此经验者,可以自行百度。

创建一个maven父项目

file-new-project
在这里插入图片描述

在这里插入图片描述

在父项目中导入jar包

我们选择已maven的方式导入,maven仓库地址:https://mvnrepository.com/。这里我们直接导入spring-webmvc的jar,它会自动将一些其他依赖的jar包导入,比如core,context,AOP,beans,expression,等。如果IDEA没有自动导包,则右击项目执行一下maven的Reload Project。关于Eclipse关于lombok的安装可参考https://blog.youkuaiyun.com/weixin_41549354/article/details/107801940,IDEA的安装请自行百度,方法非常简单,这里就不赘述了,如果不想装,就写上getter,setter,等方法。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com</groupId>
    <artifactId>SpringFather</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.2.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.10</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>
</project>
创建一个module

右击SpringFather-new-module,点击next

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bpA2umz5-1596901471078)(D:\我的文档\Pictures\31.PNG)]

项目截图

在这里插入图片描述

HelloSpring的编写

重点:IOC的思想

在使用Spring之前,我们先来稍微了解一些IOC是个什么东西。在未使用Spring的Dao-Service-Controller开发中,用户的需求可能会影响我们原始的代码,因为我们会根据用户的需求去修改源代码。

举个例子,我们在dao层有一个UserDao的接口,然后这个UserDao有好多个实现类,然后在service里面我们直接调用了UserDao接口的实现类对象,类似的直接在UserServiceImpl写:

private UserDao userDao = new UserDaoImpl1();

然后在控制器里面调用UserService对象(不接触我们的Dao层,由UserService的对象去调用UserDao的对象),但此时问题就来了,我们需要用不同UserDaoImpl的对象时,就要修改UserServiceImpl里面的代码。十分的麻烦。业务调用的主动权在Service里面写死了,

我们修改上面的例子。

修改代码为

private UserDao userDao;
public void setUserDao(User userDao) {
    this.userDao = userDao;
}

利用Set进行动态实现值的注入。程序不再具有主动性了,而是被动的在控制器里面接收UserDao的对象。这种注入思想,系统耦合性大大的降低,能够更加专注于业务的实现,主动权交给Controller,这就是IOC的原型!Spring的底层也都是利用了这种思想。

在没有IOC的程序中,对象的创建与对象间的依赖关系完全在硬编码中,对象的创建由程序自己控制,控制反转之后将对象的创建转移给第三方Spring容器,在程序需要某个对象的地方,这个SpringIOC容器将根据我们的需求自动注入所依赖的对象,程序获取依赖对象的方式反转了。

IOC是Spring框架的核心内容,在实际开发中,我们可以通过XML配置,也可以通过注解,甚至可以零配置实现IOC。我们写完POJO,接口等代码之后,通过XML配置,或者注解,然后SpringIOC容器去读取配置文件或者解析注解,从而将这些类的对象组织存入到IOC容器中,程序要用的时候,IOC容器根据需求自动注入所需的对象

IOC的实现方法是依赖注入DI(denpendency Injection)

实体类

在src/main/java文件夹下,新建一个com.pojo包,然后新建Hello.java

package com.pojo;

import lombok.Data;

@Data
public class Hello {
    private String name;
}
Spring配置文件

在资源文件夹下面新建一个beans.xml。可以参考https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#spring-core拷贝官方网站的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">

    <!--  
    使用Spring来创建对象,在Spring这些都称为bean  
    该id属性是标识单个bean定义的字符串。
    该class属性定义Bean的类型,并使用完全限定的类名。
    下面的代码就相当于,
    Hello hello = new Hello();
    hello.setName("Spring");
    -->
    <bean id="hello" class="com.pojo.Hello">
        <!-- 
         ref:引用Spring中已经管理好的对象
         value:基本数据类型
         -->
        <property name="name" value="Spring"/>
    </bean>
</beans>
实例化容器

提供给ApplicationContext构造函数的一个或多个位置路径是资源字符串,可让容器从各种外部资源(例如本地文件系统,Java等)中加载配置元数据CLASSPATH。在test文件夹下面新建一个包com。然后建一个HelloTest.java

package com;

import com.pojo.Hello;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class HelloTest {

    @Test
    public void testHello() {
        /**
         * 官方示例
         * ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
         * 作用:获取Spring的上下文对象,即Spring的容器,我们的对象都在Spring中组织好了,要用直接取就行了
         */
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        /**
         * 从Spring容器里面取出对象,方法getBean(在beans.xml中定义的id)
         * 注意id的大小写
         */
        Object hello = (Hello)applicationContext.getBean("hello");
        System.out.println(hello.toString());
    }
}

测试

在上述例子中,Hello对象已经不是通过我们去手动new出来了,而是在Spring的配置文件里面进行声明。SpringIOC容器就帮我们管理好了,我们要用的时候:

直接通过 ClassPathXmlApplicationContext(“beans.xml”)读取配置文件创建一个Spring的上下文对象

然后通过这个对象的getBean方法取出IOC管理的对象。自此就实现了Hello的控制反转,它的底层还是用的set方法来进行注入

Hello(name=Spring)

Process finished with exit code 0

简单点说说一下IOC,就好比我们要炒菜请客,已经买好了食材(类),然后请一个第三方餐厅(IOC)来帮我们做,把我们的食材跟列出来的菜单交给这个餐厅就好了(进行配置)并且把菜做好了(Singleton),等待客人过来吃饭。客人来了之后,要吃什么菜,直接根据菜单去点菜就行(使用IOC的对象)

IOC创建对象的方式

基于无参构造的注入

我们在Hello.java中加上无参构造方法。

package com.pojo;

import lombok.Data;

@Data
public class Hello {
    private String name;
    
    public Hello() {
        System.out.println("调用了无参构造方法");
    }
}

然后进行测试

调用了无参构造方法
Hello(name=Spring)

Process finished with exit code 0
基于有参构造的注入

我们先删除Hello的无参构造,然后写上一个有参构造,干掉默认的无参构造

注意:如果这时候,直接执行的话,程序会报错 No default constructor found;。即使我们修改测试类,不调用无参构造创建对象的方式,程序仍然会报错,因为SpringIOC容器在初始化的时候,会自动创建好我们注册的类的对象(默认在Singleton的情况下会创建)

package com.pojo;

import lombok.Data;

@Data
public class Hello {
    private String name;

    public Hello(String name) {
        System.out.println("调用了有参构造方法");
        this.name = name;
    }
}

官方提供了三种方式进行配置。

第一种:

在配置文件里面加上代码:

<?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">

    <!--
    使用Spring来创建对象,在Spring这些都称为bean
    该id属性是标识单个bean定义的字符串。
    该class属性定义Bean的类型,并使用完全限定的类名。
    下面的代码就相当于
    Hello hello = new Hello();
    hello.setName("Spring");
    -->
<!--    <bean id="hello" class="com.pojo.Hello">-->
<!--        &lt;!&ndash;-->
<!--         ref:引用Spring中已经管理好的对象-->
<!--         value:基本数据类型-->
<!--         &ndash;&gt;-->
<!--        <property name="name" value="Spring"/>-->
<!--    </bean>-->

    <!--
    Hello hello = new Hello("有参构造,第一种方式:下标赋值")
    -->
    <bean id="hello" class="com.pojo.Hello">
        <constructor-arg index="0" value="有参构造,第一种方式:下标赋值"/>
    </bean>
</beans>

测试:

调用了有参构造方法
Hello(name=有参构造,第一种方式:下标赋值)

Process finished with exit code 0
第二种

先在配置文件里面注释掉刚才的代码,重新加上

    <!--
    Hello hello1 = new Hello("有参构造,第二种方式:类型赋值")
    不建议使用
    -->
    <bean id="hello" class="com.pojo.Hello">
        <constructor-arg type="java.lang.String" value="有参构造,第二种方式:类型赋值"/>
    </bean>
调用了有参构造方法
Hello(name=有参构造,第二种方式:类型赋值)

Process finished with exit code 0
第三种

先在配置文件里面注释掉刚才的代码,重新加上

    <!--
    推荐使用
    有参构造,第三种方式:参数名赋值
    -->
    <bean id="hello1" class="com.pojo.Hello">
        <constructor-arg name="name" value="有参构造,第三种方式:参数名赋值"/>
    </bean>
调用了有参构造方法
Hello(name=有参构造,第三种方式:参数名赋值)

Process finished with exit code 0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值