关于spring:Spring-IOC

6次阅读

共计 38426 个字符,预计需要花费 97 分钟才能阅读完成。

Spring IOC

次要内容

Spring 框架

Spring 框架概念

​ Spring 是泛滥开源 java 我的项目中的一员,基于分层的 javaEE 利用一站式轻量级开源框架,次要外围是 IOC(管制反转 / 依赖注入)与 AOP(面向切面)两大技术,实现我的项目在开发过程中的轻松解耦,进步我的项目的开发效率。

​ 在我的项目中引入 Spring 立刻能够带来上面的益处 升高组件之间的耦合度, 实现软件各层之间的解耦。能够应用容器提供的泛滥服务,如:事务管理服务、音讯服务等等。当咱们应用容器治理事务时,开发人员就不再须要手工管制事务. 也不需解决简单的事务流传。容器提供单例模式反对,开发人员不再须要本人编写实现代码。容器提供了 AOP 技术,利用它很容易实现如权限拦挡、运行期监控等性能。

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,但提供了额定的性能,最出色的要数函数调用和简略字符串的模板函数。

  2. Spring-AOP:Spring-aop 是 Spring 的另一个外围模块, 在 Spring 中,他是以 JVM 的动静代理技术为根底,而后设计出了一系列的 Aop 横切实现,比方前置告诉、返回告诉、异样告诉等。通过其配置管理个性,Spring AOP 模块间接将面向切面的编程性能集成到了 Spring 框架中。所以,能够很容易地使 Spring 框架治理的任何对象反对 AOP。
  3. 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 等。

  4. Web 模块:由 Spring-web、Spring-webmvc、Spring-websocket 和 Spring-webmvc-portlet 4 个模块组成,Web 上下文模块建设在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。Web 模块还简化了解决多局部申请以及将申请参数绑定到域对象的工作。
  5. 报文发送:即 Spring-messaging 模块。

    Spring-messaging 是 Spring4 新退出的一个模块,主要职责是为 Spring 框架集成一些根底的报文传送利用。

  6. 单元测试:即 Spring-test 模块。Spring-test 模块次要为测试提供反对

Spring 框架环境搭建

环境要求

​ JDK 版本:

​ JDK 1.7 及以上版本

​ Spring 版本:

​ Spring 5.x 版本

新建 Maven 我的项目
  1. 创立 Maven 的一般 Java 我的项目
  2. 设置我的项目的坐标
  3. 设置我的项目的 Maven 环境
  4. 设置我的项目的名称和寄存的工作空间
调整我的项目环境
  1. 批改 JDK 版本

    <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <maven.compiler.source>1.8</maven.compiler.source>
      <maven.compiler.target>1.8</maven.compiler.target>
    </properties> 
  2. 批改单元测试 JUnit 版本

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency> 
  3. build 标签中的 pluginManagement 标签

    <!-- 删除 build 标签中的 pluginManagement 标签 -->
    <build>
    </build> 
增加 Spring 框架的依赖坐标

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

<!-- 增加 Spring 框架的外围依赖 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.4.RELEASE</version>
</dependency> 
编写 Bean 对象
package com.xxxx.service;

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

} 
增加 Spring 配置文件
  1. 在我的项目的 src 下创立文件夹 resources(Alt+insert)
  2. 将 resources 标记为资源目录
  3. 在 srcmainresources 目录下新建 spring.xml 文件,并拷贝官网文档提供的模板内容到 xml 中。

    配置 bean 到 xml 中,把对应 bean 纳入到 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.xxxx.service.UserService"></bean>
    
    </beans> 
  4. 在 spring.xml 中配置 Bean 对象

    <!--
            id:bean 对象的 id,惟一标识。个别是 Bean 对象的名称的首字母小写
            class:bean 对象的类门路
    -->
    <bean id="userService" class="com.xxxx.service.UserService"></bean> 
加载配置文件,获取实例化对象
package com.xxxx;

import com.xxxx.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

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

Spring IOC 容器 Bean 对象实例化模仿

思路:

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

定义 Bean 属性对象

package com.xxxx.spring;

/**
 * bean 对象
 *      用来接管配置文件中 bean 标签的 id 与 class 属性值
 */
public class MyBean {

    private String id; // bean 对象的 id 属性值
    private String clazz; // bean 对象的类门路

    public MyBean() {}

    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;}
} 

增加 dom4j 坐标依赖

<!-- 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> 

筹备自定义配置文件

spring.xml

<?xml version="1.0" encoding="utf-8" ?>
<beans>
    <bean id="userService" class="com.xxxx.service.UserService"></bean>
    <bean id="accountService" class="com.xxxx.service.AccountService"></bean>
</beans> 

定义 Bean 工厂接口

package com.xxxx.spring;

/**
 * Bean 工厂接口定义
 */
public interface MyFactory {
    // 通过 id 值获取对象
    public Object getBean(String id);
} 

定义 Bean 接口的实现类

package com.xxxx.spring;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.XPath;
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;

/**
 * 模仿 Spring 的实现
 *  1、通过结构器失去相干配置文件
 *  2、通过 dom4j 解析 xml 文件,失去 List   寄存 id 和 class
 *  3、通过反射实例化失去对象   Class.forName(类的全门路).newInstance(); 通过 Map<id,Class> 存储
 *  4、失去指定的实例化对象
 */
public class MyClassPathXmlApplicationContext implements BeanFactory {private Map beans = new HashMap(); // 实例化后的对象放入 map
    private List<MyBean> myBeans; // 寄存已读取 bean 配置信息

    /* 1、通过结构器失去相干配置文件 */
    public MyClassPathXmlApplicationContext(String fileName) {

        /* 2、通过 dom4j 解析 xml 文件,失去 List(寄存 id 和 class)*/
        this.parseXml(fileName);

        /* 3、通过反射实例化失去对象 Class.forName(类门路).newInstance();  通过 Map 存储 */
        this.instanceBean();}

