spring IOC

2023-10-31

1 主要内容

请添加图片描述

2. Spring 框架

2.1. Spring 框架概念

Spring 是众多开源java项目中的一员,基于分层的javaEE应用一站式轻量级开源框架,主要核心是

IOC(控制反转/依赖注入)与 AOP(面向切面)两大技术,实现项目在开发过程中的轻松解耦,提高项

目的开发效率。

在项目中引入 Spring 立即可以带来下面的好处 降低组件之间的耦合度,实现软件各层之间的解耦。可

以使用容器提供的众多服务,如:事务管理服务、消息服务等等。当我们使用容器管理事务时,开发人

员就不再需要手工控制事务.也不需处理复杂的事务传播。 容器提供单例模式支持,开发人员不再需要自

己编写实现代码。 容器提供了AOP技术,利用它很容易实现如权限拦截、运行期监控等功能。

2.2. Spring 源码架构

Spring 总共大约有20个模块,由1300多个不同的文件构成。而这些组件被分别整合在核心容器

(Core Container)、Aop(Aspect Oriented Programming)和设备支持(Instrmentation)、数据

访问及集成(Data Access/Integeration)、Web、报文发送(Messaging)、测试6个模块集合中。

  1. 核心容器:Spring-beans 和 Spring-core 模块是 Spring 框架的核心模块,包含控制反转

(Inversion of Control, IoC)和依赖注入(Dependency Injection, DI),核心容器提供 Spring 框

架的基本功能。核心容器的主要组件是 BeanFactory,工厂模式的实现。BeanFactory 使用控制反

转(IOC) 思想将应用程序的配置和依赖性规范与实际的应用程序代码分开。

Spring 上下文Spring Context:Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。

Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。

Spring-Expression 模块是统一表达式语言(unified EL)的扩展模块,可以查询、管理运行中的对

象,同时也方便的可以调用对象方法、操作数组、集合等。它的语法类似于传统EL,但提供了额外

的功能,最出色的要数函数调用和简单字符串的模板函数。

  1. Spring-AOP:Spring-aop是Spring的另一个核心模块, 在Spring中,他是以JVM的动态代理技术为

基础,然后设计出了一系列的Aop横切实现,比如前置通知、返回通知、异常通知等。通过其配置

管理特性,Spring AOP 模块直接将面向切面的编程功能集成到了 Spring 框架中。所以,可以很容

易地使 Spring 框架管理的任何对象支持 AOP。

  1. Spring Data Access(数据访问):由Spring-jdbc、Spring-tx、Spring-orm、Spring-jms和Spring

oxm 5个模块组成 Spring-jdbc 模块是 Spring 提供的JDBC抽象框架的主要实现模块,用于简化

Spring JDBC。

Spring-tx 模块是SpringJDBC事务控制实现模块。使用Spring框架,它对事务做了很好的封装,通

过它的Aop配置,可以灵活的配置在任何一层。

Spring-Orm 模块是ORM框架支持模块,主要集成 hibernate, Java Persistence API (JPA) 和 Java

Data Objects (JDO) 用于资源管理、数据访问对象(DAO)的实现和事务策略。

Spring-Jms 模块(Java Messaging Service)能够发送和接受信息。

Spring-Oxm 模块主要提供一个抽象层以支撑OXM(OXM 是 Object-to-XML-Mapping 的缩写,它

是一个O/M-mapper,将java对象映射成 XML 数据,或者将 XML 数据映射成 java 对象),例

如:JAXB, Castor, XMLBeans, JiBX 和 XStream 等。

  1. Web 模块:由Spring-web、Spring-webmvc、Spring-websocket和Spring-webmvc-portlet 4个

模块组成,Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下

文。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。

  1. 报文发送:即Spring-messaging模块。

Spring-messaging是Spring4 新加入的一个模块,主要职责是为Spring 框架集成一些基础的报文

传送应用。

  1. 单元测试:即Spring-test模块。Spring-test模块主要为测试提供支持

2.3. Spring 框架环境搭建

2.3.1. 环境要求

JDK 版本:

JDK 1.7 及以上版本

Spring版本:

Spring 5.x版本

2.3.2. 新建 Maven 项目

创建 Maven 的普通 Java 项目,选择quickstart,下面按步骤进行

2.3.3. 调整项目环境

  1. 修改 JDK 版本
 <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
  </properties>
  1. 修改单元测试 JUnit 版本
<dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
  1. 删除build标签中的pluginManagement标签

2.3.4. 添加 Spring 框架的依赖坐标

Maven仓库:https://mvnrepository.com/

<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.4.RELEASE</version>
    </dependency>

2.3.5. 编写 Bean 对象

public class UserService {
    public void test(){
        System.out.println("hello");
    }
}

2.3.6. 添加Spring 配置文件

  1. 在项目的src/main下创建文件夹 resources(Alt+insert)

  2. 将 resources 标记为资源目录

  3. 在 src\main\resources 目录下新建 spring.xml 文件,并拷贝官网文档提供的模板内容到 xml 中。

    配置 bean 到 xml 中,把对应 bean 纳入到 Spring 容器来管理

    spring framework–>LEARN–>reference dovumentation–>core–>1.2.1

    https://docs.spring.io/spring-framework/docs/5.3.20-SNAPSHOT/reference/html/core.html#spring-core

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

    <!-- xmlns 即 xml namespace xml使用的命名空间
    xmlns:xsi 即xml schema instance xml 遵守的具体规范
    xsi:schemaLocation 本文档xml遵守的规范 官方指定
    -->
   <bean id="userService" class="com.whl.service.UserService"></bean>

</beans>
  1. 在 spring.xml 中配置 Bean 对象
	<!-- id:bean对象的id,唯一标识。
    一般是Bean对象的名称的首字母小写 class:bean对象的类路径 
    -->
   <bean id="userService" class="com.whl.service.UserService"></bean>

2.3.7. 加载配置文件,获取实例化对象

public class App {
    public static void main( String[] args ) {
        // 获取Spring上下文环境 (加载配置文件)
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
        // 通过getBean方法得到Spring容器中实例化好的Bean对象 (实例化Bean对象)
        // userService代表的是配置文件中bean标签的id属性值
        UserService userService = (UserService) ac.getBean("userService");
        UserService userService2 = (UserService) ac.getBean("userService");
        // 调用方法 (使用实例化对象)
        userService.test();
        userService2.test();
    }
}

3. Spring IOC 容器 Bean 对象实例化模拟

思路:

  1. 定义Bean 工厂接口,提供获取bean方法
  2. 定义Bean工厂接口实现类,解析配置文件,实例化Bean对象
  3. 实现获取Bean方法

