首页 > 其他分享 >Spring IOC

Spring IOC

时间:2023-03-08 09:55:41浏览次数:50  
标签:set 对象 Spring void bean IOC public

1 .SpringIoc

 

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 项目

  1. 创建 Maven 的普通 Java 项目

 

  1. 设置项目的坐标、名称、工作空间

 

  1. 设置项目的 Maven 环境

 

 

2.3.3 调整项目环境

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>
  1. 修改单元测试 JUnit 版本

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

 <!--删除build标签中的pluginManagement标签-->
 <build>
 </build>

2.3.4 添加 Spring 框架的依赖坐标

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

 <!-- 添加Spring框架的核心依赖 -->
 <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-context</artifactId>
     <version>5.2.4.RELEASE</version>
 </dependency>

2.3.5 编写Bean对象

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

2.3.6 添加Spring配置文件

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

  2. 将 resources 标记为资源目录

     

 

  1. 在 src\main\resources 目录下新建 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>

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

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

 

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

 

思路:

  1. 定义Bean 工厂接口,提供获取bean方法

  2. 定义Bean工厂接口实现类,解析配置文件,实例化Bean对象

  3. 实现获取Bean方法

3.1 定义 Bean 属性对象

package com.xxx.spring;

/**
 * Bean属性对象
 *      用来存放配置文件中bean标签对应的id和class属性
 */
public class MyBean {
    private String id;      //bean标签的id属性值
    private String clazz;   //bean标签的class属性值

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

3.2. 添加 dom4j 坐标依赖

<!--引入dom4j依赖-->
    <!-- https://mvnrepository.com/artifact/dom4j/dom4j -->
    <dependency>
      <groupId>dom4j</groupId>
      <artifactId>dom4j</artifactId>
      <version>1.6.1</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/jaxen/jaxen -->
    <dependency>
      <groupId>jaxen</groupId>
      <artifactId>jaxen</artifactId>
      <version>1.1.6</version>
    </dependency>

 

3.3. 准备自定义配置文件

<?xml version="1.0" encoding="UTF-8" ?>

<beans>
<!--设置JavaBean对应的bean标签-->
    <bean id="userDao" class="com.xxx.dao.UserDao"></bean>
    <bean id="userService" class="com.xxx.service.UserService"></bean>
</beans>

 

3.4. 定义 Bean 工厂接口

package com.xxx.spring;

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

 

3.5.定义Bean接口的实现类

package com.xxx.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集合(存放bean标签的id和class属性值)
 *  3.通过反射得到对应的实例化对象,放置在map对象中(遍历list集合,通过获取对应的class属性,利用Class.forName(class).newIntance())
 *  4.通过id属性值获取指定的实例化对象
 */
public class MyClassPathXmlApplicationContext implements MyFactory{

    private List<MyBean> beanList;   //存放从配置文件文件中获取到的bean标签的信息(myBean代表的就是每一个bean标签)
    private Map<String ,Object> beanMap =new HashMap<>();  //存放实例化好的对象,通过id获取对应的对象

    //1.通过带参构造器得到对应的配置文件
    public MyClassPathXmlApplicationContext(String fileName) {
       // 2.通过dom4j解析配置文件(xml文件),得到list集合
        this.parseXml(fileName);
        //3.通过反射得到对应的实例化对象
        this.instanceBean();
    }