    /**
     * 通过 dom4j 解析 xml 文件,失去 List   寄存 id 和 class
     *  1、获取解析器
     *  2、失去配置文件的 URL
     *  3、通过解析器解析 xml 文件(spring.xml)*  4、通过 xpath 语法,获取 beans 标签下的所有 bean 标签
     *  5、通过指定语法解析文档对象,返回汇合
     *  6、判断汇合是否为空,遍历汇合
     *  7、获取标签元素中的属性
     *  8、失去 Bean 对象,将 Bean 对象设置到汇合中
     * @param fileName
     */
    private void parseXml(String fileName) {
        // 1、获取解析器
        SAXReader reader = new SAXReader();
        // 2、失去配置文件的 URL
        URL url = this.getClass().getClassLoader().getResource(fileName);
        try {
            // 3、通过解析器解析 xml 文件(spring.xml)Document document = reader.read(url);
            // 4、通过 xpath 语法,获取 beans 标签下的所有 bean 标签
            XPath xPath = document.createXPath("beans/bean");
            // 通过指定语法解析文档对象,返回汇合
            List<Element> list = xPath.selectNodes(document);
            // 判断汇合是否为空,遍历汇合
            if (list != null && list.size() > 0) {myBeans = new ArrayList<>();
                for(Element el : list) {
                    // 获取标签元素中的属性
                    String id = el.attributeValue("id"); // id 属性值
                    String clazz = el.attributeValue("class"); // class 属性值
                    System.out.println(el.attributeValue("id"));
                    System.out.println(el.attributeValue("class"));
                    // 失去 Bean 对象
                    MyBean bean = new MyBean(id, clazz);
                    // 将 Bean 对象设置到汇合中
                    myBeans.add(bean);
                }
            }
        } catch (DocumentException e) {e.printStackTrace();
        }
    }

    /**
     * 通过反射实例化失去对象  
     *     Class.forName(类的全门路).newInstance();  
     *    通过 Map<id,Class> 存储
     */
    private void instanceBean() {
        // 判断 bean 汇合是否为空,不为空遍历失去对应 Bean 对象
        if (myBeans != null && myBeans.size() > 0) {for (MyBean bean : myBeans){                                      
                try {
                    // 通过类的全门路实例化对象
                    Object object = Class.forName(bean.getClazz()).newInstance();
                    // 将 id 与实例化对象设置到 map 对象中
                    beans.put(bean.getId(), object);
                } catch (Exception e) {e.printStackTrace();
                }
            }
        }
    }

    /**
     * 通过 key 获取 map 中的指定 value
     * @param id
     * @return
     */
    @Override
    public Object getBean(String id) {Object object = beans.get(id);
        return object;
    }
} 

测试自定义 IOC 容器

  1. 创立与配置文件中对应的 Bean 对象

    UserService.java

    package com.xxxx.service;
     
    public class UserService {public void test(){System.out.println("UserService Test...");
        }
    } 

    AccountService.java

    package com.xxxx.service;
    
    public class AccountService {public void test(){System.out.println("AccountService Test...");
        }
    } 
  2. 测试是否能够获取实例化的 Bean 对象

    package com.xxxx;
    
    import com.xxxx.spring.MyFactory;
    import com.xxxx.spring.MyClassPathXmlApplicationContext;
    import com.xxxx.service.AccountService;
    import com.xxxx.service.UserService;
    
    public class App {public static void main(String[] args) {MyFactory factory = new MyClassPathXmlApplicationContext("spring.xml");
            // 失去实例化对象
            UserService userService = (UserService) factory.getBean("userService");
            userService.test();
    
            UserService userService2 = (UserService) factory.getBean("userService");
            System.out.println(userService+"=====" + userService2);
    
            AccountService accountService = 
            (AccountService)factory.getBean("accountService");
            accountService.test();}
    } 

    ​ Spring 容器在启动的时候 读取 xml 配置信息,并对配置的 bean 进行实例化(这里模仿的比较简单,仅用于帮忙大家了解),同时通过上下文对象提供的 getBean() 办法拿到咱们配置的 bean 对象,从而实现内部容器自动化保护并创立 bean 的成果。

Spring IOC 配置文件加载

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">
    
    <bean id="userService" class="com.xxxx.service.UserService"></bean>
</beans> 
依据相对路径加载资源
ApplicationContext ac  = new ClassPathXmlApplicationContext("spring.xml"); 
依据绝对路径加载资源(理解)
ApplicationContext ac = new FileSystemXmlApplicationContext("C:/IdeaWorkspace/spring01/src/main/resources/spring.xml"); 

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">
    
    <bean id="userService" class="com.xxxx.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">
    
    <bean id="userDao" class="com.xxxx.dao.UserDao"></bean>
</beans> 
可变参数,传入多个文件名
// 同时加载多个资源文件
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml","dao.xml"); 
通过总的配置文件 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"); 

Spring IOC 容器 Bean 对象实例化

结构器实例化

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

  1. 设置配置文件 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">
    
        <bean id="userService" class="com.xxxx.service.UserService"></bean>
    
    </beans> 
  2. 获取实例化对象

    ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
    UserService userService = (UserService) ac.getBean("userService");  
    userService.test(); 

动态工厂实例化(理解)

注:

  • 要有该工厂类及工厂办法
  • 工厂办法为动态的
  1. 定义动态工厂类

    package com.xxxx.factory;
    
    import com.xxxx.service.UserService;
    
    /**
     * 定义动态工厂类
     */
    public class StaticFactory {
        /**
         * 定义对应的静态方法,返回实例化对象
         * @return
         */
        public static UserService createUserService() {return new UserService();
        }
    } 
  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"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <!-- 动态工厂 -->
        <bean id="userService" class="com.xxxx.factory.StaticFactory" factory-method="createUserService"></bean>
    
    </beans> 
  3. 获取实例化对象

    ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
    UserService userService = (UserService) ac.getBean("userService");  
    userService.test(); 

    ​ 当咱们指定 Spring 应用动态工厂办法来创立 Bean 实例时,Spring 将先解析配置文件,并依据配置文件指定的信息,通过反射调用动态工厂类的动态工厂办法,并将该动态工厂办法的返回值作为 Bean 实例 ,在这个过程中,Spring 不再负责创立 Bean 实例,Bean 实例是由用户提供的动态工厂办法提供 的。

实例化工厂实例化(理解)

