Spring(基础)

在这里插入图片描述
Spring 官网地址: https://spring.io/

spring基础知识

什么是Spring
Spring是一个开源框架,它由Rod Johnson创建。它是为了解决企业应用开发的复杂性而创建的。

Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。
然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。
目的:解决企业应用开发的复杂性
功能:使用基本的JavaBean代替EJB,并提供了更多的企业应用功能
范围:任何Java应用
它是一个容器框架,用来装javabean(java对象),中间层框架(万能胶)可以起一个连接作用,比如说把Struts和hibernate粘合在一起运用。简单来说,Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。

什么是控制反转(或依赖注入) IOC

控制反转 IoC,用白话来讲,就是由容器控制程序之间的(依赖)关系,而非传统实现中,由程序代码直接操控。这也就是所谓“控制反转”的概念所在:(依赖)控制权由应用代码中转到了外部容器,控制权的转移,是所谓反转。

Spring的体系结构

Spring 框架采用分层架构,根据不同的功能被划分成了多个模块,这些模块可根据作 用分为 Data Access/Integration、Web、AOP、Aspects、Messaging、Instrumentation、Core Container 和 Test。
Data Access/Integration(数据访问/集成)
数据访问/集成层包括 JDBC、ORM、OXM、JMS 和 Transactions 模块
在这里插入图片描述
Web
Spring 的 Web 层由 spring-web、spring-webmvc、spring-websocket 和 spring-webflux 组成。
在这里插入图片描述
Core Container(核心容器)
Spring 的核心容器是其他模块建立的基础,由 Beans 模块、Core 核心模块、Context 上 下文模块和 Expression Language 表达式语言模块组成。
在这里插入图片描述
AOP 模块
提供了面向切面编程实现,允许定义方法拦截器和切入点,将代码按 照功能进行分离,以降低耦合性。
Aspects 模块
提供与 AspectJ 的集成,是一个功能强大且成熟的面向切面编程 (AOP)框架。
Instrumentation 模块
提供了类工具的支持和类加载器的实现,可以在特定的应 用服务器中使用。
Test模块
支持 Spring 组件,使用 JUnit 或 TestNG 框架的测试。

Spring 的 jar 包

下载地址

在这里插入图片描述
我们选用5.2.7版本
在这里插入图片描述
对上图的不同的文件后缀做出介绍:

-dist 后缀表示该文件夹下存放的是 jar 包,文档和 xsd 文件; 
-docs 后缀表示该文件夹下存放相关文档,开发指南和 API; 
-schema 里存放了 Spring 所用的 xsd 文件。
libs 目录文件说明: 
.RELEASE.jar: 开发时需要引用的 jar 
.RELEASE-javadoc.jar: 文档 
.RELEASE-sources.jar: 源码

在这里插入图片描述
在这里插入图片描述

Spring IOC 容器

Spring IOC 容器介绍

IOC 思想 :
是指在程序开发中,对象实例的创建不再由调用者管理,而是 由 Spring 容器创建。Spring 容器会负责控制程序之间的关系,而不是由程序代码直接控制, 因此,控制权由程序代码转移到了 Spring 容器中,控制权发生了反转.
IOC 容器概念 :
IOC 容器就是具有依赖注入功能的容器,IOC 容器负责实例化、定位、配置应用程序中 的对象及建立这些对象间的依赖。
Bean 的概念 :
在 Spring 中,被 Spring 容器所管理的对象称之为”Bean”对象。一个 Spring 的 Bean 对象 可以是任何形式的 POJO。
Spring IOC 容器类型:
Spring 提供了两种 IoC 容器,分别为 BeanFactory 和 ApplicationContext
BeanFactory:
是基础类型的 IOC 容器。简单来说,BeanFactory 就是一个管理 Bean 的工厂,它主要负责初始化各种 Bean,并调用它们的生命周期方法。
ApplicationContext:
ApplicationContext 是 BeanFactory 的子接口,也被称为应用上下文。 它不仅提供了 BeanFactory 的所有功能, 还添加了对国际化、资源访问、事件传播等方面的良好支持。

ApplicationContext 接口有两个常用的实现类:
在这里插入图片描述

Spring IOC 容器的使用