3.1. 修改pom.xml,添加 dom4j 坐标依赖

<?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.whl</groupId>
  <artifactId>Spring02BeanFactory</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>Spring02BeanFactory</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>

    <!-- dom4j -->
    <dependency>
      <groupId>dom4j</groupId>
      <artifactId>dom4j</artifactId>
      <version>1.6.1</version>
    </dependency>
    <!-- XPath -->
    <dependency>
      <groupId>jaxen</groupId>
      <artifactId>jaxen</artifactId>
      <version>1.1.6</version>
    </dependency>
  </dependencies>

  <build>

  </build>
</project>

3.2 定义Bean属性对象

package com.whl.po;

public class MyBean {
    private String id;
    private String clazz;

    public MyBean(String id, String clazz) {
        this.id = id;
        this.clazz = clazz;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getClazz() {
        return clazz;
    }

    public void setClazz(String clazz) {
        this.clazz = clazz;
    }
}


3.3. 准备自定义配置文件

spring.xml

<?xml version="1.0" encoding="utf-8" ?>
<beans>
    <bean id="userService" class="com.whl.service.UserService"></bean>
    <bean id="userDao" class="com.whl.dao.UserDao"></bean>
</beans>

3.4. 定义 Bean 工厂接口

package com.whl.factory;

public interface MyBeanFactory {
    /**
     * 对外围提供获取实例化后对象的方法
     * @return
     */
    Object getBean(String name);
}

3.5. 定义 Bean 接口的实现类

package com.whl.factory;

import com.whl.po.MyBean;
import org.dom4j.*;
import org.dom4j.io.SAXReader;

import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MyClassPathXmlApplicationContext implements MyBeanFactory{
    List<MyBean> beanList = new ArrayList(); //存储解析出来的id 和 class权限定名

    Map<String,Object> beanMap = new HashMap();  //存储id 和 实例化后的对象

    /**
     * 加载配置文件,获取配置的标签,实例化对象
     * @param fileName
     */
    public MyClassPathXmlApplicationContext(String fileName) {

        //解析xml配置文件
        parseXml(fileName);

        //实例化bean对象
        instanceBean();
    }


    /**
     * 实例化出bean对象
     */
    private void instanceBean() {
        //遍历beanList  解析到的配置内容
        if(beanList != null && beanList.size() > 0){
            for(MyBean bean:beanList){
                String id = bean.getId();
                String clazz = bean.getClazz(); //权限定名

                try {
                    //实例化对象
                    Object obj = Class.forName(clazz).newInstance();
                    //将数据存放在map中,方便用户获取
                    beanMap.put(id,obj);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }


    /**
     * 解析配置文件,获取到bean标签中的id 和 class 属性值
     * @param fileName
     */
    private void parseXml(String fileName) {

        //获取解析器
        SAXReader reader = new SAXReader();
        //获取到配置文件的url对象
        URL url = this.getClass().getClassLoader().getResource(fileName);
        try {
            //读取配置文件
            Document document = reader.read(url);
            //创建XPath语法匹配解析xml中的bean标签
            XPath xPath = document.createXPath("beans/bean");
            //匹配获取bean标签
            List<Element> list = xPath.selectNodes(document);
            //准备获取id属性和class属性
            if(list != null && list.size() > 0){
                //遍历获取到的bean标签
                for(Element bean:list){
                    String id = bean.attributeValue("id");  //唯一标识
                    String clazz = bean.attributeValue("class"); //全限定名

                    /*System.out.println(id);
                    System.out.println(clazz);*/

                    //存储id值和clazz的值
                    MyBean myBean = new MyBean(id, clazz);
                    beanList.add(myBean); //将所有的数据存入list
                }
            }

        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }

    /**
     * 通过唯一的标识获取到实例化后的对象
     * ToDo
     * @return
     */
    @Override
    public Object getBean(String name) {
        if(beanMap != null && beanMap.size() > 0){
            return beanMap.get(name);
        }
        return null;
    }
}

3.6. 测试自定义 IOC 容器

创建与配置文件中对应的Bean对象

UserService.java

package com.whl.service;

public class UserService {
    public void test(){
        System.out.println("UserService.........");
    }
}

UserDao.java

package com.whl.dao;

public class UserDao {
    public void test(){
        System.out.println("UserDao.........");
    }
}

测试是否可以获取实例化的Bean对象

package com.whl;

import com.whl.dao.UserDao;
import com.whl.factory.MyBeanFactory;
import com.whl.factory.MyClassPathXmlApplicationContext;

/**
 * Hello world!
 */
public class App {
    public static void main(String[] args) {
        //加载配置,实例化对象
        MyBeanFactory ac = new MyClassPathXmlApplicationContext("spring.xml");
        UserDao userDao = (UserDao) ac.getBean("userDao");

        userDao.test();
    }
}

4. Spring IOC 配置文件加载

4.1. Spring 配置文件加载

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

    <!-- xmlns 即 xml namespace xml使用的命名空间
    xmlns:xsi 即xml schema instance xml 遵守的具体规范
    xsi:schemaLocation 本文档xml遵守的规范 官方指定
    -->
   <bean id="userService" class="com.whl.service.UserService"></bean>

</beans>

4.1.1. 根据相对路径加载资源

ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");

4.1.2. 根据绝对路径加载资源(了解)

ApplicationContext ac = new FileSystemXmlApplicationContext("C:/IdeaWorkspace/spring01/src/main/resources/sp ring.xml");

4.2. Spring 多配置文件加载

Spring 框架启动时可以加载多个配置文件到环境中。对于比较复杂的项目,可能对应的配置文件有多

个,项目在启动部署时会将多个配置文件同时加载进来。

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

    <!-- xmlns 即 xml namespace xml使用的命名空间
    xmlns:xsi 即xml schema instance xml 遵守的具体规范
    xsi:schemaLocation 本文档xml遵守的规范 官方指定
    -->
   <bean id="userService" class="com.whl.service.UserService"></bean>

</beans>

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

    <!-- xmlns 即 xml namespace xml使用的命名空间
    xmlns:xsi 即xml schema instance xml 遵守的具体规范
    xsi:schemaLocation 本文档xml遵守的规范 官方指定
    -->
   <bean id="userDao" class="com.whl.dao.UserDao"></bean>

</beans>

4.2.1. 可变参数,传入多个文件名

// 同时加载多个资源文件
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml","dao.xml");

4.2.2. 通过总的配置文件import其他配置文件

spring.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">
    
    <!--导入需要包含的资源文件--> 
    <import resource="service.xml"/> 
    <import resource="dao.xml"/> 
</beans>

加载时只需加载总的配置文件即可

// 加载总的资源文件
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");

5. Spring IOC 容器 Bean 对象实例化

5.1. 构造器实例化

注:通过默认构造器创建 空构造方法必须存在 否则创建失败

package com.whl.service;

public class UserService {
   /* private String name;
    
    public UserService() {
    }

    public UserService(String name) {
    }*/

    public void test(){
        System.out.println("hello");
    }
}

  1. 设置配置文件 spring.xml

默认选择空构造,在UserService中写了一个有参构造不写空构造会找不到

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

    <!-- xmlns 即 xml namespace xml使用的命名空间
    xmlns:xsi 即xml schema instance xml 遵守的具体规范
    xsi:schemaLocation 本文档xml遵守的规范 官方指定
    -->
   <!--配置bean对象
           id:给实例化后对象的别名,唯一的标识,一般是Bean对象的名称的首字母小写
           class:需要spring帮助创建实例对象的路径,bean对象的类路径,全限定名  -->
    
    <bean id="userService" class="com.whl.service.UserService"></bean>


</beans>
  1. 获取实例化对象
public class App {
    public static void main( String[] args ) {
        // 获取Spring上下文环境 (加载配置文件)
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
        // 通过getBean方法得到Spring容器中实例化好的Bean对象 (实例化Bean对象)
        // userService代表的是配置文件中bean标签的id属性值
        UserService userService = (UserService) ac.getBean("userService");
        UserService userService2 = (UserService) ac.getBean("userService");
        // 调用方法 (使用实例化对象)
        userService.test();
        //userService2.test();
        System.out.println(userService);
        System.out.println(userService2);
    }
}

5.2. 静态工厂实例化(了解)

注:

  • 要有该工厂类及工厂方法
  • 工厂方法为静态的

定义静态工厂类

package com.whl.factory;

import com.whl.service.UserService;

/**
 * 静态工厂实例化
 *      1.定义一个类
 *      2.定义一个静态方法,返回实例化的对象
 */
public class StaticFactory {
    public static UserService creatUserService(){
        return new UserService();
    }
}

设置配置文件 spring.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">

    <!-- xmlns 即 xml namespace xml使用的命名空间
    xmlns:xsi 即xml schema instance xml 遵守的具体规范
    xsi:schemaLocation 本文档xml遵守的规范 官方指定
    -->
   <!--配置bean对象
           id:给实例化后对象的别名,唯一的标识,一般是Bean对象的名称的首字母小写
           class:需要spring帮助创建实例对象的路径,bean对象的类路径,全限定名  -->
    
    <!--<bean id="userService" class="com.whl.service.UserService"></bean>-->

    <!--
        静态工厂
    -->
    <bean id="userService" class="com.whl.factory.StaticFactory" factory-method="creatUserService"></bean>


</beans>

获取实例化对象

public class App {
    public static void main( String[] args ) {
        // 获取Spring上下文环境 (加载配置文件)
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
        // 通过getBean方法得到Spring容器中实例化好的Bean对象 (实例化Bean对象)
        // userService代表的是配置文件中bean标签的id属性值
        UserService userService = (UserService) ac.getBean("userService");
        UserService userService2 = (UserService) ac.getBean("userService");
        // 调用方法 (使用实例化对象)
        userService.test();
        //userService2.test();
        System.out.println(userService);
        System.out.println(userService2);
    }
}

当我们指定Spring使用静态工厂方法来创建Bean实例时,Spring将先解析配置文件,并根据配

置文件指定的信息,通过反射调用静态工厂类的静态工厂方法,并将该静态工厂方法的返回值作为

Bean实例**,在这个过程中,Spring不再负责创建Bean实例,**Bean实例是由用户提供的静态工厂

方法提供的。

5.3. 实例化工厂实例化(了解)

注:

  • 工厂方法为非静态方法
  • 需要配置工厂bean,并在业务bean中配置factory-bean,factory-method属性

定义工厂类

package com.whl.factory;

import com.whl.service.UserService;

/**
 * 实例化工厂
 *      1.定义一个普通类
 *      2.定义一个普通方法,返回实例化的对象
 */
public class InstanceFactory {
    public UserService createUserService(){
        return new UserService();
    }
}

设置配置文件 spring.xml

 <!--实例化工厂
    1.定义实例化工厂bean
    2.引用工厂bean 指定工厂创建方法(方法为非静态) -->

    <bean id="instanceFactory" class="com.whl.factory.InstanceFactory"></bean>
    <bean id="userService" factory-bean="instanceFactory" factory-method="createUserService"></bean>

获取实例化对象

package com.whl;

import com.whl.service.UserService;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Hello world!
 *
 */
public class App {
    public static void main( String[] args ) {
        // 获取Spring上下文环境 (加载配置文件)
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
        // 通过getBean方法得到Spring容器中实例化好的Bean对象 (实例化Bean对象)
        // userService代表的是配置文件中bean标签的id属性值
        UserService userService = (UserService) ac.getBean("userService");
        UserService userService2 = (UserService) ac.getBean("userService");
        // 调用方法 (使用实例化对象)
        userService.test();
        //userService2.test();
        System.out.println(userService);
        System.out.println(userService2);
    }
}

5.4. Spring三种实例化Bean的方式比较

方式一:通过bean的缺省构造函数创建,当各个bean的业务逻辑相互比较独立的时候或者和外界

关联较少的时候可以使用。

方式二:利用静态factory方法创建,可以统一管理各个bean的创建,如各个bean在创建之前需要

相同的初始化处理,则可用这个factory方法险进行统一的处理等等。

方式三:利用实例化factory方法创建,即将factory方法也作为了业务bean来控制,1可用于集成

其他框架的bean创建管理方法,2能够使bean和factory的角色互换。

开发中项目一般使用一种方式实例化bean,项目开发基本采用第一种方式,交给Spring托管,使用

时直接拿来使用即可。另外两种了解

6. Spring IOC 注入

手动实例化与外部引入

对于 UserDao 对象的创建不要主动的去实例化(new),而是通过带参方法 形式将UserDao 传入过来,从而实现 UserService 对UserDao类 的依赖。

而实际创建对象的幕后对象即是交给了外部来创建。

6.1. Spring IOC 手动装配(注入)

Spring 支持的注入方式共有四种:set 注入、构造器注入、静态工厂注入、实例化工厂注入。

6.1.1. set方法注入

  • 注:

    属性字段需要提供set方法

    四种方式,推荐使用set方法注入

6.1.1.1. 业务对象 JavaBean

UserDao.java

package com.whl.dao;

public class UserDao {
    public void test(){
        System.out.println("连接数据库,查询数据");
    }
}

UserService.java

package com.whl.service;

import com.whl.dao.UserDao;

public class UserService {
   private UserDao userDao;

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

    public void test(){
        System.out.println("userservice.......");
        System.out.println(userDao);
    }
}

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

    <!--
            property  set注入
                name 指向属性名称(自动生成的set方法)
                ref 指向bean标签的id值  bean对象
                value 对应的是具体的值

        -->
    <bean id="userDao" class="com.whl.dao.UserDao"></bean>
    <bean id="userService" class="com.whl.service.UserService">
        <property name="userDao" ref="userDao"></property>
    </bean>

</beans>
6.1.1.2. 常用对象和基本类型

UserService.java

package com.whl.service;

import com.whl.dao.UserDao;

public class UserService {

   private Integer port;

   private String name;

    public void setPort(Integer port) {
        this.port = port;
    }

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

   
    public void test(){
        System.out.println("userservice.......");
        System.out.println(name);
        System.out.println(port);
    }
}

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

    <!--
            property  set注入
                name 指向属性名称(自动生成的set方法)
                ref 指向bean标签的id值  bean对象
                value 对应的是具体的值

        -->
    <bean id="userDao" class="com.whl.dao.UserDao"></bean>
    <bean id="userService" class="com.whl.service.UserService">
        <property name="userDao" ref="userDao"></property>
        <property name="port" value="8080"></property>
        <property name="name" value="张三"></property>
    </bean>

</beans>
6.1.1.3. 集合类型和属性对象

UserService.java

package com.whl.service;

import com.whl.dao.UserDao;

import java.util.List;
import java.util.Map;
import java.util.Properties;

public class UserService {
 

    // List集合  set注入(提供set方法)
    public List<String> list;
    public void setList(List<String> list) {
        this.list = list;
    }
    public void printList(){
        list.forEach(k -> System.out.println(k));
    }


    // Map set注入(提供set方法)
    private Map<String,Object> map;
    public void setMap(Map<String, Object> map) {
        this.map = map;
    }
    public void printMap(){
        map.forEach((k,v) -> System.out.println(k+v));
    }


    // Properties set注入(提供set方法)
    private Properties properties;
    public void setProperties(Properties properties) {
        this.properties = properties;
    }
    public void printProperties(){
        properties.forEach((k,v) -> System.out.println(k+"----"+v));
    }

  

    public void test(){
        System.out.println("userservice.......");
     
        printList();
        printMap();
        printProperties();
    }
}

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

    <!--
            property  set注入
                name 指向属性名称(自动生成的set方法)
                ref 指向bean标签的id值  bean对象
                value 对应的是具体的值

        -->
    <bean id="userDao" class="com.whl.dao.UserDao"></bean>
    <bean id="userService" class="com.whl.service.UserService">
        <property name="userDao" ref="userDao"></property>
        <property name="port" value="8080"></property>
        <property name="name" value="张三"></property>


        <!--注入 List-->
        <property name="list">
            <list>
                <value>123</value>
                <value>456</value>
                <value>789</value>
            </list>
        </property>
        <property name="map">
            <map>
                <entry>
                    <key><value>卢本伟</value></key>
                    <value>五五开</value>
                </entry>
                <entry>
                    <key><value>PDD</value></key>
                    <value>拼到底</value>
                </entry>
            </map>
        </property>
        <property name="properties">
            <props>
                <prop key="UZI">永远的神</prop>
                <prop key="麻辣香锅">莽夫</prop>
            </props>
        </property>
    </bean>
</beans>
6.1.1.4. 测试代码

UserDao

package com.whl.dao;

public class UserDao {
    public void test(){
        System.out.println("连接数据库,查询数据");
    }
}

UserService.java

package com.whl.service;

import com.whl.dao.UserDao;

import java.util.List;
import java.util.Map;
import java.util.Properties;

public class UserService {
   private UserDao userDao;

   private Integer port;

   private String name;

    // List集合  set注入(提供set方法)
    public List<String> list;
    public void setList(List<String> list) {
        this.list = list;
    }
    public void printList(){
        list.forEach(k -> System.out.println(k));
    }


    // Map set注入(提供set方法)
    private Map<String,Object> map;
    public void setMap(Map<String, Object> map) {
        this.map = map;
    }
    public void printMap(){
        map.forEach((k,v) -> System.out.println(k+v));
    }


    // Properties set注入(提供set方法)
    private Properties properties;
    public void setProperties(Properties properties) {
        this.properties = properties;
    }
    public void printProperties(){
        properties.forEach((k,v) -> System.out.println(k+"----"+v));
    }

    public void setPort(Integer port) {
        this.port = port;
    }

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

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

    public void test(){
        System.out.println("userservice.......");
        System.out.println(userDao);
        System.out.println(name);
        System.out.println(port);

        printList();
        printMap();
        printProperties();
    }
}

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

    <!--
            property  set注入
                name 指向属性名称(自动生成的set方法)
                ref 指向bean标签的id值  bean对象
                value 对应的是具体的值

        -->
    <bean id="userDao" class="com.whl.dao.UserDao"></bean>
    <bean id="userService" class="com.whl.service.UserService">
        <property name="userDao" ref="userDao"></property>
        <property name="port" value="8080"></property>
        <property name="name" value="张三"></property>


        <!--注入 List-->
        <property name="list">
            <list>
                <value>123</value>
                <value>456</value>
                <value>789</value>
            </list>
        </property>
        <property name="map">
            <map>
                <entry>
                    <key><value>卢本伟</value></key>
                    <value>五五开</value>
                </entry>
                <entry>
                    <key><value>PDD</value></key>
                    <value>拼到底</value>
                </entry>
            </map>
        </property>
        <property name="properties">
            <props>
                <prop key="UZI">永远的神</prop>
                <prop key="麻辣香锅">莽夫</prop>
            </props>
        </property>
    </bean>
</beans>

测试代码

public class App {
    public static void main( String[] args ) {
        // 获取Spring上下文环境 (加载配置文件)
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
        // 通过getBean方法得到Spring容器中实例化好的Bean对象 (实例化Bean对象)
        // userService代表的是配置文件中bean标签的id属性值
        UserService userService = (UserService) ac.getBean("userService");
        // 调用方法 (使用实例化对象)
        userService.test();
      
    }
}

6.1.2. 构造器注入

  • 注:

    提供带参构造器

6.1.2.1 使用
  • 单个Bean对象作为参数
  • 多个Bean对象作为参数
  • Bean对象和常用对象作为参数
6.1.2.2 循环依赖问题

循环问题产生的原因:

Bean通过构造器注入,之间彼此相互依赖对方导致bean无法实例化。 a中有b,b中有a。

解决方法:将构造器注入改为set方法注入

6.1.2.3 代码

TypeDao.java

package com.whl.dao;

public class TypeDao {
    public void test(){
        System.out.println("TypeDao 连接数据库,查询数据");
    }
}

UserDao.java

package com.whl.dao;

public class UserDao {
    public void test(){
        System.out.println("连接数据库,查询数据");
    }
}

TypeService.java

package com.whl.service;

import com.whl.dao.TypeDao;
import com.whl.dao.UserDao;

public class TypeService {
    private TypeDao typeDao;

    public TypeService(TypeDao typeDao, UserDao userDao, String name) {
        this.typeDao = typeDao;
    }

    public void test(){
        System.out.println(typeDao);
    }
}

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

    <!--
            property  set注入
                name 指向属性名称(自动生成的set方法)
                ref 指向bean标签的id值  bean对象
                value 对应的是具体的值

            构造器注入
                ref 引用,其他bean标签中的id值
                name 对应的是类中属性
                index 设置匹配参数列表中的索引 确定位置
        -->
    <bean id="typeDao" class="com.whl.dao.TypeDao"></bean>
    <bean id="userDao123" class="com.whl.dao.UserDao"></bean>

    <bean id="typeService" class="com.whl.service.TypeService">
        <constructor-arg name="typeDao" ref="typeDao"></constructor-arg>
        <constructor-arg name="name" value="zhangsan"></constructor-arg>
        <constructor-arg name="userDao" ref="userDao123" ></constructor-arg>
    </bean>

</beans>

App.java

package com.whl;

import com.whl.service.TypeService;
import com.whl.service.UserService;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Hello world!
 *
 */
public class App {
    public static void main( String[] args ) {
        // 获取Spring上下文环境 (加载配置文件)
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("spring2.xml");
        // 通过getBean方法得到Spring容器中实例化好的Bean对象 (实例化Bean对象)
        // userService代表的是配置文件中bean标签的id属性值
        TypeService typeService = (TypeService) ac.getBean("typeService");
        // 调用方法 (使用实例化对象)
        typeService.test();

    }
}

6.1.5. 注入方式的选择

开发项目中set方式注入首选

使用构造注入可以在构建对象的同时一并完成依赖关系的建立,对象一建立则所有的一切也就准备好

了,但如果要建立的对象关系很多,使用构造器注入会在构建函数上留下一长串的参数,且不易记忆,这时

使用Set注入会是个不错的选择。

使用Set注入可以有明确的名称,可以了解注入的对象会是什么,像setXXX()这样的名称会比记忆

Constructor上某个参数的位置代表某个对象更好。

p名称空间的使用

spring2.5以后,为了简化setter方法属性注入,引用p名称空间的概念,可以将 子元素,简化为元素

属性配置。

  • 属性字段提供 set 方法
  • 在配置文件 spring.xml 引入 p 名称空间
xmlns:p="http://www.springframework.org/schema/p"

代码实例(在set方法上改)

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

    <!--
            property  set注入
                name 指向属性名称(自动生成的set方法)
                ref 指向bean标签的id值  bean对象
                value 对应的是具体的值

        -->
    <bean id="userDao" class="com.whl.dao.UserDao"></bean>
    <bean id="userService" class="com.whl.service.UserService" p:port="8081" p:userDao-ref="userDao">
       <!-- <property name="userDao" ref="userDao"></property>
        <property name="port" value="8080"></property>
        <property name="name" value="张三"></property>-->

    </bean>
</beans>

6.2. Spring IOC 自动装配(注入)

注解方式注入 Bean

对于 bean 的注入,除了使用 xml 配置以外,可以使用注解配置。注解的配置,可以简化配置文件,

提高开发的速度,使程序看上去更简洁。对于注解的解释,Spring对于注解有专门的解释器,对定义的

注解进行解析,实现对应bean对象的注入。通过反射技术实现

6.2.1. 准备环境

修改配置文件

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

加入依赖

<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.4.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>javax.annotation</groupId>
      <artifactId>javax.annotation-api</artifactId>
      <version>1.3.2</version>
    </dependency>

开启自动化注入

<context:annotation-config/>

<bean id="accountDao" class="com.whl.annotation.AccountDao"></bean>
<bean id="accountService" class="com.whl.annotation.AccountService"></bean>

给注入的bean对象添加注解

6.2.2. @Resource注解

@Resource jdk11版本移除了这个属性 需要去单独引入对应的依赖,推荐使用**@Resource** 注解是属于J2EE的,减少了与Spring的耦合。

  • 默认会先通过属性/字段的名称 匹配 bean工厂中实例化后的对象 id唯一标识

  • 如果名称没有匹配到对应的对象,那么自动换成 类型class 匹配

  • set方法可有可无

  • 将注解放置在对应set上也可以注入

  • 如果注解使用配置了name属性,那么会强制用name的值去匹配 id的值,不会走类型class匹配

  • 当注入接口时,如果接口只有一个实现则正常实例化;如果接口存在多个实现,则需要使用name

    属性指定需要被实例化的bean对象

AccountDao

package com.whl.annotation;


public class AccountDao {
}

AccountService

package com.whl.annotation;

import com.whl.test.Factory;

import javax.annotation.Resource;

public class AccountService {

    @Resource
    //@Resource(name="accountDao1234")
    private AccountDao accountDao;
      @Resource
//    当注入接口时,如果接口只有一个实现则正常实例化;如果接口存在多个实现,则需要使用name
//    属性指定需要被实例化的bean对象
//    @Resource(name = "myFactory2")
    private Factory factory;
    //@Resource
    //set方法可有可无,将注解放置在对应set上也可以注入
    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    public void test(){
        System.out.println(accountDao);
        factory.print();
    }
}

Factory

package com.whl.test;

public interface Factory {

    public void print();
}

MyFactory1

package com.whl.test;


public class MyFactory1 implements Factory{

    @Override
    public void print() {
        System.out.println("工厂1");
    }
}

MyFactory2

package com.whl.test;


public class MyFactory2 implements Factory{

    @Override
    public void print() {
        System.out.println("工厂2");
    }
}

App

package com.whl;

import com.whl.annotation.AccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Hello world!
 */
public class App {
    public static void main(String[] args) {
       ApplicationContext ac = new ClassPathXmlApplicationContext("springAnnotation.xml");
        AccountService accountServicr = (AccountService) ac.getBean("accountService");
        accountServicr.test();
    }
}

springAnnotation.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"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <!--开启自动化装配(注入)-->
    <context:annotation-config/>

    <bean id="accountDao" class="com.whl.annotation.AccountDao"></bean>
<!--    如果名称没有匹配到对应的对象,那么自动换成 类型class 匹配-->
<!--    <bean id="accountDao1234" class="com.whl.annotation.AccountDao"></bean>-->
    <bean id="accountService" class="com.whl.annotation.AccountService"></bean>
    <bean id="myFactory1" class="com.whl.test.MyFactory1"></bean>
<!--    <bean id="myFactory2" class="com.whl.test.MyFactory2"></bean>-->

</beans>

pom.xml

<?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.whl</groupId>
  <artifactId>Spring04Annotation</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>Spring04Annotation</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.4.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>javax.annotation</groupId>
      <artifactId>javax.annotation-api</artifactId>
      <version>1.3.2</version>
    </dependency>
  </dependencies>

  <build>

  </build>
</project>

6.2.3. @Autowired注解

@Autowired注解实现自动化注入:

  • 默认通过类型(Class类型)查找bean对象 与属性字段的名称无关

  • 属性可以提供set方法,也可以不提供set方法

  • 注解可以声明在属性级别 或 set方法级别

  • 可以添加@Qualifier结合使用,通过value属性值查找bean对象(value属性值必须要设置,且值要与bean标签的id属性值对应)

7. Spring IOC 扫描器

实际的开发中,bean的数量非常多,采用手动配置bean的方式已无法满足生产需要,Spring这时候

同样提供了扫描的方式,对扫描到的bean对象统一进行管理,简化开发配置,提高开发效率。

7.1. Spring IOC 扫描器的配置

Spring IOC 扫描器 
	作用:bean对象统一进行管理,简化开发配置,提高开发效率 
	
	1、设置自动化扫描的范围 
		如果bean对象未在指定包范围,即使声明了注解,也无法实例化 
	2、使用指定的注解(声明在类级别) 
		bean对象的id属性默认是 类的首字母小写 
		Dao层:@Repository Service层: 
		@Service Controller层: 
		@Controller 任意类: 
		@Component 
		注:开发过程中建议按照指定规则声明注解,自动化扫描需要无参构造

设置自动化扫描范围

<?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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
        
        <!-- 设置自动化扫描的范围 --> 
        <context:component-scan base-package="com.yjxxt"/> 
      

使用特定的注解

  • @Repository (Dao层)
  • @Service(Service层 )
  • @Controller (Controller 层 )
  • @Component (任意层)

7.2. Spring 模拟用户登录流程

分层:

​ controller

​ 1.接收参数

​ 2.调用service层,返回基本信息

​ service

​ 2.校验参数 非空

​ 3.调用dao层查询数据库

​ 4.校验查询对象是否为空,可能没查到,返回数据

​ 5.比对密码,可能密码有误,返回数据

​ dao

​ 通过用户名查询数据,返回对象

7.2.1. 配置文件的加载

 <!--单元测试-->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>

    <!--spring 环境-->
    <dependency>
      <groupId>javax.annotation</groupId>
      <artifactId>javax.annotation-api</artifactId>
      <version>1.3.2</version>
    </dependency>

    <!--Resource注解-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.7.RELEASE</version>
    </dependency>

7.2.2 扫描器注入

spring.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"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <!--注解 注入!-->
    <context:annotation-config/>
    <!--扫描器-->
    <context:component-scan base-package="com.whl"></context:component-scan>

</beans>

7.2.3 Dao层 (查询用户记录)

定义JavaBean User.java

package com.whl.po;

public class User {
    private String uname;
    private String upwd;

    public String getUname() {
        return uname;
    }

    public void setUname(String uname) {
        this.uname = uname;
    }

    public String getUpwd() {
        return upwd;
    }

    public void setUpwd(String upwd) {
        this.upwd = upwd;
    }
}

编写Dao层 UserDao.java

package com.whl.dao;

import com.whl.po.User;
import org.springframework.stereotype.Repository;
//通过用户名查询数据,返回对象
@Repository
public class UserDao {
    private final String UNAME = "admin";
    private final String UPWD = "123456";

    /**
     *通过用户名查询对象信息
     * @param uname
     * @return
     */
    public User queryUserByUname(String uname){
        User user = null;
        if (!UNAME.equals(uname)){
            //数据未查到
            return user;
        }
        user = new User();
        user.setUname(UNAME);
        user.setUpwd(UPWD);
        return user;
    }
}

7.2.4 Service层 (业务逻辑处理)

定义业务处理返回消息模型 ResultInfo.java

package com.whl.po.vo;

public class ResultInfo {

    private Integer code=1;//0失败  1成功
    private String msg="success"; //提示语

    @Override
    public String toString() {
        return "ResultInfo{" +
                "code=" + code +
                ", msg='" + msg + '\'' +
                '}';
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}

编写Service层 UserService.java

package com.whl.service;

import com.whl.dao.UserDao;
import com.whl.po.User;
import com.whl.po.vo.ResultInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 *  service
 *         2.校验参数 非空
 *         3.调用dao层查询数据库
 *         4.校验查询对象是否为空,可能没查到,返回数据
 *         5.比对密码,可能密码有误,返回数据
 */
@Service
public class UserService {
    @Autowired
    private UserDao userDao;
    public ResultInfo LoginCheck(String uname,String upwd){

        //返回基本信息
        ResultInfo resultInfo = new ResultInfo();
        //参数非空校验
        if(uname==null || "".equals(uname.trim())){
            resultInfo.setCode(0);
            resultInfo.setMsg("用户名不能为空");
            return resultInfo;
        }
        if(upwd==null || "".equals(upwd.trim())){
            resultInfo.setCode(0);
            resultInfo.setMsg("密码不能为空");
            return resultInfo;
        }

        //查询数据库  调用dao
        User user = userDao.queryUserByUname(uname);
        //判断是否查询到了数据
        if(user==null){
            resultInfo.setCode(0);
            resultInfo.setMsg("用户名不存在,请注册");
            return resultInfo;
        }
        //校验密码  将用户输入的密码和数据库中的密码比对
        if(!user.getUpwd().equals(upwd)){
            resultInfo.setCode(0);
            resultInfo.setMsg("密码错误");
            return resultInfo;
        }
        return resultInfo;
    }
}

7.2.5 Controller层 (接收请求)

package com.whl.controller;

import com.whl.po.vo.ResultInfo;
import com.whl.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

/**
 * controller
 *         1.接收参数
 *         2.调用service层,返回基本信息
 */
@Controller
public class UserController {
    @Autowired
    private UserService userService;
    public ResultInfo Login(String uanme,String upwd){
        ResultInfo resultInfo = userService.LoginCheck(uanme, upwd);
        return resultInfo;
    }
}

**7.2.6 **通过 JUnit 进行测试

package com.whl;

import com.whl.controller.UserController;
import com.whl.po.vo.ResultInfo;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class LoginTest {
    @Test
    public void login(){
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
        UserController userController = (UserController) ac.getBean("userController");
        ResultInfo resultInfo = userController.Login("admin", "123456");
        System.out.println(resultInfo);
    }
}

8. Bean的作用域与生命周期

8.1. Bean的作用域

默认情况下,我们从Spring容器中拿到的对象均是单例的,对于bean的作用域类型如下:

8.1.1. singleton 作用域

在这里插入图片描述

注意: lazy-init是懒加载, 如果等于true时作用是指Spring容器启动的时候不会去实例化这个bean,

**是在程序调用时才去实例化. **默认是false即Spring容器启动时实例化.

默认情况下,被管理的bean只会IOC容器中存在一个实例,对于所有获取该Bean的操作Spring容器将

只返回同一个Bean。

**容器在启动的情况下就实例化所有singleton **的 bean对象,并缓存与容器中

lazy-init属性(懒加载)

如果为false,则在IOC容器启动时会实例化bean对象,默认false

如果为true,则IOC容器启动时不会实例化Bean对象,在使用bean对象时才会实例化

lazy-init设置为false有什么好处?

1)可以提前发现潜在的配置问题

2)Bean 对象存在于缓存中,使用时不用再去实例化bean,加快程序运行效率

 <bean id="userController" class="com.whl.controller.UserController" lazy-init="true"></bean>
<!--com.whl.controller.UserController@78452606
    com.whl.controller.UserController@78452606-->
 @Test
    public void sinTest(){
         ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");

         UserController userController1 = (UserController) ac.getBean("userController");

         UserController userController2 = (UserController) ac.getBean("userController");
         System.out.println(userController1);
         System.out.println(userController2);
    
    }

什么对象适合作为单例对象?

一般来说对于无状态或状态不可改变的对象适合使用单例模式。(不存在会改变对象状态的成员变

量)

比如:controller层、service层、dao层

什么是无状态或状态不可改变的对象?

实际上对象状态的变化往往均是由于属性值得变化而引起的,比如user类 姓名属性会有变化,属性姓

名的变化一般会引起user对象状态的变化。对于我们的程序来说,无状态对象没有实例变量的存在,保

证了线程的安全性,service 层业务对象即是无状态对象。线程安全的。

8.1.2. prototype 作用域

在这里插入图片描述

通过scope=“prototype” 设置bean的类型 ,每次向Spring容器请求获取Bean都返回一个全新的

Bean,相对于"singleton"来说就是不缓存Bean,每次都是一个根据Bean定义创建的全新Bean。

 <bean id="userController" class="com.whl.controller.UserController"  scope="prototype"></bean>
   <!-- com.whl.controller.UserController@78452606
    com.whl.controller.UserController@147e2ae7-->
 <bean id="userController" class="com.whl.controller.UserController"  scope="singleton"></bean>
    <!--com.whl.controller.UserController@78452606
    com.whl.controller.UserController@78452606-->

8.1.3. Web应用中的作用域

  1. request作用域

表示每个请求需要容器创建一个全新Bean。比如提交表单的数据必须是对每次请求新建一个Bean

来保持这些表单数据,请求结束释放这些数据。

  1. session作用域

表示每个会话需要容器创建一个全新Bean。比如对于每个用户一般会有一个会话,该用户的用户

信息需要存储到会话中,此时可以将该Bean作用域配置为session级别。

  1. globalSession作用域

类似于session作用域,其用于portlet(Portlet是基于Java的Web组件,由Portlet容器管理,并由容

器处理请求,生产动态内容)环境的web应用。如果在非portlet环境将视为session作用域。

配置方式和基本的作用域相同,只是必须要有web环境支持,并配置相应的容器监听器或拦截器从而

能应用这些作用域,目前先熟悉概念,后续集成web时讲解具体使用,大家只需要知道有这些作用域就

可以

8.2. Bean的生命周期

对比已经学过的servlet 生命周期(容器启动装载并实例化servlet类,初始化servlet,调用service方

法,销毁servlet)。

同样对于Spring容器管理的bean也存在生命周期的概念

在Spring中,Bean的生命周期包括Bean的定义、初始化、使用和销毁4个阶段

8.2.1. Bean的定义

在Spring中,通常是通过配置文档的方式来定义Bean的。

在一个配置文档中,可以定义多个Bean。

8.2.2. Bean 的初始化

默认在IOC容器加载时,实例化对象。

Spring bean 初始化有两种方式:

**方式一:**在配置文档中通过指定 init-method 属性来完成。

UserController.java

public class UserController {   

    public void init(){
        System.out.println("UserController....初始化");
    }
}

spring.xml

<bean id="userController" class="com.whl.controller.UserController"  init-method="init"></bean>

LoginTest.java

 @Test
    public void sinTest(){
        //如果加上lazy-init="true",则需在放开一行
         ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");

         /*UserController userController1 = (UserController) ac.getBean("userController");

         UserController userController2 = (UserController) ac.getBean("userController");
         System.out.println(userController1);
         System.out.println(userController2);*/
       
    }

方式二: 当前类实现 org.springframework.beans.factory.InitializingBean 接口。

UserController.java

public class UserController implements InitializingBean {
   
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("UserController....接口初始化");
    }
}

spring.xml

<bean id="userController" class="com.whl.controller.UserController" ></bean>

LoginTest.java

 @Test
    public void sinTest(){
        //如果加上lazy-init="true",则需在放开一行
         ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");

         /*UserController userController1 = (UserController) ac.getBean("userController");

         UserController userController2 = (UserController) ac.getBean("userController");
         System.out.println(userController1);
         System.out.println(userController2);*/
       
    }

Bean对象实例化过程是在Spring容器初始化时被实例化的,但也不是不可改变的,可以通过 lazy

init=“true” 属性延迟bean对象的初始化操作,此时再调用getBean 方法时才会进行bean的初始化操作

8.2.3. Bean 的使用

**方式一:**使用 BeanFactory

// 得到Spring的上下文环境 
BeanFactory factory = new ClassPathXmlApplicationContext("spring.xml"); 
RoleService roleService = (RoleService) factory.getBean("roleService");

**方式二:**使用 ApplicationContext

// 得到Spring的上下文环境
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
RoleService roleService = (RoleService) ac.getBean("roleService");

8.2.4. Bean的销毁

实现销毁方式(Spring容器会维护bean对象的管理,可以指定bean对象的销毁所要执行的方法)。

**步骤一:**实现销毁方式(Spring容器会维护bean对象的管理,可以指定bean对象的销毁所要执行的方

法)

<bean id="userController" class="com.whl.controller.UserController" destroy-method="destory"></bean>

**步骤二:**通过 AbstractApplicationContext 对象,调用其close方法实现bean的销毁过程

AbstractApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
ac.close();

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

spring IOC 的相关文章

随机推荐

  • postgreSQL离线安装(rpm包方式)

    1 下载pg的rpm包 https yum postgresql org 根据选择适合的版本 这里以centos7和pg13 0为例 下载好这四个rpm包 postgresql13 server 13 0 1PGDG rhel7 x86 6
  • 开心档-软件开发入门之MongoDB 高级索引

    作者简介 每天分享MongoDB教程的学习经验 和学习笔记 座右铭 有自制力 做事有始有终 学习能力强 愿意不断地接触学习新知识 个人主页 iOS开发上架的主页 前言 本章将会讲解在数组中创建索引 需要对数组中的每个字段依次建立索引 所以在
  • 按键实现顺序一次亮2个led,顺序一次灭2个led

    c语言实现编程 keil51 点亮led灯 学习记录 在以前的基础上实现按一下 亮俩个 按一下 灭俩个 解决一直存在的问题 1 char代表的首位为符号位 1为负数 0为正数 所以有效位数为7位 uchar不区分 直接就是8位 2 关于右移
  • 100天精通Python(基础篇)——第4天:数据类型

    作者介绍 Python领域优质创作者 数据开发工程师 励志成为Python全栈工程师 关注我发现更多精彩 本文已收录于Python全栈系列专栏 100天精通Python从入门到就业 欢迎订阅 订阅后可私聊进Python全栈VIP交流群 手把
  • Java 流

    Java 流 什么是流 流是一个相对抽象的概念 所谓流就是一个传输数据的通道 这个通道可以传输相应类型的数据 进而完成数据的传输 这个通道被实现为一个具体的对象 字符流和字节流 抽象类 处理字节 InputStream OutputStre
  • 心电图心电轴怎么计算_需要你拿小本本记下的知识点——教你怎么看懂心电图...

    心电图 相信大家都很熟悉 但是你是否能看懂心电图呢 攻略来啦 大家可以拿小本本记下来 推荐有点医学基础的人观看 了解一下心电图怎么看 也能对自己有所帮助 接下来就让我们开始吧 心电图的波形组成 见下图 基本知识 1 拿到一个心电图 先看基本
  • python 环境配置测试,手工照敲线性回归实战

    lesson013 linear regression py import numpy as np error for y wx b def compute error for line given points b w points to
  • nodejs --buffer模块(三) buffer的操作和属性

    全局方法 Buffer byteLength string encoding 返回字符串实际字节的长度 Buffer compare buf1 buf2 比较两个buffer的前后顺序 等价于buffer1 compare buf2 Buf
  • 【Qt教程】2.2 - Qt5 布局管理器(水平、垂直、栅格布局)、弹簧、设计一个登陆界面

    使用布局管理器 来设计一个登陆界面 都是操作 没代码没理论 参照 Qt设计一登陆窗口布局 1 新建空工程 双击 ui文件 进入界面设计区 我们新建工程时候 使用的是QMainWindow类 会自动包含菜单栏 状态栏 在右上角对象浏览器中 我
  • TeleGram都有哪些限制?

    账户 用户名 形如 TGgeek 5 32字符 用户名 username 有什么用 一定要设置吗 如何设置 名字长度 1 64字符 姓氏长度 0 64字符 账号自毁时限 如果账号在一定时间内不上线 到时限后会自动删除账号和所有资料 删除后不
  • visual studio:未能加载文件或程序集“xxx.dll”或它的某一个依赖项

    1 没有添加库目录或附加库目录 2 如果dll内部有错误 也会提示这个
  • 内联元素的padding和margin

    内联元素的padding和margin能设置上吗 这是我前段时间面试某中厂被问到的一道面试题 一开始有点懵 但照自己的理解是这样回答的 内联元素不能通过改变宽高来改变元素大小 只能通过内部撑开 padding设置不上 margin left
  • rand()查询效率问题解决

    随机从数据表中取一条数据 我们一般会用到rand 函数 但是如果用不好的话 rand 的效率实在太低 基础使用 SELECT FROM tablename ORDER BY RAND LIMIT 1 这是最基本的rand 用法 实例测试 我
  • 史上最全,Spring Boot入门篇总结,收藏起来慢慢看

    Spring Boot是Spring家族下的一个全新开发框架 其设计目的主要是用来简化Spring应用的创建及开发过程 它提供了自动配置 starter依赖等特性 从而使开发人员从大量的XML配置中解脱出来 Spring Boot致力于在蓬
  • mysql-批量更新

    方法一 用update结合case then实现 原始SQL语句 UPDATE baginfo 2021 09 SET channel id CASE id WHEN 1 THEN 3 WHEN 2 THEN 4 WHEN 3 THEN 5
  • 五分钟9步搞定nginx正向代理配置方法

    nginx在绝大数的场景中我们使用其用于做web中间件或反向代理使用 但是nginx实际上也提供了正向代理的功能 下面我们来进行nginx正向代理配置操作 以便大家能够掌握nginx正向代理配置方法 第一步 获取nginx正向代理模块 gi
  • 微信小程序---点餐小程序左侧滑动菜单实现

    文章目录 前言 一 初识scroll view 二 左侧导航 三 右侧滑动 前言 最近在帮亲戚做一款微信的点餐小程序 以前从没有接触过小程序的我只能现做现卖 一边看文档一边实践尝试 在进行到点菜模块左侧滑动菜单时遇到了小小的阻碍 索性在查找
  • ARM Mbed数字信号处理

    信号处理对于许多应用而言很重要 借助现代计算机的强大功能 许多信号处理功能现在都可以通过数字方式完成 本文 我们将说明如何使用Arm Mbed DSP库进行数字信号处理和控制 低通滤波器 在Arm Mbed 网站上 有关于如何设计和实现低通
  • 基于 LowCodeEngine 的低代码组件体系的建设和实践

    今天在这里和大家聊一聊前端组件 或者现在更流行的说法 物料 的话题 物料本身已经不是一个新鲜的话题了 从 06 年 jQuery 发布 前端物料就开始以各种 jQuery 插件的形式不断涌现 直到今天我们仍然可以在 github 上看到很多
  • spring IOC

    1 主要内容 2 Spring 框架 2 1 Spring 框架概念 Spring 是众多开源java项目中的一员 基于分层的javaEE应用一站式轻量级开源框架 主要核心是 IOC 控制反转 依赖注入 与 AOP 面向切面 两大技术 实现