注:

  • 工厂办法为非静态方法
  • 须要配置工厂 bean,并在业务 bean 中配置 factory-bean,factory-method 属性
  1. 定义工厂类

    package com.xxxx.factory;
    
    import com.xxxx.service.UserService;
    
    /**
     * 定义工厂类
     */
    public class InstanceFactory {
        /**
         * 定义方法,返回实例化对象
         * @return
         */
        public UserService createUserService() {return new UserService();
        }
    } 
  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"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <!--
            实例化工厂
                1. 定义实例化工厂 bean
                2. 援用工厂 bean 指定工厂创立办法(办法为非动态)
        -->
        <bean id="instanceFactory" class="com.xxxx.factory.InstanceFactory"></bean>
        <bean id="userService" factory-bean="instanceFactory" factory-method="createUserService"></bean>
    
    </beans> 
  3. 获取实例化对象

    ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
    UserService userService = (UserService) ac.getBean("userService");  
    userService.test(); 

Spring 三种实例化 Bean 的形式比拟

  • 形式一:通过 bean 的缺省构造函数创立,当各个 bean 的业务逻辑互相比拟独立的时候或者和外界关联较少的时候能够应用。
  • 形式二:利用动态 factory 办法创立,能够对立治理各个 bean 的创立,如各个 bean 在创立之前须要雷同的初始化解决,则可用这个 factory 办法险进行对立的解决等等。
  • 形式三:利用实例化 factory 办法创立,行将 factory 办法也作为了业务 bean 来管制,1 可用于集成其余框架的 bean 创立治理办法,2 可能使 bean 和 factory 的角色调换。

    开发中我的项目个别应用一种形式实例化 bean,我的项目开发根本采纳第一种形式,交给 Spring 托管,应用时间接拿来应用即可。另外两种理解

Spring IOC 注入

手动实例化与内部引入

图一:

图二:

​ 比照发现:图二中对于 UserDao 对象的创立并没有像图一那样被动的去实例化,而是通过带参办法模式将 UserDao 传入过去,从而实现 UserService 对 UserDao 类 的依赖。

而理论创建对象的幕后对象即是交给了内部来创立。

Spring IOC 手动拆卸(注入)

​ Spring 反对的注入形式共有四种:set 注入、结构器注入、动态工厂注入、实例化工厂注入。

set 办法注入

注:

  • 属性字段须要提供 set 办法
  • 四种形式,举荐应用 set 办法注入
业务对象 JavaBean
  1. 属性字段提供 set 办法

    public class UserService {
    
        // 业务对象 UserDao set 注入(提供 set 办法)private UserDao userDao;
        public void setUserDao(UserDao userDao) {this.userDao = userDao;}
    } 
  2. 配置文件的 bean 标签设置 property 标签

    <?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">
        
       <!--
            IOC 通过 property 标签手动拆卸(注入):Set 办法注入
                    name:bean 对象中属性字段的名称
                    ref:指定 bean 标签的 id 属性值
        --> 
        <bean id="userDao" class="com.xxxx.dao.UserDao"></bean>
        <bean id="userService" class="com.xxxx.service.UserService">
            <!-- 业务对象 注入 -->
            <property name="userDao" ref="userDao"/>
        </bean>
    </beans> 
罕用对象和根本类型
  1. 属性字段提供 set 办法

    public class UserService {
    
        // 罕用对象 String  set 注入(提供 set 办法)private String host;
        public void setHost(String host) {this.host = host;}
    
        // 根本类型 Integer   set 注入(提供 set 办法)private Integer port;
        public void setPort(Integer port) {this.port = port;}
    } 
  2. 配置文件的 bean 标签设置 property 标签

    <?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">
        
       <!--
            IOC 通过 property 标签手动拆卸(注入):Set 办法注入
                    name:bean 对象中属性字段的名称
                    value: 具体的值(根本类型 罕用对象 | 日期  汇合)--> 
        <bean id="userService" class="com.xxxx.service.UserService">
            <!-- 罕用对象 String 注入 -->
            <property name="host" value="127.0.0.1"/>
            <!-- 根本类型注入 -->
            <property name="port" value="8080"/>
        </bean>
    
    </beans> 
汇合类型和属性对象
  1. 属性字段提供 set 办法

    public class UserService {
    
        // List 汇合  set 注入(提供 set 办法)public List<String> list;
        public void setList(List<String> list) {this.list = list;}
       
    
        // Set 汇合  set 注入(提供 set 办法)private Set<String> set;
        public void setSet(Set<String> set) {this.set = set;}
    
        // Map set 注入(提供 set 办法)private Map<String,Object> map;
        public void setMap(Map<String, Object> map) {this.map = map;}
        
    
        // Properties set 注入(提供 set 办法)private Properties properties;
        public void setProperties(Properties properties) {this.properties = properties;}
       
    } 
  2. 配置文件的 bean 标签设置 property 标签

    <?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">
        
       <!--
            IOC 通过 property 标签手动拆卸(注入):Set 办法注入
                    name:bean 对象中属性字段的名称
                    value: 具体的值(根本类型 罕用对象 | 日期  汇合)--> 
        <!--List 汇合 注入 -->
        <property name="list">
            <list>
                <value> 上海 </value>
                <value> 北京 </value>
                <value> 杭州 </value>
            </list>
        </property>
    
        <!--Set 汇合注入 -->
        <property name="set">
            <set>
                <value> 上海 SH</value>
                <value> 北京 BJ</value>
                <value> 杭州 HZ</value>
            </set>
        </property>
    
        <!--Map 注入 -->
        <property name="map">
            <map>
                <entry>
                    <key><value> 周杰伦 </value></key>
                    <value> 我是如此置信 </value>
                </entry>
                <entry>
                    <key><value> 林俊杰 </value></key>
                    <value> 惋惜没如果 </value>
                </entry>
                <entry>
                    <key><value> 陈奕迅 </value></key>
                    <value> 十年 </value>
                </entry>
            </map>
        </property>
    
        <!--Properties 注入 -->
        <property name="properties">
            <props>
                <prop key="上海"> 东方明珠 </prop>
                <prop key="北京"> 天安门 </prop>
                <prop key="杭州"> 西湖 </prop>
            </props>
        </property>
    
    </beans> 
测试代码

UserService.java

public class UserService {