搭建环境

创建项目
创建一个java project项目
在这里插入图片描述
添加核心容器的jar包
在这里插入图片描述
在这里插入图片描述
导入jar包
在这里插入图片描述

导入tomcat
在这里插入图片描述
选中,然后点击ok
退出到主界面,再次点进去
在这里插入图片描述
注意以下箭头指向
在这里插入图片描述
出现如下图片所示时,加入tomcat成功
在这里插入图片描述
在这里插入图片描述
参考文章链接

添加 Spring 配置文件:

applicationContext.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">

    
</beans>

通过 IOC 容器管理 Bean 对象

创建 UsersService 接口与实现类

package com.bjsxt.service;

public interface UsersService {
    void addUsers();
}

package com.bjsxt.service.impl;

import com.bjsxt.service.UsersService;


public class UsersServiceImpl implements UsersService {
    @Override
    public void addUsers() {
         System.out.println("UsersService addUsers ......");
    }
}

修改配置文件

<?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="usersService" class="com.bjsxt.service.impl.UsersServiceImpl"/>
</beans>

获取 IOC 容器中的对象

package com.bjsxt.test;

import com.bjsxt.service.UsersService;
import com.bjsxt.service.impl.UsersServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UsersServiceTest {
    public static void main(String[] args) {
/*        UsersService usersService = new UsersServiceImpl();
        usersService.addUsers();*/
        //启动Spring
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        //从IOC容器中获取
        UsersService usersService = (UsersService) applicationContext.getBean("usersService");
        usersService.addUsers();
    }
}

可能会报出如下异常
在这里插入图片描述
这是因为没有导入common包导致的
我们将common jar包导入,可以得到
在这里插入图片描述
在这里插入图片描述

Spring IOC 容器创建 Bean 对象的三种方式

通过构造方法去创建Bean对象

我们知道,一个构造方法是和类同名的,当类实例化一个对象的时候,会自动调用构造方法。
在这里插入图片描述在这里插入图片描述

通过静态工厂方法创建对象

静态工厂方法是23种设计模式的工厂设计模式当中的一种方法,设计模式的工厂模式可以分为静态工厂和动态工厂。(工厂模式的作用也就是为我们提供了一个创建对象的过程)

什么是静态工厂方法
静态工厂法模式是一种封装对象创建的方法。如果没有工厂方法,只需调用类的构造器(构造方法)直接:Foo x = new Foo()… 创建对象。使用此模式,您可以调用工厂方法:Foo x = Foo.create()… 去创建对象。构造函数被标记为私有函数,因此只能从类内部调用它们,而工厂方法标记为static这样就可以在没有对象的情况下调用它。
为什么使用静态工厂方法
使用静态工厂方法的好处有:
具名、环保、多子

具名:
	静态工厂方法有名称
		对于构造器来说,根据入参的不同可以有多个构造器,但是这些构造器的名称都是一样的,使用者在调用时就会一头雾水,到底应该调用哪一个呢。
		而使用了静态工厂方法之后,你可以根据方法的功能给方法起不同的名字,只有名字起得好,使用者看到方法名就知道是什么意思,知道这时候应该调用哪一个方法,大大提高了代码的可读性。
环保:
	不必每次调用的时候都创建一个新对象
		使用构造器,每次都会产生一个新的对象。
		而静态工厂方法,可以重复地返回预先创建好的对象。
多子:
	可以返回原返回类型的任何子类型的对象
		使用构造器,你只能返回一种类型的对象。
		而使用静态工厂方法,你可以根据需要,返回原返回类型的任何子类型的对象。

正是因为静态工厂方法有着比构造器更大的优势,我们在创建类时,切忌第一反应就是提供公有构造器,要优先考虑静态工厂方法

小结

  • 静态工厂方法具有三大优势——具名、环保、多子。
  • 如果一个类提供了静态工厂方法,那么也就不需要考虑对这个类进行工厂模式了。
  • 我们在创建类时,切忌第一反应就是提供公有构造器,要优先考虑静态工厂方法。

实践

创建静态工厂方法:

package com.bjsxt.factory;

import com.bjsxt.service.UsersService;
import com.bjsxt.service.impl.UsersServiceImpl;

