狂神说Java --- 记录Spring学习笔记

Posted 小智RE0

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了狂神说Java --- 记录Spring学习笔记相关的知识,希望对你有一定的参考价值。

传送门 ==>B站遇见狂神说—Spring5教程

感谢狂神,学习视频真的是通俗易懂♥♥♥

笔记和练习只是跟着视频整理的;有的知识点并没有整理进来



Spring 官网==>https://spring.io
Spring官方文档==>https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html

本次使用的是Spring Web MVC

<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.3.9</version>
</dependency>

之后还可能用到spring jdbc

<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.3.9</version>
</dependency>

1.Spring概述

Spring是开源免费的轻量级的控制反转(IOC)和面向切面(AOP)的容器框架;支持事务处理.

由7个模块组成,

(Spring Boot) 构建一切,(Sprint Cloud)协调一切,(Spring Cloud Data Flow)连接一切

(Spring Boot)就像脚手架,可实现快速开发单个微服务;而学习它的前提是学习Spring和SpringMVC.


2. 控制反转IOC

IOC理论推导

创建一个空的maven项目,删除src目录;作为父级项目;

还是和之前一样,先去检查maven地址;

pom.xml导包

<dependencies>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.3.9</version>
    </dependency>
    <!--测试使用-->
    <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
</dependency>
</dependencies>

可看到,下载结束后,出现了好几个资源包

创建一个子级maven工程;


就用一个基础的项目构建来说吧;
持久层接口UserDao;

public interface UserDao {
    //查询用户;
    void findUser();
}

持久层实现类UserDaoImpl;

public class UserDaoImpl implements UserDao{
    public void findUser() {
        System.out.println("默认调用的方法");
    }
}

业务层接口UserService;

public interface UserService {
    //查询用户;
    void findUser();
}

业务层接口的实现类UserServiceImpl;

public class UserServiceImpl implements UserService{
    private UserDao userDao=new UserDaoImpl();

    public void findUser() {
      //在业务层调用持久层的方法;
        userDao.findUser();
    }
}

测试调用

@Test
    public void test(){
        UserService userService=new UserServiceImpl();
        userService.findUser();
    }

这时输出

而如果说,这时候又来需求了,持久层新增了一个实现类UsermysqlImpl

public class UserMySqlImpl implements UserDao{
    public void findUser() {
        System.out.println("MySql的方法");
    }
}

那么如果说想要拿到这个需求的实现,就要在业务层的实现类UserServiceImpl中;去更改持久层的实现类改为UserMySqlImpl;

public class UserServiceImpl implements UserService{
    private UserDao userDao=new UserMySqlImpl();

    public void findUser() {
      //在业务层调用持久层的方法;
        userDao.findUser();
    }
}

测试调用,即可

如果说又有一个新的需求,创建了一个新的持久层实现类UserOracleImpl;

public class UserOracleImpl implements UserDao{
    public void findUser() {
        System.out.println("Oracle方式");
    }
}

那么就得去业务层UserServiceImpl中更改;

public class UserServiceImpl implements UserService{
    private UserDao userDao=new UserOracleImpl();

    public void findUser() {
      //在业务层调用持久层的方法;
        userDao.findUser();
    }
}

然后测试调用

在之前的业务中,用户的需求可能会影响原来的代码,就要根据用户的需求更改代码.

要是在UserServiceImpl中用set实现动态修改实现类;

public class UserServiceImpl implements UserService{
     private UserDao userDao;
    //控制反转的原型,在业务层提供动态的用户需求方法;
    //用set实现动态注入值;
     public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
      }

    public void findUser() {
      //在业务层调用持久层的方法;
      userDao.findUser();
    }
}

在测试执行的方法内,只需要调用setUserDao 方法,去更改里面的持久层实现类即可

public class MyTest {
    @Test
    public void test() {
        UserService userService = new UserServiceImpl();
        ((UserServiceImpl) userService).setUserDao(new UserMySqlImpl());
        userService.findUser();
    }
}


每使用set设置之前,程序是需要主动创建对象,控制权在开发者手中,使用了set注入后,程序不再具有主动性,变为被动的接受对象.
开发者不必管理对象的创建,系统耦合性降低,专注于业务的实现.

即控制反转 IOC 的原型.


IOC的本质

控制反转IOC 设计思想,而 DI(依赖注入)是实现IOC的一种方法,
在没有使用IOC的程序,作为面向对象编程的语言,对象的创建和对象间的依赖关系是必须硬编码在程序中,对象的创建由程序自己控制,

控制反转后将对象的创建转移到第三方, 获取依赖对象的方式反转.


3.试试Spring

ok新建一个实体类User;

public class User {
    private String name;

    public User(){
        System.out.println("User类的无参构造");
    }
    
    public User(String name){
        this.name=name;
        System.out.println("User类的有参构造");
    }
    
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\\'' +
                '}';
    }
}

resources目录下创建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-3.0.xsd">

    <!--使用spring 创建对象;就是 bean-->
    <!--这时的id就是变量名;class就是new的对象-->
    <!--property: 可以为对象的属性设置值-->

    <bean id="user" class="com.lzq.pojo.User">
        <property name="name" value="xiaozhi"/>
    </bean>
</beans>

测试