    // 业务对象 UserDao set 注入(提供 set 办法)private UserDao userDao;
    public void setUserDao(UserDao userDao) {this.userDao = userDao;}

    // 罕用对象 String  set 注入(提供 set 办法)private String host;
    public void setHost(String host) {this.host = host;}

    // 根本类型 Integer   set 注入(提供 set 办法)private Integer port;
    public void setPort(Integer port) {this.port = port;}

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

    // Set 汇合  set 注入(提供 set 办法)private Set<String> set;
    public void setSet(Set<String> set) {this.set = set;}
    // Set 汇合输入
    public void printSet() {set.forEach(s -> System.out.println(s));
    }

    // Map set 注入(提供 set 办法)private Map<String,Object> map;
    public void setMap(Map<String, Object> map) {this.map = 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;}
    // Properties 输入
    public  void printProperties(){properties.forEach((k,v) -> System.out.println(k + ","+ v));
    }

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

        userDao.test();

        studentDao.test();

        System.out.println("Host:" + host  + ",port:" + port);

        // List 汇合
        printList();

        // Set 汇合
        printSet();

        // Map
        printMap();

        // Properties
        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">
    
    <!--
        IOC 通过 property 标签手动拆卸(注入):Set 办法注入
                name:bean 对象中属性字段的名称
                ref:指定 bean 标签的 id 属性值
                value: 具体的值(根本类型 罕用对象 | 日期  汇合)-->
    <bean id="userDao" class="com.xxxx.dao.UserDao"></bean>
    <bean id="userService" class="com.xxxx.service.UserService">
        <!-- 业务对象 注入 -->
        <property name="userDao" ref="userDao"/>
        <property name="studentDao" ref="studentDao"/>

        <!-- 罕用对象 String 注入 -->
        <property name="host" value="192.168.1.109"/>
        <!-- 根本类型注入 -->
        <property name="port" value="8080"/>

        <!--List 汇合 注入 -->
        <property name="list">
            <list>
                <value> 上海 </value>
                <value> 北京 </value>
                <value> 杭州 </value>
            </list>
        </property>

        <!--Set 汇合注入 -->
        <property name="set">
            <set>
                <value> 上海 SH</value>
                <value> 北京 BJ</value>
                <value> 杭州 HZ</value>
            </set>
        </property>

        <!--Map 注入 -->
        <property name="map">
            <map>
                <entry>
                    <key><value> 周杰伦 </value></key>
                    <value> 我是如此置信 </value>
                </entry>
                <entry>
                    <key><value> 林俊杰 </value></key>
                    <value> 惋惜没如果 </value>
                </entry>
                <entry>
                    <key><value> 陈奕迅 </value></key>
                    <value> 十年 </value>
                </entry>
            </map>
        </property>

        <!--Properties 注入 -->
        <property name="properties">
            <props>
                <prop key="上海"> 东方明珠 </prop>
                <prop key="北京"> 天安门 </prop>
                <prop key="杭州"> 西湖 </prop>
            </props>
        </property>

    </bean>
    
</beans> 
结构器注入

注:

  • 提供带参结构器
单个 Bean 对象作为参数

Java 代码

public class UserService {

    private UserDao userDao; // JavaBean 对象
    
    public UserService(UserDao userDao) {this.userDao = userDao;}

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

        userDao.test();}

} 

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">
    <!--
        IOC 通过结构器注入:通过 constructor-arg 标签进行注入
                name:属性名称
                ref:指定 bean 标签的 id 属性值
    -->
    <bean id="userDao" class="com.xxxx.dao.UserDao" ></bean>
    
    <bean id="userService" class="com.xxxx.service.UserService">
        <constructor-arg name="userDao" ref="userDao"></constructor-arg> 
    </bean>

</beans> 
多个 Bean 对象作为参数

Java 代码

public class UserService {

    private UserDao userDao;  // JavaBean 对象
    private AccountDao accountDao  // JavaBean 对象
        
    public UserService(UserDao userDao, AccountDao accountDao) {
        this.userDao = userDao;
        this.accountDao = accountDao;
    }

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

        userDao.test();
        accountDao.test();}

} 

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">
     <!--
        IOC 通过结构器注入:通过 constructor-arg 标签进行注入
                name:属性名称
                ref:指定 bean 标签的 id 属性值
    -->
    <bean id="userDao" class="com.xxxx.dao.UserDao" ></bean>
    <bean id="accountDao" class="com.xxxx.dao.AccountDao" ></bean>
    
    <bean id="userService" class="com.xxxx.service.UserService">
        <constructor-arg name="userDao" ref="userDao"></constructor-arg> 
        <constructor-arg name="accountDao" ref="accountDao"></constructor-arg>
    </bean>

</beans> 
Bean 对象和罕用对象作为参数

Java 代码

public class UserService {

    private UserDao userDao;  // JavaBean 对象
    private AccountDao accountDao;  // JavaBean 对象
    private String uname;  // 字符串类型
        
    public UserService(UserDao userDao, AccountDao accountDao, String uname) {
        this.userDao = userDao;
        this.accountDao = accountDao;
        this.uname = uname;
    }

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

        userDao.test();
        accountDao.test();
        System.out.println("uname:" + uname);
    }

} 

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">
    <!--
        IOC 通过结构器注入:通过 constructor-arg 标签进行注入
                name:属性名称
                ref:指定 bean 标签的 id 属性值
                 value:根本类型 罕用对象的值
                index:结构器中参数的下标,从 0 开始
    -->
    <bean id="userDao" class="com.xxxx.dao.UserDao" ></bean>
    <bean id="accountDao" class="com.xxxx.dao.AccountDao" ></bean>
    <bean id="userService" class="com.xxxx.service.UserService">
        <constructor-arg name="userDao" ref="userDao"></constructor-arg> 
        <constructor-arg name="accountDao" ref="accountDao"></constructor-arg>
        <constructor-arg name="uname" value="admin"></constructor-arg>
    </bean>

</beans> 
循环依赖问题

循环问题产生的起因:

​ Bean 通过结构器注入,之间彼此相互依赖对方导致 bean 无奈实例化。