/**
 * 静态工厂方法的实践
 * 使用static 意味着,无论我获取多少次getInstance方法,拿到的都是相同的UsersServiceImpl()
 */
public class ObjectFactory {
    public static UsersService getInstance(){
        return new UsersServiceImpl();    
    }
}

修改配置文件:

<?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="usersService" class="com.bjsxt.service.impl.UsersServiceImpl"/>
    <!--通过静态工厂方法去实例化对象-->
    <bean id="usersService2" class="com.bjsxt.factory.ObjectFactory" factory-method="getInstance"/>
</beans>

创建测试类进行测试:

package com.bjsxt.test;

import com.bjsxt.service.UsersService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ObjectFactoryTest {
    public static void main(String[] args){
        //启动Spring
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        //从IOC容器中获取
        UsersService usersService = (UsersService) applicationContext.getBean("usersService2");
        usersService.addUsers();
    }
}

在这里插入图片描述
输出两次Init…,也就是说,构造方法被调用了两次
出现这个结果是因为在配置文件内
在这里插入图片描述
我们先调用了UsersServiceImpl类,运行时会执行一次他的构造方法

又因为下方的静态工厂方法的使用,我们调用了一次UsersServiceImpl()方法
在这里插入图片描述
在这里插入图片描述
所以输出两次Init…

通过动态工厂方法创建对象

什么是动态工厂方法
动态工厂和静态工厂最大的区别是:在创建对象时所返回的对象并不是相同的对象,而是每次调用方法都会产生一个新的对象
怎么使用动态工厂方法
将工厂方法的static去掉即可

实践
创建包含动态工厂的方法

package com.bjsxt.factory;

import com.bjsxt.service.UsersService;
import com.bjsxt.service.impl.UsersServiceImpl;

public class DynamicObjectFactory {
    public UsersService getInstance(){
        return new UsersServiceImpl();
    }
}

修改配置文件


    <!--通过动态工厂方法实例化对象-->
    <bean id="dynamicObjectFactory" class="com.bjsxt.factory.DynamicObjectFactory"/>
    <bean id="usersService3" factory-bean="dynamicObjectFactory" factory-method="getInstance"/>

创建测试类

package com.bjsxt.test;

import com.bjsxt.service.UsersService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class DynamicFactoryTest {
    public static void main(String[] args){

        //启动Spring
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        //从IOC容器中获取
        UsersService usersService = (UsersService) applicationContext.getBean("usersService3");
        usersService.addUsers();
    }
}

在这里插入图片描述

在 Spring IOC 容器中获取 Bean 对象的方式

通过 id 或 name 获取 Bean 对象

格式:applicationContext.getBean(id|name);
配置文件
这里使用name属性:

<bean id="usersService" name="name1,name2,name3" class="com.bjsxt.service.impl.UsersServiceImpl"/>

同时,将其他bean注释

获取 bean 对象

    public static void main(String[] args) {
/*        UsersService usersService = new UsersServiceImpl();
        usersService.addUsers();*/
        //启动Spring
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        //从IOC容器中获取
        UsersService usersService = (UsersService) applicationContext.getBean("name2");
        usersService.addUsers();  
    }

报出的异常
在这里插入图片描述
Exception in thread “main” org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named ‘usersService3’ available
这是因为没有将测试文件重新指定为 测试配置文件
在这里插入图片描述
异常解除:
在这里插入图片描述

通过类型获取 Bean 对象

通过类型来或取 Bean 时,要求类型必须是唯一的。
获取 Bean 对象:

//通过类型获取 Bean 对象 
UsersService usersService = applicationContext.getBean(UsersServiceImpl.class); usersService.addUsers();

通过 id 或 name 与类型获取 Bean 对象

在 SpringIOC 容器中,通过类型获取对象时,如果同一类型存在多个对象,我们可以使 用 id 或 name 来识别需要获取的对象。
第一种方法

        //启动Spring
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        //从IOC容器中获取
        UsersService usersService = applicationContext.getBean("name2",UsersServiceImpl.class);
        usersService.addUsers();