public class Test01 {
    public static void main(String[] args) {
        //获取Spring得上下文对象;
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

        //由于创建对象就是 Spring 中的bean; 获取bean即可获取对象;
        User user = (User) context.getBean("user");

        System.out.println(user.toString());
    }
}

输出:

User类的无参构造
User{name='xiaozhi'}

可以看出,从始至终没有使用new构造方法进行创建User类的对象;
但是实际上在xml配置文件中,已经被Spring创建对象了;且设置了属性name的值;
程序本身不去创建对象,作为了被动的接收对象.

此过程就是控制反转;IOC; 由Spring 创建 管理 装配.

这里使用了set方法来进行注入的;若删除set方法;就无法得到属性name.
设置value是针对于基本数据;

设置实体类显示小叶子图标;


再看看刚才的UserDao,实际上,根据需要就可以直接在配置文件修改即可.

ref: 会引用 在Spring中设置创建的对象


3.1 IOC创建对象的方式

刚在在测执行时;注意到,输出有调用到无参构造方法;

那么如果将User类的无参构造方法去掉;即为User类写个显示的有参构造,默认隐式的无参构造就没有了;

再次执行,出现异常提示;提示初始化异常;

在xml配置文件中也有提示

IOC创建对象时默认使用无参构造方法,

那么如果说想用有参构造方法呢,有三种方式;

方式1:使用index(下标) 指定有参构造方法的参数是第几个; value 为参数赋值 ;
beans.xml 文件的bean标签下的constructor-arg标签中配置

<?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-3.0.xsd">

    <!--方式1:使用 index(下标)  指定有参构造方法的参数是第几个; value 为参数赋值 -->

    <bean id="user" class="com.lzq.pojo.User">
        <constructor-arg index="0" value="小智从零开始学Java"/>
    </bean>
</beans>

执行,是调用了有参构造方法的;且为参数name赋值也取到了.

方式2:使用type 属性 显式的指定构造函数参数的类型;value为参数赋值.

注意: 基本类型可直接写;引用类型要注明类的地址;
例如官方文档中是这么写的.

<bean id="exampleBean" class="examples.ExampleBean">
   <constructor-arg type="int" value="2001"/>
   <constructor-arg type="java.lang.String" value="Zara"/>
</bean>

ok,用方式2调有参构造方法,为user类创建对象.

<?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-3.0.xsd">
    <!--方式2: 使用 type属性 显式的指定构造函数参数的类型; value 为参数赋值-->
    <bean id="user" class="com.lzq.pojo.User">
        <constructor-arg type="java.lang.String" value="方式二"/>
    </bean>
</beans>

执行,使用成功;

方式 3: 直接使用 参数名name设置 ; value 参数赋值

<?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-3.0.xsd">
    <!--方式3: 使用参数名name; -->
    <bean id="user" class="com.lzq.pojo.User" >
        <constructor-arg name="name" value="方式3"/>
    </bean>
</beans>

执行,使用成功;


还有就是,在pojo包下,再创建一个Student类;

public class Student {
    private int age;

    public Student() {
        System.out.println("Student类的无参构造方法");
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

注意;仅仅是在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-3.0.xsd">

    <!--User类-->
    <!--方式3: 使用参数名name; -->
    <bean id="user" class="com.lzq.pojo.User" >
        <constructor-arg name="name" value="方式3"/>
    </bean>

    <!--Student类-->
    <bean id="student" class="com.lzq.pojo.Student">

    </bean>

</beans>

诶,这里还是执行之前测试User类的代码;

public class Test01 {
    public static void main(String[] args) {
        //获取Spring得上下文对象;
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

        //由于创建对象就是 Spring 中的bean; 获取bean即可获取对象;
        User user = (User) context.getBean("user");

        System.out.println(user.toString());
    }
}

但是输出结果时,发现Student类创建对象时调用的无参构造方法也有记录;

实际上, Spring容器就像是一个婚介网站

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


3.2 Spring配置说明

别名
alias

比如说;为User类创建对象时的变量id user 取个别名u

<alias name="user"  alias="u"/>

那么,在执行测试时,使用别名也能获取到这个User类的对象;

Bean的配置
细细看看<bean>标签内的几个配置标签

id 就是 bean的唯一标识符 ,也就相当于对象名;

classbean 对应的全限定名==> 包名 +类型;

name别名 ;且 可以写多个别名,用逗号或者分号隔开即可

<bean id="user" class="com.lzq.pojo.User"  name="u1,u2;u3">
</bean>

import标签
一般在团队开发中使用;可以将多个配置文件导入合并为一个

<import resource="beans.xml"/>
<import resource="otherbeans.xml"/>
<import resource="otherbeans2.xml"/>

3.3 DI (依赖注入)

第一个就是构造函数注入,也就是刚才在创建对象时修改调用有参无参构造方法时;就使用过了.

第二个就是set注入,这个很重要

依赖: = = > bean对象的创建依赖于Spring容器
注入: = => bean对象中的所有属性,由容器注入.

3.3.1 set

以上是关于狂神说Java --- 记录Spring学习笔记的主要内容,如果未能解决你的问题,请参考以下文章

狂神说spring笔记全链接

狂神说spring笔记全链接

狂神说spring笔记全链接

狂神说spring笔记全链接

狂神说spring笔记全链接

狂神说Java学习笔记12:Java流程控制之for循环