问题展现:

  1. Java 代码

    public class AccountService {
    
        private RoleService roleService;
    
       public AccountService(RoleService roleService) {this.roleService = roleService;}
    
        public void  test() {System.out.println("AccountService Test...");
        }
    }
    
    public class RoleService {
    
        private AccountService accountService;
    
       public RoleService(AccountService accountService) {this.accountService = accountService;}
    
        public void  test() {System.out.println("RoleService Test...");
        }
    } 
  2. XML 配置

    <!--
         如果多个 bean 对象中相互注入,则会呈现循环依赖的问题
         能够通过 set 办法注入解决
    -->
    <bean id="accountService" class="com.xxxx.service.AccountService">
        <constructor-arg name="roleService" ref="roleService"/>
    </bean>
    
    <bean id="roleService" class="com.xxxx.service.RoleService">
        <constructor-arg name="accountService" ref="accountService"/>
    </bean> 

如何解决:将结构器注入改为 set 办法注入

  1. Java 代码

    public class AccountService {
    
        private RoleService roleService;
    
       /* public AccountService(RoleService roleService) {this.roleService = roleService;}*/
    
        public void setRoleService(RoleService roleService) {this.roleService = roleService;}
    
        public void  test() {System.out.println("AccountService Test...");
        }
    }
    
    public class RoleService {
    
        private AccountService accountService;
    
       /* public RoleService(AccountService accountService) {this.accountService = accountService;}*/
    
        public void setAccountService(AccountService accountService) {this.accountService = accountService;}
    
        public void  test() {System.out.println("RoleService Test...");
        }
    } 
  2. XML 配置

    <!--
        <bean id="accountService" class="com.xxxx.service.AccountService">
        <constructor-arg name="roleService" ref="roleService"/>
        </bean>
    
        <bean id="roleService" class="com.xxxx.service.RoleService">
            <constructor-arg name="accountService" ref="accountService"/>
        </bean>
    -->
    <!-- 批改为 set 办法注入 -->
    <bean id="accountService" class="com.xxxx.service.AccountService">
        <property name="roleService" ref="roleService"/>
    </bean>
    
    <bean id="roleService" class="com.xxxx.service.RoleService">
        <property name="accountService" ref="accountService"/>
    </bean> 
动态工厂注入
  1. 定义动态工厂类

    public class StaticFactory {
    
        // 定义静态方法
        public static TypeDao createTypeDao() {return new TypeDao();
        }
    } 
  2. Java 代码

    public class TypeService {
    
        private TypeDao typeDao;
        
        public void setTypeDao(TypeDao typeDao) {this.typeDao = typeDao;}
    
        public void  test() {System.out.println("TypeService Test...");
        }
    } 
  3. XML 配置

    在配置文件中设置 bean 标签,指定工厂对象并设置对应的办法

    <bean id="typeService" class="com.xxxx.service.TypeService">
        <property name="typeDao" ref="typeDao"/>
    </bean>
    <!--
        动态工厂注入:动态工厂注入也是借助 set 办法注入,只是被注入的 bean 对象的实例化是通过动态工厂实例化的
    -->
    <bean id="typeDao" class="com.xxxx.factory.StaticFactory" factory-method="createTypeDao"></bean> 
实例化工厂注入
  1. 定义工厂类

    public class InstanceFactory {public TypeDao createTypeDao() {return new TypeDao();
        }
    } 
  2. Java 代码

    public class TypeService {
    
        private TypeDao typeDao;
        
        public void setTypeDao(TypeDao typeDao) {this.typeDao = typeDao;}
    
        public void  test() {System.out.println("TypeService Test...");
        }
    } 
  3. XML 配置

    申明工厂 bean 标签,申明 bean 对象,指明工厂对象和工厂办法

    <bean id="typeService" class="com.xxxx.service.TypeService">
        <property name="typeDao" ref="typeDao"/>
    </bean>
    <!--
        实例化工厂注入:实例化工厂注入也是借助 set 办法注入,只是被注入的 bean 对象的实例化是通过实例化工厂实例化的
    -->
    <bean id="instanceFactory" class="com.xxxx.factory.InstanceFactory"></bean>
    <bean id="typeDao" factory-bean="instanceFactory" factory-method="createTypeDao"></bean> 

    重点把握 set 注入和结构器注入,工厂形式理解即可。理论开发中根本应用 set 形式注入 bean。

注入形式的抉择

开发我的项目中 set 形式注入首选

​ 应用结构注入能够在构建对象的同时一并实现依赖关系的建设,对象一建设则所有的所有也就筹备好了,但如果要建设的对象关系很多,应用结构器注入会在构建函数上留下一长串的参数, 且不易记忆, 这时应用 Set 注入会是个不错的抉择。
应用 Set 注入能够有明确的名称,能够理解注入的对象会是什么,像 setXXX()这样的名称会比记忆 Constructor 上某个参数的地位代表某个对象更好。

p 名称空间的应用

​ spring2.5 当前,为了简化 setter 办法属性注入,援用 p 名称空间的概念,能够将 子元素,简化为元素属性配置。

  1. 属性字段提供 set 办法

    public class UserService {
    
        // 业务对象 UserDao set 注入(提供 set 办法)private UserDao userDao;
        public void setUserDao(UserDao userDao) {this.userDao = userDao;}
        
        // 罕用对象 String  set 注入(提供 set 办法)private String host;
        public void setHost(String host) {this.host = host;}
    } 
  2. 在配置文件 spring.xml 引入 p 名称空间

    xmlns:p="http://www.springframework.org/schema/p" 
    <?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">
        
        <bean id="userDao" class="com.xxxx.dao.UserDao"></bean>
        <!--
            p: 属性名:="xxx"        引入常量值
            p: 属性名 -ref:="xxx"    引入其余 Bean 对象的 id 属性值
        -->
        <bean id="userService" class="com.xxxx.service.UserService" 
            p:userDao-ref="userDao" 
            p:host="127.0.0.1" />
    
    </beans> 

Spring IOC 主动拆卸(注入)

注解形式注入 Bean

​ 对于 bean 的注入,除了应用 xml 配置以外,能够应用注解配置。注解的配置,能够简化配置文件,进步开发的速度,使程序看上去更简洁。对于注解的解释,Spring 对于注解有专门的解释器,对定义的注解进行解析,实现对应 bean 对象的注入。通过 反射技术实现