第二种方法

    public static void main(String[] args) {
        //启动Spring IOC容器
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");

        /*方式二*/
        //获取Spring IOC容器中所有的Bean对象的ID
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        //输出Bean对象的所有id
        for(String name: beanDefinitionNames){
            System.out.println(name);
        }
        UsersService usersService = applicationContext.getBean(beanDefinitionNames[0],UsersServiceImpl.class);
        usersService.addUsers();
    }

在这里插入图片描述

Spring IOC 容器如何创建对象

如何实例化对象

Spring IOC 容器在启动时默认的会将在配置文件中所配置的所有 Bean 对象立即进行实 例化,并保存在 IOC 容器中。
我们可以通过<bean>标签 lazy-init 属性的实现延迟实例化对象。 
注意:lazy-init="false"只对 scope 属性为 singleton 才有效,如果 scope 属性为 pototype, 无论 lazy-init 的属性值是什么,都只在通过 getbean 时进行实例化。

立即创建bean
azy-init=“false”(默认)
在 Spring IOC 容器启动时会实例化配置文件中的所有 Bean 对象。

   <bean id="usersService" name="name1,name2" class="com.bjsxt.service.impl.UsersServiceImpl" lazy-init="false"/>

    <!--通过静态工厂方法去实例化对象-->
    <bean id="usersService2" class="com.bjsxt.factory.ObjectFactory" factory-method="getInstance"/>

在这里插入图片描述

延迟创建bean
azy-init=“true”
当调用 getBean 方法是创建对象。

    <bean id="usersService" name="name1,name2" class="com.bjsxt.service.impl.UsersServiceImpl" lazy-init="true"/>

    <!--通过静态工厂方法去实例化对象-->
    <bean id="usersService2" class="com.bjsxt.factory.ObjectFactory" factory-method="getInstance"/>

在这里插入图片描述

Bean 对象的作用域

作用域限定了 Spring Bean 的作用范围,在 Spring 配置文件定义 Bean 时,通过 声明 scope 配置项,可以灵活定义 Bean 的作用范围。

scope 属性的值:

  • singleton(默认的值)
  • prototype
    <bean id="usersService" name="name1,name2" class="com.bjsxt.service.impl.UsersServiceImpl" scope="singleton"/>

    <!--通过静态工厂方法去实例化对象-->
    <bean id="usersService2" class="com.bjsxt.factory.ObjectFactory" factory-method="getInstance"/>

测试类

public class BeanScopeTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        System.out.println("------------------------");

    }
}

在这里插入图片描述

    <bean id="usersService" name="name1,name2" class="com.bjsxt.service.impl.UsersServiceImpl" scope="prototype"/>

    <!--通过静态工厂方法去实例化对象-->
    <bean id="usersService2" class="com.bjsxt.factory.ObjectFactory" factory-method="getInstance"/>

在这里插入图片描述

singleton(单例)

singleton 为 scope 属性的默认值。当 scope 属性的值为 singleton 时,Spring IOC 容器启 动时会立即实例化一次 Bean 对象,并一直被 Spring IOC 容器所缓存,所以生命周期较长
在这里插入图片描述
配置文件

   <bean id="usersService" name="name1,name2" class="com.bjsxt.service.impl.UsersServiceImpl" scope="singleton"/>

    <!--通过静态工厂方法去实例化对象-->
    <bean id="usersService2" class="com.bjsxt.factory.ObjectFactory" factory-method="getInstance"/>

测试类:

    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        System.out.println("------------------------");
        UsersService usersService = (UsersService) applicationContext.getBean("usersService");
        UsersService usersService1 = (UsersService)applicationContext.getBean("usersService");
        System.out.println(usersService);
        System.out.println(usersService1);
    }

在这里插入图片描述
两个对象引用的地址是一样的

prototype(多例)

当 scope 属性的值为 prototype 时,每次调用调用 getBean 方法时都会返回一个新的 Bean 对象,Spring IOC 容器并不会缓存该对象,所以就不再负责管理它的生命周期。
在这里插入图片描述

    <bean id="usersService" name="name1,name2" class="com.bjsxt.service.impl.UsersServiceImpl" scope="prototype"/>

    <!--通过静态工厂方法去实例化对象-->
    <bean id="usersService2" class="com.bjsxt.factory.ObjectFactory" factory-method="getInstance"/>