    /**
     * 通过dom4j解析配置文件(xml文件),得到list集合
     *  1.获取解析器
     *  2.获取配置文件的URL
     *  3.通过解析器解析配置文件(xml文件)
     *  4.通过XPath语法解析,获取beans标签下的所有bean标签
     *  5.通过指定的解析语法解析文档对象,返回元素集合
     *  6.判断元素集合是否为空
     *  7.如果元素集合不为空,遍历集合
     *  8.获取bean标签元素属性(id和class属性值)
     *  9.获取MyBean对象,将id和class属性值设置到对象中,再将对象设置到MyBean的集合中
     * @param fileName
     */
    private void parseXml(String fileName)  {
        //1.获取解析器
        SAXReader saxReader =new SAXReader();
        //2.获取配置文件的URL
        URL url =this.getClass().getClassLoader().getResource(fileName);
        try {
            //3.通过解析器解析配置文件(xml文件)
            Document document =saxReader.read(url);
           // 4.通过XPath语法解析,获取beans标签下的所有bean标签
            XPath xPath =document.createXPath("beans/bean");
            //5.通过指定的解析语法解析文档对象,返回元素集合
            List<Element> elementList =xPath.selectNodes(document);
            //6.判断元素集合是否为空
            if (elementList !=null && elementList.size()>0){
                //实例化beanList
                beanList =new ArrayList<>();
                //7.如果元素集合不为空,遍历集合
                for(Element el:elementList){
                    //8.获取bean标签元素属性(id和class属性值)
                    String id =el.attributeValue("id");
                    String clazz =el.attributeValue("class");
                    //9.获取MyBean对象,将id和class属性值设置到对象中,再将对象设置到MyBean的集合中
                    MyBean myBean =new MyBean(id,clazz);
                    beanList.add(myBean);
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 通过反射得到对应的实例化对象,放置在map对象中
     *  1.判断对象集合是否为空,如果不为空,则遍历集合,获取对象的id和class
     *  2.通过类的全路径名  反射  得到实例化对象 Class.forName(class).newInstance();
     *  3.将对应的id和实例化的bean对象设置到map对象
     */
    private void instanceBean() {
        //1.判断对象集合是否为空,如果不为空,则遍历集合,获取对象的id和class
        if (beanList !=null &&beanList.size()>0){
            for (MyBean bean :beanList){
                String id =bean.getId();
                String clazz =bean.getClazz();
                try{
                    //2.通过类的全路径名  反射  得到实例化对象 Class.forName(class).newInstance();
                    Object object =Class.forName(clazz).newInstance();
                    //3.将对应的id和实例化的bean对象设置到map对象
                    beanMap.put(id,object);
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }

    }

    /**
     * 通过id获取对应的map对象中的value值(实例化好bean对象)
     * @param id
     * @return
     */
    @Override
    public Object getBean(String id) {
        Object object = beanMap.get(id);
        return object;
    }
}

3.6. 测试自定义 IOC 容器

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

UserService.java

package com.xxx.service;

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

UserDao.java

package com.xxx.dao;

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

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

package com.xxx;

import com.xxx.dao.UserDao;
import com.xxx.service.UserService;
import com.xxx.spring.MyClassPathXmlApplicationContext;
import com.xxx.spring.MyFactory;

/**
 * Hello world!
 *
 */
public class App {
    public static void main( String[] args ) {
        //得到工厂的实现对象
        MyFactory factory =new MyClassPathXmlApplicationContext("spring.xml");
        //得到对应的实例化对象
        UserDao userDao = (UserDao) factory.getBean("userDao");
        userDao.test();

        UserService userService = (UserService) factory.getBean("userService");
        userService.test();
    }
}

Spring 容器在启动的时候 读取xml配置信息,并对配置的 bean 进行实例化(这里模拟的比较简

单,仅用于帮助大家理解),同时通过上下文对象提供的 getBean() 方法拿到我们配置的 bean 对

象,从而实现外部容器自动化维护并创建 bean 的效果。

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遵守的规范 官方指定
   -->
    <!--
         id:bean对象的id,唯一标识。一般是Bean对象的名称的首字母小写
         class:bean对象的类路径(包名加类名)
    -->
    <bean id="userService" class="com.xxx.service.UserService">
        <!-- collaborators and configuration for this bean go here -->
    </bean>
</beans>

4.1.1 根据相对路径加载资源

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

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

ApplicationContext ac = new
FileSystemXmlApplicationContext("C:/IdeaWorkspace/spring01/src/main/resources/spring.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">
    
    <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>

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导入其他配置文件-->
        <import resource="beans.xml"></import>
        <import resource="spring.xml"></import>
</beans>

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

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

 

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

5.1. 构造器实例化

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

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对象需要提供空构造
    -->
    <bean id="typeDao" class="com.xxx.dao.TypeDao"></bean>
</beans>

2.获取实例化对象

package com.xxx.test;

import com.xxx.dao.TypeDao;
import com.xxx.service.UserService;
import com.xxx.service.UserService02;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * IOC容器Bean对象的实例化方式
 *  1.构造器实例化  (Bean对象需要提供空构造)
 */
public class Starter03 {
    public static void main(String[] args) {
        BeanFactory factory =new ClassPathXmlApplicationContext("spring02.xml");
        TypeDao typeDao = (TypeDao) factory.getBean("typeDao");
        typeDao.test();
    }
}

 

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

注:

要有该工厂类及工厂方法

工厂方法为静态的

1.定义静态工厂类

package com.xxx.factory;

import com.xxx.service.TypeService;
import sun.reflect.generics.tree.TypeSignature;

/**
 * 定义静态工厂类
 *
 */
public class StaticFactory {
    /**
     * 定义对应的静态方法
     * @return
     */
    public static TypeService createService(){
        return new TypeService();
    }
}

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.定义工厂类及对应的静态方法
            2.配置bean对象对应的工厂类及静态方法

            id:需要被实例化的bean对象的id
            class:静态工厂类的路径
            factory-method:静态工厂类中实例化bean对象的静态方法
    -->
    <bean id="typeService" class="com.xxx.factory.StaticFactory" factory-method="createService"></bean>
</beans>

3.获取实例化对象

//静态工厂实例化
TypeService typeService = (TypeService) factory.getBean("typeService");
typeService.test();

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

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

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

 

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

 

注:

工厂方法为非静态方法

需要配置工厂bean,并在业务bean中配置factory-bean,factory-method属性

1.定义工厂类

package com.xxx.factory;

import com.xxx.controller.TypeController;

/**
 * 定义实例化工厂
 */
public class InstanceFactory {
    /**
     * 定义实例化方法
     * @return
     */
    public TypeController createTypeController(){
        return new TypeController();
    }
}

 

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.定义工厂类及对应的方法
            2.配置工厂对象
            3.配置bean对象对应的工厂对象及工厂方法

            factory-bean:工厂对象对应的id属性值
            factory-method:工厂类中的方法
    -->
    <!--工厂对象-->
    <bean id="instanceFactory" class="com.xxx.factory.InstanceFactory"></bean>
    <!--bean对象-->
    <bean id="typeController" factory-bean="instanceFactory" factory-method="createTypeController"></bean>
</beans>

 

3.获取实例化对象

package com.xxx.test;

import com.xxx.controller.TypeController;
import com.xxx.dao.TypeDao;
import com.xxx.service.TypeService;
import com.xxx.service.UserService;
import com.xxx.service.UserService02;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * IOC容器Bean对象的实例化方式
 *  1.构造器实例化  (Bean对象需要提供空构造)
 *  2.静态工厂实例化(了解)
 *  3.实例化工厂(了解)
 */
public class Starter03 {
    public static void main(String[] args) {
        BeanFactory factory =new ClassPathXmlApplicationContext("spring02.xml");
        //构造器实现
        TypeDao typeDao = (TypeDao) factory.getBean("typeDao");
        typeDao.test();

        //静态工厂实例化
        TypeService typeService = (TypeService) factory.getBean("typeService");
        typeService.test();

        //实例化工厂
        TypeController typeController = (TypeController) factory.getBean("typeController");
        typeController.test();
    }
}

 

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

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

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

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

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

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

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

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

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

 

6. Spring IOC 注入

 

手动实例化与外部引入

图一:

 

图二:

 

对比发现:图二中对于 UserDao 对象的创建并没有像图一那样主动的去实例化,而是通过带参方法

形式将UserDao 传入过来,从而实现 UserService 对UserDao类 的依赖。

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

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

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

6.1.1. set方法注入

注:

属性字段需要提供set方法

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

6.1.1.1. 业务对象 JavaBean

1.属性字段提供set方法

package com.xxx.service;

import com.xxx.dao.UserDao;

public class UserService {
    //手动实例化
    //private UserDao userDao =new UserDao();

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

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

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

<!--
    Set方法注入
          通过property属性注入
            name:bean对象中属性字段的名称
            ref:指定bean标签的id属性值
-->
    <bean id="userService" class="com.xxx.service.UserService">
        <property name="userDao" ref="userDao"></property>
    <!-- collaborators and configuration for this bean go here -->
    </bean>
    <bean id="userDao" class="com.xxx.dao.UserDao"></bean>


</beans>

 

6.1.1.2. 常用对象和基本类型

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
6.1.1.3. 集合类型和属性对象
1. 属性字段提供set方法
2. 配置文件的bean标签设置property标签
        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>

 

6.1.1.3. 集合类型和属性对象

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>

 

6.1.1.4. 测试代码

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>

 

6.1.2 构造器注入

注:

提供带参构造器

6.1.2.1. 单个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>

6.1.2.1.多个Bean对象作为参数

Java 代码

public class UserService {
    private UserDao userDao;  // JavaBean 对象
    private AccountDao accountDao  // JavaBean 对象
    XML配置
    6.1.2.3. Bean对象和常用对象作为参数
    Java 代码
        
    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>

6.1.2.3. 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(){
XML配置
6.1.2.4. 循环依赖问题
循环问题产生的原因:
 Bean通过构造器注入,之间彼此相互依赖对方导致bean无法实例化。 
问题展示:
1. Java 代码
        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>

6.1.2.4.循环依赖问题

循环问题产生的原因:

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

问题展示:

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;
2. XML配置
6.1.3. 静态工厂注入
1. 定义静态工厂类
2. Java代码
    }*/
    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>

 

6.1.3 静态工厂注入

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>

 

6.1.4 实例化工厂注入

1.定义工厂类

public class InstanceFactory {
     public TypeDao createTypeDao() {
        return new TypeDao();
   }
}

 

  1. 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

 

6.1.5 注入方法注入

开发项目中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"?>
6.2. Spring IOC 自动装配(注入)
注解方式注入 Bean
对于 bean 的注入,除了使用 xml 配置以外,可以使用注解配置。注解的配置,可以简化配置文件,
提高开发的速度,使程序看上去更简洁。对于注解的解释,Spring对于注解有专门的解释器,对定义的
注解进行解析,实现对应bean对象的注入。通过反射技术实现。
6.2.1. 准备环境
1. 修改配置文件
2. 开启自动化注入
3. 给注入的bean对象添加注解
<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>

 

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

注解方式注入 Bean

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

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

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

 

6.2.1. 准备环境

 

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对象添加注解

 

6.2.2. @Resource注解

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

Spring配置文件

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

import com.xxx.dao.UserDao;

import javax.annotation.Resource;

/**
 *  @Resource注解实现自动注入(反射)
 *      1.注解默认通过属性字段名称查找对应的bean对象(属性字段的名称与bean标签的id属性值一致)
 */
public class UserService {
    //注入JavaBean对象
    @Resource
    private UserDao userDao;

    //set方法
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void test(){
        System.out.println("UserService test...");
        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.UserDao02"></bean>

 

使用注解 UserService.java

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

6.2.3. @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的耦合

 

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

   注:开发过程中建议按照指定规则声明注解

 

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
public class PropertyUtils {
    public void test(){
        System.out.println("PropertyUtils...");
   }
}

 

7.2 Spring 模拟用户登录流程

 

7.2.1. Dao层 (查询用户记录)

1.定义JavaBean User.java

package com.xxx.entity;

/**
 * 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.xxx.dao;

import com.xxx.entity.User;
import org.springframework.stereotype.Repository;

@Repository
public class UserDao {

    //定义登录的账号密码
    private final String USERNAME ="admin";
    private final String USERPWD ="admin";

    /**
     * 通过用户名查询用户对象
     *      如果存在,返回对应的用户对象,如果不存在,返回null
     * @param userName
     * @return
     */
    public User queryUserByUserName(String userName){
        User user =null;
        //判断用户名是否存在
        if (!USERNAME.equals(userName)){
            return null;
        }
        //给user对象赋值
        user = new User();
        user.setUserName(userName);
        user.setUserPwd(USERPWD);
        return user;

    }
}

7.2.2. Service层 (业务逻辑处理)

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

package com.xxx.entity.vo;

/**
 * 消息模型对象
 *  用来处理结果
 *      resultCode  状态码
 *          1=成功  0=失败
 *      resultMsg  提示信息
 */
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.xxx.service;

import com.xxx.dao.UserDao;
import com.xxx.entity.User;
import com.xxx.entity.vo.MessageModel;
import com.xxx.util.StringUtil;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service
public class UserService {
    @Resource
    private UserDao userDao;

    /**
     * 验证登录是否成功
     *  1.参数的非空校验
     *  2.通过用户名查询用户对象(调用Dao层的查询方法)
     *  3.判断密码是否正确
     * @param uname
     * @param upwd
     * @return
     */
    public MessageModel checkUserLogin(String uname,String upwd){
        //返回消息模型
        MessageModel messageModel = new MessageModel();

        //1.参数的非空校验
        if (StringUtil.isEmpty(uname)||StringUtil.isEmpty(upwd)){
            //用户名或者密码不能为空
            messageModel.setResultCode(0);
            messageModel.setResultMsg("用户名称和密码不能为空");
            return messageModel;
        }
        //2.通过用户名查询用户对象(调用Dao层的查询方法)
        User user =userDao.queryUserByUserName(uname);
        //判断用户对象是否为空
        if(user ==null){
            messageModel.setResultCode(0);
            messageModel.setResultMsg("用户名不存在,请重试");
            return messageModel;
        }
        //3.判断密码是否正确
        if(!upwd.equals(user.getUserPwd())){
            messageModel.setResultCode(0);
            messageModel.setResultMsg("用户名密码不正确");
            return messageModel;
        }
        //登录成功
        messageModel.setResultMsg("登录成功");
        return messageModel;
    }
}

7.2.3. Controller层 (接收请求)

1.编写Controller层 UserController.java

package com.xxx.controller;

import com.xxx.entity.vo.MessageModel;
import com.xxx.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class UserController {
    @Autowired
    private UserService userService;

    public MessageModel userLogin(String uname,String upwd){

        MessageModel messageModel = userService.checkUserLogin(uname,upwd);
        return messageModel;
    }
}

 

7.2.4.通过JUnit 进行测试

package com.xxx.test;

import com.xxx.controller.UserController;
import com.xxx.entity.vo.MessageModel;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * 单元测试类
 */
public class UserTest {
    public static void main(String[] args) {
        //获取spring的上下文环境
        BeanFactory factory =new ClassPathXmlApplicationContext("spring.xml");
        //得到实例化的userController对象
        UserController userController = (UserController) factory.getBean("userController");
        MessageModel messageModel =userController.userLogin("admin","admin");
        System.out.println("状态码:" +messageModel.getResultCode() +"提示信息:"+messageModel.getResultMsg());
    }
}

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,加快程序运行效率

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

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

量)

比如:controller层、service层、dao层

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

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

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

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

 

8.1.2. prototype作用域

 

 

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

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

 

8.1.3. Web应用中的作用域

1.request作用域

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

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

2.session作用域

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

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

3.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 属性来完成。

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的初始化操作

 

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="roleService" class="com.xxxx.service.RoleService" destroymethod="destroy"></bean>
    
**步骤二:**通过 AbstractApplicationContext 对象,调用其close方法实现bean的销毁过程
AbstractApplicationContext ctx=new ClassPathXmlApplicationContext("spring.xml");
ctx.close();


IOC/DI-控制反转和依赖注入
     将对象实例化的创建过程转交给外部容器(IOC容器 充当工厂角色)去负责;属性赋值的操作;
 

 

 

 

标签:set,对象,Spring,void,bean,IOC,public
From: https://www.cnblogs.com/MeltSky/p/17190925.html

相关文章

  • SMU Spring 2023 Trial Contest Round 2
    A-生活大爆炸版石头剪刀布B-联合权值C-飞扬的小鸟D-无线网络发射器选址E-寻找道路F-廊桥分配G-格雷码A-生活大爆炸版石头剪刀布这套题就是注意处......
  • Spring启用Log4日志框架
    配置maven依赖<!--log4j2的依赖--><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId>......
  • Spring Task
    SpringTask定时任务1.主要内容 2.定时任务概述在项目中开发定时任务应该一种比较常见的需求,在Java中开发定时任务主要有三种解决方案:一是使用JDK自带的Timer......
  • Spring Aop
    SpringAop1.主要内容 2.代理模式代理模式在Java开发中是一种比较常见的设计模式。设计目的旨在为服务类与客户类之间插入其他功能,插入的功能对于调用者是透明的,......
  • SpringBoot监听类——小结②
    SpringBoot的监听类的配置有两种方法,一是通过SpringBoot的自动扫描功能来进行,但是前提是在Listener类上添加相应的注解@WebListener 二是自己进行相应的配置类编写pa......
  • 手牵手入门Spring6整合Mybatis3.5
    方式一Object类get和set,无参构造+有参构造Pom.xml引入依赖<!--打包方式jar--><packaging>jar</packaging><!--配置多个仓库--><repositories><!--Spring6-->......
  • spring的初步学习
    引入单独使用spring只需引入<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>6.0.6</version></de......
  • Spring Boot | 事件监听器异步处理事件,实现代码解耦
    一、简介SpringBoot事件监听器(EventListener)用于在应用程序的生命周期中,监听SpringBoot应用程序中各种事件的发生,以便在事件发生时执行某些特定的操作。二、集成步骤1......
  • SpringMVC中的异常处理器
    SpringMVC中的异常处理器目录SpringMVC中的异常处理器一、概述二、异常处理器初始化位置默认策略@ControllerAdvice工作原理RequestMappingHandlerAdapterExceptionHandle......
  • Spring Boot | 集成MapStruct实现不同类型Java对象间的自动转换
    MapStruct简介MapStructisacodegeneratorthatgreatlysimplifiestheimplementationofmappingsbetweenJavabeantypesbasedonaconventionoverconfigura......