筹备环境
  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"> 
  2. 开启自动化注入

    <!-- 开启自动化拆卸(注入)-->
    <context:annotation-config/>
    
    <bean id="userDao" class="com.xxxx.dao.UserDao"></bean>
    <bean id="userService" class="com.xxxx.service.UserService"></bean> 
  3. 给注入的 bean 对象增加注解
@Resource 注解

@Resource 注解实现主动注入(反射)

  • 默认依据属性字段名称查找对应的 bean 对象(属性字段的名称与 bean 标签的 id 属性值相等)
  • 如果属性字段名称未找到,则会通过类型(Class 类型)查找
  • 属性能够提供 set 办法,也能够不提供 set 办法
  • 注解能够申明在属性级别 或 set 办法级别
  • 能够设置 name 属性,name 属性值必须与 bean 标签的 id 属性值统一;如果设置了 name 属性值,就只会依照 name 属性值查找 bean 对象
  • 当注入接口时,如果接口只有一个实现则失常实例化;如果接口存在多个实现,则须要应用 name 属性指定须要被实例化的 bean 对象

代码示例

  1. 默认依据属性字段名称查找对应的 bean 对象(属性字段的名称与 bean 标签的 id 属性值相等)

    /**
     * @Resource 注解实现主动注入(反射)*  默认依据属性字段名称查找对应的 bean 对象(属性字段的名称与 bean 标签的 id 属性值相等)*/
    public class UserService {
    
        @Resource
        private UserDao userDao; // 属性字段的名称与 bean 标签的 id 属性值相等
    
        public void setUserDao(UserDao userDao) {this.userDao = userDao;}
    
        public void test() {
            // 调用 UserDao 的办法
            userDao.test();}
    } 
  2. 如果属性字段名称未找到,则会通过类型(Class 类型)查找

    /**
     * @Resource 注解实现主动注入(反射)*   如果属性字段名称未找到,则会通过类型(Class 类型)查找
     */
    public class UserService {
    
        @Resource
        private UserDao ud; // 当在配置文件中属性字段名(ud)未找到,则会查找对应的 class(UserDao 类型)public void setUd(UserDao ud) {this.ud = ud;}
    
        public void test() {
            // 调用 UserDao 的办法
            ud.test();}
    } 
  3. 属性能够提供 set 办法,也能够不提供 set 办法

    /**
     * @Resource 注解实现主动注入(反射)*   属性能够提供 set 办法,也能够不提供 set 办法
     */
    public class UserService {
    
        @Resource
        private UserDao userDao; // 不提供 set 办法
    
        public void test() {
            // 调用 UserDao 的办法
            userDao.test();}
    } 
  4. 注解能够申明在属性级别 或 set 办法级别

    /**
     * @Resource 注解实现主动注入(反射)*   注解能够申明在属性级别 或 set 办法级别
     */
    public class UserService {
    
        private UserDao userDao;
    
        @Resource // 注解也可设置在 set 办法上
        public void setUserDao(UserDao userDao) {this.userDao = userDao;}
    
        public void test() {
            // 调用 UserDao 的办法
            userDao.test();}
    } 
  5. 能够设置 name 属性,name 属性值必须与 bean 标签的 id 属性值统一;如果设置了 name 属性值,就只会依照 name 属性值查找 bean 对象

    /**
     * @Resource 注解实现主动注入(反射)*   能够设置 name 属性,name 属性值必须与 bean 的 id 属性值统一;*   如果设置了 name 属性值,就只会依照 name 属性值查找 bean 对象
     */
    public class UserService {@Resource(name = "userDao") // name 属性值与配置文件中 bean 标签的 id 属性值统一
        private UserDao ud;
    
        public void test() {
            // 调用 UserDao 的办法
            ud.test();}
    } 
  6. 当注入接口时,如果接口只有一个实现则失常实例化;如果接口存在多个实现,则须要应用 name 属性指定须要被实例化的 bean 对象

    定义接口类 IUserDao.java

    package com.xxxx.dao;
    
    /**
     * 定义接口类
     */
    public interface IUserDao {public void test();
    } 

    定义接口实现类 UserDao01.java

    package com.xxxx.dao;
    
    /**
     * 接口实现类
     */
    public class UserDao01 implements IUserDao {
    
        @Override
        public void test(){System.out.println("UserDao01...");
        }
    } 

    定义接口实现类 UserDao02.java

    package com.xxxx.dao;
    
    /**
     * 接口实现类
     */
    public class UserDao02 implements IUserDao {
    
        @Override
        public void test(){System.out.println("UserDao02...");
        }
    } 

    XML 配置文件

    <!-- 开启自动化拆卸(注入)-->
    <context:annotation-config/>
    
    <bean id="userService" class="com.xxxx.service.UserService"></bean>
    
    <bean id="userDao01" class="com.xxxx.dao.UserDao01"></bean>
    <bean id="userDao02" class="com.xxxx.dao.UserDao01"></bean> 

    应用注解 UserService.java

    /**
     * @Resource 注解实现主动注入(反射)*   当注入接口时,如果接口只有一个实现则失常实例化;如果接口存在多个实现,则须要应用 name 属性指定须要被实例化的 bean 对象
     */
    public class UserService {@Resource(name = "userDao01") // name 属性值与其中一个实现类的 bean 标签的 id 属性值统一
        private IUserDao iUserDao; // 注入接口(接口存在多个实现)public void test() {iUserDao.test();
        }
    } 