再次调用测试类,多例的测试类和单例的测试类相同

在这里插入图片描述
这是一个对Spring IOC 容器的使用,但我们可以发现,这样做会更加复杂,因此我们在使用的时候,大多数情况下使用的都是Spring IOC的依赖注入。

DI 依赖注入

对于 Spring IOC 容器而言我们更多的是使用它的依赖注入。 Spring 创建对象的过程叫 做 IOC,创建对象时给对象属性赋值叫做 DI,所以我们可以认为 IOC 和 DI 是同一个事情。

什么是依赖注入(DI)

依赖注入是指在 Spring IOC 容器创建对象的过程中,将所 依赖的对象通过配置进行注入。我们可以通过依赖注入的方式来降低对象间的耦合度。

类之间的关系

继承 实现 依赖 关联 聚合 组合
关系强度:继承 = 实现 > 组合 > 聚合 > 关联 > 依赖

我们重点介绍:
依赖关系
是一种使用的关系, 即一个类的实现需要另一个类的协助, 所以要尽量 不使用双向的互相依赖
主要体现在:局部变量 方法的参数或者对静态方法的调用

聚合关系
是整体与部分的关系.如车和轮胎是整体和部分的关系
主要体现在:成员变量

为什么使用依赖注入

有一篇讲的很浅显的文章,跳转链接
依赖注入有如下优点:
开闭原则:
开闭原则的好处是:易于扩展,易于维护
高内聚,低耦合

依赖注入的方式

在使用依赖注入时,如果注入的是 Bean 对象,那么要求注入的 Bean 对象与被注入的 Bean 对象都需要 Spring IOC 容器来实例化。

通过 Set 方法注入

需要为注入的成员变量提供 Set 方法。

示例:

创建持久层

package com.bjsxt.dao;

public interface UsersDao {
    void insertUsers();
}

package com.bjsxt.dao.impl;

import com.bjsxt.dao.UsersDao;

public class UsersDaoImpl implements UsersDao {
    @Override
    public void insertUsers() {
        System.out.println("JDBC:....insert into ....");
    }
}

修改业务层的UsersServiceImpl类:

public class UsersServiceImpl implements UsersService {
    private UsersDao usersDao;

    public UsersDao getUsersDao() {
        return usersDao;
    }

    public void setUsersDao(UsersDao usersDao) {
        this.usersDao = usersDao;
    }

    public UsersServiceImpl(){
        System.out.println("Init.......");
    }
    @Override
    public void addUsers() {
        usersDao.insertUsers();
//         System.out.println("UsersService addUsers ......");
    }
}

如果不实现set和get方法,usersDao就是空的,会报出空指针异常。

修改配置文件


    <bean id="usersDao" class="com.bjsxt.dao.impl.UsersDaoImpl"/>
    <bean id="usersService" name="name1,name2" class="com.bjsxt.service.impl.UsersServiceImpl">
        <property name="usersDao">
            <ref bean="usersDao"/>
        </property>
    </bean>

SpringIOC启动时,会先去实例化bean对象,会发现id叫usersService的对象内有一个属性叫usersDao,而且这个属性需要注入的是usersDao对象,那么就会将usersDao通过usersServiceImpl类的set方法注入到usersDao对象内,这样usersDao内就不是空的

创建一个测试类

package com.bjsxt.test;

import com.bjsxt.service.UsersService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class DITest {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        UsersService usersService= (UsersService) applicationContext.getBean("usersService");
        usersService.addUsers();
    }
}

在这里插入图片描述
使用Spring DI进行注入编程的好处是,如果我们要使用Mybatis去替换原有的JDBC,那么我们只需要添加好Mybatis的接口和实现类之后,修改xml内对应的配置即可。
如:
我们在持久层新建一个实现类:

package com.bjsxt.dao.impl;

import com.bjsxt.dao.UsersDao;

public class UsersDaoMybatisImpl implements UsersDao {
    @Override
    public void insertUsers() {
        System.out.println("Mybatis.....insert into.....");
    }
}

在原有代码的基础上,我们添加对应的Mybatis的bean对象,将原来的usersDao替换为usersDaoMybatis即可

    <bean id="usersDao" class="com.bjsxt.dao.impl.UsersDaoImpl"/>
    <!-- 新建一个Mybatis的bean对象 -->
    <bean id="usersDaoMybaits" class="com.bjsxt.dao.impl.UsersDaoMybatisImpl"/>
    <bean id="usersService" name="name1,name2" class="com.bjsxt.service.impl.UsersServiceImpl">
        <property name="usersDao">
            <ref bean="usersDaoMybaits"/>
        </property>
    </bean>

在这里插入图片描述

通过 构造方法注入

Bean 对象中需要提供有参的构造方法
在配置文件内创建bean对象

    <bean id="usersDaoMybaits" class="com.bjsxt.dao.impl.UsersDaoMybatisImpl"/>
    <bean id="usersService" name="name1,name2" class="com.bjsxt.service.impl.UsersServiceImpl">
        <!--
        name:根据参数名称识别参数  name="usersDao"
        index:根据参数的位置来识别参数   index="0"
        type:根据参数的类型识别参数     type="com.bjsxt.dao.UsersDao"
        -->
        <constructor-
        <constructor-arg name="usersDao">
            <ref bean="usersDaoMybaits"/>
        </constructor-arg>
    </bean>

为bean对象提供一个有参的构造方法

    private UsersDao usersDao;
 
    public UsersServiceImpl(UsersDao usersDao){
        this.usersDao = usersDao;
    }

调用测试类

public class DITest {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        UsersService usersService= (UsersService) applicationContext.getBean("usersService");
        usersService.addUsers();
    }
}

在这里插入图片描述

自动注入(使用方便,后期维护不方便)

自动注入的方式有两种,一种是全局配置自动注入,另一种是局部配置自动注入。

无论全局配置或局部单独配置,都有 5 个值可以选择:
no:当 autowire 设置为 no 的时候,Spring 就不会进行自动注入。
byName:在 Spring 容器中查找 id 与属性名相同的 bean,并进行注入。需要提供 set 方 法。
byType:在 Spring 容器中查找类型与属性名的类型相同的 bean,并进行注入。需要提供 set 方法。
constructor:仍旧是使用 byName 方式,只不过注入的时候,使用构造方式进行注入。
default:全局配置的 default 相当于 no,局部的 default 表示使用全局配置设置。

局部自动注入
通过 bean 标签中的 autowier 属性配置自动注入。
有效范围:仅针对当前 bean 标签生效。

    <bean id="usersDao" class="com.bjsxt.dao.impl.UsersDaoImpl"/> 
    <!-- byName 根据名称去查找对应的bean对象 -->
    <bean id="usersService" name="name1,name2" class="com.bjsxt.service.impl.UsersServiceImpl" autowire="byName">

    </bean>

我们这里有一个usersDao,当autowire="byName"时,我们会将usersDao注入给我们的usersService.usersDao对应的bean对象是UsersDaoImpl
我们将UsersDaoImpl类的属性重新添加上get 和 set 方法

public class UsersServiceImpl implements UsersService {
    public UsersDao getUsersDao() {
        return usersDao;
    }

    public void setUsersDao(UsersDao usersDao) {
        this.usersDao = usersDao;
    }

    private UsersDao usersDao;

    public UsersServiceImpl(UsersDao usersDao){
        this.usersDao = usersDao;
    }
    public UsersServiceImpl(){
        System.out.println("Init.......");
    }
    @Override
    public void addUsers() {
        usersDao.insertUsers();
//         System.out.println("UsersService addUsers ......");
    }

创建一个测试类


public class AutoWireTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        UsersService usersService =(UsersService) applicationContext.getBean("usersService");
        usersService.addUsers();
    }
}

在这里插入图片描述
也可以使用Mybatis的bean对象

 
    <bean id="usersDaoMybaits" class="com.bjsxt.dao.impl.UsersDaoMybatisImpl"/>
    <!-- byName 根据名称去查找对应的bean对象 -->
    <bean id="usersService" name="name1,name2" class="com.bjsxt.service.impl.UsersServiceImpl" autowire="byName">

    </bean>