@Autowired 注解

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

  • 默认通过类型(Class 类型)查找 bean 对象 与属性字段的名称无关
  • 属性能够提供 set 办法,也能够不提供 set 办法
  • 注解能够申明在属性级别 或 set 办法级别
  • 能够增加 @Qualifier 联合应用,通过 value 属性值查找 bean 对象(value 属性值必须要设置,且值要与 bean 标签的 id 属性值对应)
  1. 默认通过类型(Class 类型)查找 bean 对象 与属性字段的名称无关

    /**
     * @Autowired 注解实现自动化注入
     *  默认通过类型(Class 类型)查找 bean 对象   与属性字段的名称无关
     */
    public class UserService {
    
        @Autowired
        private UserDao userDao; // 默认通过类型(Class 类型)查找 bean 对象  与属性字段的名称无关
    
        public void setUserDao(UserDao userDao) {this.userDao = userDao;}
    
        public void test() {
            // 调用 UserDao 的办法
            userDao.test();}
    } 
  2. 属性能够提供 set 办法,也能够不提供 set 办法

    /**
     * @Autowired 注解实现自动化注入
     *  属性能够提供 set 办法,也能够不提供 set 办法
     */
    public class UserService {
    
        @Autowired
        private UserDao userDao; // 不提供 set 办法
    
        public void test() {
            // 调用 UserDao 的办法
            userDao.test();}
    } 
  3. 注解能够申明在属性级别 或 set 办法级别

    /**
     * @Autowired 注解实现自动化注入
     *  注解能够申明在属性级别 或 set 办法级别
     */
    public class UserService {
    
        private UserDao userDao; 
    
        @Autowired// 注解能够申明在 set 办法级别
        public void setUserDao(UserDao userDao) {this.userDao = userDao;}
    
        public void test() {
            // 调用 UserDao 的办法
            userDao.test();}
    } 
  4. 能够增加 @Qualifier 联合应用,通过 value 属性值查找 bean 对象(value 属性值必须要设置,且值要与 bean 标签的 id 属性值对应)

    /**
     * @Autowired 注解实现自动化注入
     *  能够增加 @Qualifier 联合应用,通过 value 属性值查找 bean 对象
             value 属性值必须要设置,且值要与 bean 标签的 id 属性值对应
     */
    public class UserService {
    
        @Autowired
        @Qualifier(value="userDao") // value 属性值必须要设置,且值要与 bean 标签的 id 属性值对应
        private UserDao userDao;
    
        public void test() {userDao.test();
        }
    } 

    举荐应用@Resource 注解是属于 J2EE 的,缩小了与 Spring 的耦合。

Spring IOC 扫描器

​ 理论的开发中,bean 的数量十分多,采纳手动配置 bean 的形式已无奈满足生产须要,Spring 这时候同样提供了扫描的形式,对扫描到的 bean 对象对立进行治理,简化开发配置,进步开发效率。

Spring IOC 扫描器的配置

Spring IOC 扫描器
   作用:bean 对象对立进行治理,简化开发配置,进步开发效率

   1、设置自动化扫描的范畴
            如果 bean 对象未在指定包范畴,即便申明了注解,也无奈实例化
   2、应用指定的注解(申明在类级别)bean 对象的 id 属性默认是 类的首字母小写
         Dao 层:@Repository
         Service 层:@Service
         Controller 层:@Controller
         任意类:@Component
    注:开发过程中倡议依照指定规定申明注解 
  1. 设置自动化扫描范畴

    <?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.xxxx"/>
    
    </beans> 
  2. 应用特定的注解

    @Repository(Dao 层)

    @Repository
    public class ResourceDao {public void  test() {System.out.println("ResourceDao...");
        }
    } 

    @Service(Service 层)

    @Service
    public class ResourceService {
    
        @Resource
        private ResourceDao resourceDao; // service 层注入 dao 层的 bean 对象
    
        public  void  test() {System.out.println("ResourceService...");
            resourceDao.test();}
    } 

    @Controller(Controller 层)

    @Controller
    public class ResourceController {
    
        @Autowired
        private ResourceService resourceService; // Controller 层注入 service 层的 bean 对象
    
        public  void  test() {System.out.println("ResourceController...");
            resourceService.test();}
    } 

    @Component(任意层)

    @Component
    public class PropertyUtils {public void test(){System.out.println("PropertyUtils...");
        }
    } 

Spring 模仿用户登录流程

Dao 层(查问用户记录)
  1. 定义 JavaBean User.java

    package com.xxxx.po;
    
    /**
     * User 用户实体类
     */
    public class User {
    
        private String userName; // 用户名称
        private String userPwd; // 用户明码
    
        public String getUserName() {return userName;}
    
        public void setUserName(String userName) {this.userName = userName;}
    
        public String getUserPwd() {return userPwd;}
    
        public void setUserPwd(String userPwd) {this.userPwd = userPwd;}
    } 
  2. 编写 Dao 层 UserDao.java

    package com.xxxx.dao;
    
    import com.xxxx.po.User;
    import org.springframework.stereotype.Repository;
    
    @Repository
    public class UserDao {
        
        private final String USERNAME = "admin";
        private final String USERPWD = "admin";
        
        /**
         * 通过用户名称查问用户对象
         * @param userName
         * @return
         */
        public User queryUserByUserName(String userName){
            User user = null;
            // 判断用户名称是否正确
            if(!USERNAME.equals(userName)){
                // 如果不正确,返回 null
                return null;
            }
            // 如果正确,将用户名称和明码设置到 user 对象中
            user = new User();
            user.setUserName(USERNAME);
            user.setUserPwd(USERPWD);
    
            return user;
        }
    } 
Service 层(业务逻辑解决)
  1. 定义业务解决返回音讯模型 MessageModel.java

    package com.xxxx.po.vo;
    
    /**
     * 定义业务解决返回音讯模型
     *     封装返回后果
     */
    public class MessageModel {
    
        private Integer resultCode = 1; // 后果状态码  1= 胜利,0= 失败
        private String resultMsg = "操作胜利!"; // 后果提示信息
    
        public Integer getResultCode() {return resultCode;}
    
        public void setResultCode(Integer resultCode) {this.resultCode = resultCode;}
    
        public String getResultMsg() {return resultMsg;}
    
        public void setResultMsg(String resultMsg) {this.resultMsg = resultMsg;}
    } 
  2. 编写 Service 层 UserService.java

    package com.xxxx.service;
    
    import com.xxxx.dao.UserDao1;
    import com.xxxx.po.User;
    import com.xxxx.po.vo.MessageModel;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    
    @Service
    public class UserService {
        @Resource
        private UserDao userDao;
    
        /**
         * 验证用户登录
         * @param userName
         * @param userPwd
         * @return
         */
        public MessageModel userLoginCheck(String userName, String userPwd){
            // 定义业务解决返回音讯模型
            MessageModel messageModel = new MessageModel();
            // 判断用户名称是否非空
            if(null == userName || "".equals(userName.trim())){messageModel.setResultCode(0);
                messageModel.setResultMsg("用户名不能为空!");
                return messageModel;
            }
            // 判断用户明码是否为空
            if(null == userPwd || "".equals(userPwd.trim())){messageModel.setResultCode(0);
                messageModel.setResultMsg("明码不能为空!");
                return messageModel;
            }
            // 通过用户名称查问用户对象
            User user = userDao.queryUserByUserName(userName);
            // 判断用户对象是否为空
            if(null == user){messageModel.setResultCode(0);
                messageModel.setResultMsg("该用户不存在!");
                return messageModel;
            }
            // 如果用户对象不为空,判断明码是否正确
            if(!user.getUserPwd().equals(userPwd)){messageModel.setResultCode(0);
                messageModel.setResultMsg("用户明码不正确!");
                return messageModel;
            }
            // 登录胜利
            messageModel.setResultMsg("登录胜利!");
            
            return messageModel;
        }
    } 
Controller 层(接管申请)
  1. 编写 Controller 层 UserController.java

    package com.xxxx.controller;
    
    import com.xxxx.po.vo.MessageModel;
    import com.xxxx.service.UserService1;
    import org.springframework.stereotype.Controller;
    
    import javax.annotation.Resource;
    
    @Controller
    public class UserController {
        @Resource
        private UserService userService;
    
        /**
         * 用户登录
         * @param userName
         * @param userPwd
         * @return
         */
        public MessageModel login(String userName, String userPwd){
            // 调用 Dao 层判断用户登录操作,返回后果
            MessageModel messageModel = userService.userLoginCheck(userName, userPwd);
            return messageModel;
        }
    } 
通过 JUnit 进行测试
package com.xxxx;

import com.xxxx.controller.UserController;
import com.xxxx.po.vo.MessageModel;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestLogin {

    @Test
    public void test() {
        // 失去 Spring 容器上下文环境
        ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
        // 失去 UserController 实例化对象
        UserController userController = (UserController) ac.getBean("userController");
        // 传入参数调用 UserController 的办法,返回封装类
        MessageModel messageModel= userController.login("admin", "admin");

        System.out.println("状态码:" + messageModel.getResultCode() + ",提示信息:" + messageModel.getResultMsg());
    }
} 

Bean 的作用域与生命周期

Bean 的作用域

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

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,放慢程序运行效率

什么对象适宜作为单例对象?
​ 一般来说对于无状态或状态不可扭转的对象适宜应用单例模式。(不存在会扭转对象状态的成员变量)
​ 比方:controller 层、service 层、dao 层

什么是无状态或状态不可扭转的对象?

​ 实际上对象状态的变动往往均是因为属性值得变动而引起的,比方 user 类 姓名属性会有变动,属性姓名的变动个别会引起 user 对象状态的变动。对于咱们的程序来说,无状态对象没有实例变量的存在,保障了线程的安全性,service 层业务对象即是无状态对象。线程平安的。

prototype 作用域

​ 通过 scope=“prototype”设置 bean 的类型,每次向 Spring 容器申请获取 Bean 都返回一个全新的 Bean,绝对于 ”singleton” 来说就是不缓存 Bean,每次都是一个依据 Bean 定义创立的全新 Bean。

Web 利用中的作用域
  1. request 作用域

    示意每个申请须要容器创立一个全新 Bean。比方提交表单的数据必须是对每次申请新建一个 Bean 来放弃这些表单数据,申请完结开释这些数据。

  2. session 作用域

    示意每个会话须要容器创立一个全新 Bean。比方对于每个用户个别会有一个会话,该用户的用户信息须要存储到会话中,此时能够将该 Bean 作用域配置为 session 级别。

  3. globalSession 作用域

    相似于 session 作用域,其用于 portlet(Portlet 是基于 Java 的 Web 组件,由 Portlet 容器治理,并由容器解决申请,生产动静内容)环境的 web 利用。如果在非 portlet 环境将视为 session 作用域。

​ 配置形式和根本的作用域雷同,只是必须要有 web 环境反对,并配置相应的容器监听器或拦截器从而能利用这些作用域,目前先相熟概念,后续集成 web 时解说具体应用,大家只须要晓得有这些作用域就能够了。

Bean 的生命周期

​ 比照曾经学过的 servlet 生命周期(容器启动装载并实例化 servlet 类,初始化 servlet,调用 service 办法,销毁 servlet)。

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

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

Bean 的定义

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

​ 在一个配置文档中,能够定义多个 Bean。

Bean 的初始化

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

Spring bean 初始化有两种形式:

形式一:在配置文档中通过指定 init-method 属性来实现。

public class RoleService {
    // 定义初始化时须要被调用的办法
    public void init() {System.out.println("RoleService init...");
    }
} 
<!-- 通过 init-method 属性指定办法 -->
<bean id="roleService" class="com.xxxx.service.RoleService" init-method="init"></bean> 

形式二: 实现 org.springframework.beans.factory.InitializingBean 接口。

public class RoleService implements InitializingBean {

    @Override
    public void afterPropertiesSet() throws Exception {System.out.println("RoleService init...");
    }
} 
<bean id="roleService" class="com.xxxx.service.RoleService" ></bean> 

​ Bean 对象实例化过程是在 Spring 容器初始化时被实例化的,但也不是不可扭转的,能够通过 lazy-init=“true”属性提早 bean 对象的初始化操作,此时再调用 getBean 办法时才会进行 bean 的初始化操作

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"); 
Bean 的销毁

​ 实现销毁形式(Spring 容器会保护 bean 对象的治理,能够指定 bean 对象的销毁所要执行的办法)。

步骤一:实现销毁形式(Spring 容器会保护 bean 对象的治理,能够指定 bean 对象的销毁所要执行的办法)

<bean id="roleService" class="com.xxxx.service.RoleService" destroy-method="destroy"></bean> 
** 步骤二:** 通过 AbstractApplicationContext 对象,调用其 close 办法实现 bean 的销毁过程 
AbstractApplicationContext ctx=new ClassPathXmlApplicationContext("spring.xml");
ctx.close(); 
IOC/DI- 管制反转和依赖注入
      将对象实例化的创立过程转交给内部容器(IOC 容器 充当工厂角色)去负
正文完
 0