同理,使用autowire=“constructor” 进行注入

    <bean id="usersDaoMybaits" class="com.bjsxt.dao.impl.UsersDaoMybatisImpl"/>
    <bean id="usersService" name="name1,name2" class="com.bjsxt.service.impl.UsersServiceImpl" autowire="constructor"/>

在这里插入图片描述

全局自动注入
通过 beans 标签中的 default-autowire 属性配置自动注入。
有效范围:配置文件中的所有 bean 标签都生效。

<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"
       default-autowire="byType">

在这里插入图片描述
但是,我们的配置文件会报出一个异常
在这里插入图片描述
如果我们任然去运行测试类,那么控制台会给出一个报错
在这里插入图片描述
我们删除一个bean对象即可

    <bean id="usersDao" class="com.bjsxt.dao.impl.UsersDaoImpl"/> 
    <bean id="usersService" name="name1,name2" class="com.bjsxt.service.impl.UsersServiceImpl" />
    

在这里插入图片描述

或者


    <!-- 新建一个Mybatis的bean对象 -->
    <bean id="usersDaoMybaits" class="com.bjsxt.dao.impl.UsersDaoMybatisImpl"/>
    <bean id="usersService" name="name1,name2" class="com.bjsxt.service.impl.UsersServiceImpl" />

在这里插入图片描述
但我们如果使用byName查询自建的Mybaits时,会报出一个空指针的异常
如下:

<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"
       default-autowire="byName">

    <bean id="usersDaoMybaits" class="com.bjsxt.dao.impl.UsersDaoMybatisImpl"/>
    <bean id="usersService" name="name1,name2" class="com.bjsxt.service.impl.UsersServiceImpl" />

在这里插入图片描述
因为usersServiceImpl类的usersDao并没有注入,所以在addUsers方法内使用usersDao对象去调用的insertUsers(),usersDao本来就是空的,自然会报出空指针异常 。
解决方法:
需要将bean对象的id的名字和注入对象的名称一样
也就是将UsersServiceImpl类的usersDao改为usersDaoMybatis

public class UsersServiceImpl implements UsersService {
    private UsersDao usersDaoMybaits;

    public UsersDao getUsersDaoMybaits() {
        return usersDaoMybaits;
    }

    public void setUsersDaoMybaits(UsersDao usersDaoMybaits) {
        this.usersDaoMybaits = usersDaoMybaits;
    }

    public UsersServiceImpl(UsersDao usersDao){
        this.usersDaoMybaits = usersDao;
    }
    public UsersServiceImpl(){
        System.out.println("Init.......");
    }
    @Override
    public void addUsers() {
        usersDaoMybaits.insertUsers();
//         System.out.println("UsersService addUsers ......");
    }
}

在这里插入图片描述
异常解除

依赖注入的数据类型

注入 Bean 对象
上面的示例也有讲解使用

方式一:

<property name="FieldName"> 
	<ref bean="BeanID"/> 
</property>

方式二:

<property name="FieldName" ref ="BeanID"/>  

注入基本数据类型和字符串的值
方式一:

<property name="FieldName"> 
	<value>content</value> 
</property>

方式二:

<property name="FieldName" value="Content" /> 

示例:

<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="usersDao" class="com.bjsxt.dao.impl.UsersDaoImpl"/>
    <!-- 新建一个Mybatis的bean对象 -->
    <!--<bean id="usersDaoMybaits" class="com.bjsxt.dao.impl.UsersDaoMybatisImpl"/>-->
    <bean id="usersService" name="name1,name2" class="com.bjsxt.service.impl.UsersServiceImpl">
        <property name="usersDao" ref="usersDao"/>
        <property name="username">
            <value>OldLiu</value>
        </property>
        <!-- 两种property格式,都可以 -->
 		<property name="userage" value="13"/>
    </bean>

注意,之前的全局配置自动注入的配置需要删掉对应的属性和值

   private String username;
    private int userage;

    public void setUsername(String username) {
        this.username = username;
    }

    public void setUserage(int userage) {
        this.userage = userage;
    }
        @Override
    public void addUsers() {
        usersDao.insertUsers();
        System.out.println(this.userage+"  "+this.username);
//         System.out.println("UsersService addUsers ......");
    }

在这里插入图片描述
注入List类型的数据
配置文件:

        <property name="list">
            <list>
                <value>一个好名</value>
                <value>itbz</value>
            </list>
        </property>

UsersServiceImpl类

    private List<String> list;
    
        public void setList(List<String> list) {
        this.list = list;
    }
  @Override
    public void addUsers() {
        usersDao.insertUsers();
        System.out.println(this.list);
//         System.out.println("UsersService addUsers ......");
    }

在这里插入图片描述
也可以使用 list.forEach(System.out::println);jianglist对象循环输出。

我们修改泛型,自建一个users实体类

package com.bjsxt.pojo;

public class Users {
    private String username;
    private int userage;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public int getUserage() {
        return userage;
    }

    public void setUserage(int userage) {
        this.userage = userage;
    }

    @Override
    public String toString() {
        return "Users{" +
                "username='" + username + '\'' +
                ", userage=" + userage +
                '}';
    }
}

在UsersServiceImpl类内新建list

    private List<Users> users;

    public void setUsers(List<Users> users) {
        this.users = users;
    }
        public void addUsers() {
        usersDao.insertUsers();
        users.forEach(System.out::println); 
    }

调用测试类,输出结果为:
在这里插入图片描述

注入 Set类型的数据
在UsersServiceImpl类内新建

    private Set<Users> usersSet;

    public void setUsersSet(Set<Users> usersSet) {
        this.usersSet = usersSet;
    }

    public void addUsers() {
        usersDao.insertUsers();
        usersSet.forEach(System.out::println); 
    }

配置文件


        <property name="usersSet">
            <set>
                <bean class="com.bjsxt.pojo.Users">
                    <property name="username" value="Oldlu-set"/>
                    <property name="userage" value="30"/>
                </bean>
                <bean class="com.bjsxt.pojo.Users">
                    <property name="username" value="admin-set"/>
                    <property name="userage" value="20"/>
                </bean>
            </set>
        </property>

在这里插入图片描述
注入 Map类型的数据

  • 第一种方式
    配置文件
        <property name="map">
            <map>
                <entry key="key1" value="value1"/>
                <entry key="key2" value="value2"/>
            </map>
        </property>

在UsersServiceImpl类内

    private Map<String,String> map;

    public void setMap(Map<String, String> map) {
        this.map = map;
    }
    public void addUsers() {
        usersDao.insertUsers();
               for(Map.Entry<String,String> entry:this.map.entrySet()){
            		System.out.println(entry.getKey()+"\t"+entry.getValue());
        } 
    }

在这里插入图片描述

  • 第二种方式
    private Map<String,Users> usersMap;

    public void setUsersMap(Map<String, Users> usersMap) {
        this.usersMap = usersMap;
    }
    public void addUsers() {
        usersDao.insertUsers();
        for(Map.Entry<String,Users> entry:this.usersMap.entrySet()){
            System.out.println(entry.getKey()+"\t"+entry.getValue());
        } 
    }

    <bean id="usersService" name="name1,name2" class="com.bjsxt.service.impl.UsersServiceImpl">
    ........
        <property name="usersMap">
            <map>
                <entry key="users1" value-ref="users1" />
                <entry key="users2" value-ref="users2" />
            </map>
        </property>
    </bean>

    <bean id="users1" class="com.bjsxt.pojo.Users">
        <property name="username" value="Oldlu-map"/>
        <property name="userage" value="30"/>
    </bean>
    <bean id="users2" class="com.bjsxt.pojo.Users">
        <property name="username" value="admin-map"/>
        <property name="userage" value="20"/>
    </bean>
    

在这里插入图片描述

注入 Properties

    private Properties properties;

    public void setProperties(Properties properties) {
        this.properties = properties;
    }
    public void addUsers() {
        usersDao.insertUsers();

        String value1 = this.properties.getProperty("pro1");
        String value2 = this.properties.getProperty("pro2");
        System.out.println(value1+"\t"+value2); 
    }

        <property name="properties">
            <props>
                <prop key="pro1">provalue1</prop>
                <prop key="pro2">provalue2</prop>
            </props>
        </property>

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值