天天看点

11-SSM_Spring_IoC与DI

目录

​​一,Spring介绍​​

​​1,什么是框架​​

​​2,spring是什么​​

​​3,Spring的优势​​

​​4,Spring的体系结构​​

​​4.1 核心容器​​

​​4.2 数据访问/集成​​

​​4.3 Web​​

​​4.4 其他​​

​​二,Spring核心-IoC​​

​​1,概念​​

​​2,入门案例​​

​​2.1 在一个工程中创建多个项目 ​​

​​2.2 创建实例的方法​​

​​2.3 获取Spring容器​​

​​2.4 其他常用的api​​

​​2.5 创建非自定义对象​​

​​4,bean标签属性​​

​​4.1 scope​​

​​4.2 lazy-init​​

​​4.3 init-method与destroy-method​​

​​5,创建对象的3种方式​​

​​5.1 默认的构造方法​​

​​5.2 带参数的构造方法 ​​

​​5.3 使用工厂方法​​

​​6,基于XML的DI​​

​​6.1 通过set方法注入​​

​​6.2 通过构造方法注入​​

​​6.3 自动注入​​

​​7,基于注解实现IoC​​

​​7.1 声明Bean的注解 @Component​​

​​7.2 包扫描​​

​​8,属性注入的注解实现​​

​​8.1 属性注入@Vaule​​

​​8.2 byType自动注入@Autowired​​

​​8.3 byName自动注入@Autowired和@Qualifier​​

​​8.4 自动注入@Resource​​

一,Spring介绍

1,什么是框架

框架(Framework):框(指其约束性)架(指其支撑性),在软件设计中指为解决一个开放性问题而设计的具有一定约束性的支撑结构。在此结构上可以根据具体问题扩展、安插更多的组成部分,从而更迅速和方便地构建完整的解决问题的方案。
  1. 框架本身一般不完整到可以解决特定问题
  2. 框架天生就是为扩展而设计的
  3. 框架里面可以为后续扩展的组件提供很多辅助性、支撑性的方便易用的实用工具(utilities),也就是说框架时常配套了一些帮助解决某类问题的库(libraries)或工具(tools)。

如何学习框架呢?

  • 1、知道框架能做什么
  • 2、学习框架的语法,一般框架完成一个功能需要一定的步骤
  • 3、框架的内部实现原理(扩展)
  • 4、尝试实现一个框架(提升)

2,spring是什么

Spring官网 ​​Spring | Home​​

11-SSM_Spring_IoC与DI
11-SSM_Spring_IoC与DI
11-SSM_Spring_IoC与DI

Spring 被称为 J2EE 的春天,是一个是分层的 Java SE/EE full-stack 开源的轻量级的 Java 开发框架, 是最受欢迎的企业级 Java 应用程序开发框架,数以百万的来自世界各地的开发人员使用 Spring 框架来创建性能好、易于测试、可重用的代码。

Spring具有控制反转(IoC)和面向切面(AOP)两大核心。Java Spring框架通过声明式方式灵活地进行事务的管理,提高开发效率和质量。

Spring 框架不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何 Java 应用都可以从 Spring 中受益。Spring 框架还是一个超级粘合平台,除了自己提供功能外,还提供粘合其他技术和框架的能力。

3,Spring的优势

1、方便解耦,简化开发

Spring 就是一个大工厂,可以将所有对象的创建和依赖关系的维护交给 Spring 管理。

2、方便集成各种优秀框架

Spring 不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如 Struts2、Hibernate、MyBatis 等)的直接支持。

3、降低 Java EE API 的使用难度

Spring 对 Java EE 开发中非常难用的一些 API(JDBC、JavaMail、远程调用等)都提供了封装,使这些 API 应用的难度大大降低。

4、方便程序的测试

Spring 支持 JUnit4,可以通过注解方便地测试

5、AOP 编程的支持

Spring 提供面向切面编程,可以方便地实现对程序进行权限拦截和运行监控等功能。

6、声明式事务的支持

只需要通过配置就可以完成对事务的管理,而无须手动编程。

4,Spring的体系结构

Spring 为我们提供了一站式解决方案,但Spring 是模块化的,允许挑选和选择适用于项目的模块,不需要把剩余部分也引入。

Spring 框架提供约 20 个模块,可以根据应用程序的要求来选择。

11-SSM_Spring_IoC与DI

4.1 核心容器

核心容器由 Spring-core,Spring-beans,Spring-context,Spring-context-support和Spring-expression(SpEL,Spring 表达式语言,Spring Expression Language)等模块组成

  • Spring-core 模块提供了框架的基本组成部分,包括 IoC 和依赖注入功能。
  • Spring-beans 模块提供 BeanFactory,工厂模式的微妙实现,它移除了编码式单例的需要,并且可以把配置和依赖从实际编码逻辑中解耦。
  • context 模块建立在由 core和 beans 模块的基础上建立起来的,它以一种类似于 JNDI 注册的方式访问对象。Context 模块继承自 Bean 模块,并且添加了国际化(比如,使用资源束)、事件传播、资源加载和透明地创建上下文(比如,通过 Servelet 容器)等功能。Context 模块也支持 Java EE 的功能,比如 EJB、JMX 和远程调用等。ApplicationContext 接口是 Context 模块的焦点。
  • Spring-context-support 提供了对第三方集成到 Spring 上下文的支持,比如缓存(EhCache,Guava, JCache)、邮件(JavaMail)、调度(CommonJ, Quartz)、模板引擎(FreeMarker,JasperReports, Velocity)等。
  • Spring-expression 模块提供了强大的表达式语言,用于在运行时查询和操作对象图。它是 JSP2.1规范中定义的统一表达式语言的扩展,支持 set 和 get 属性值、属性赋值、方法调用、访问数组集合及索引的内容、逻辑算术运算、命名变量、通过名字从 Spring IoC 容器检索对象,还支持列表的投影、选择以及聚合等。

完整依赖关系

11-SSM_Spring_IoC与DI

4.2 数据访问/集成

JDBC=Java Data Base Connectivity

ORM=Object Relational Mapping

OXM=Object XML Mapping

JMS=Java Message Service

  • JDBC 模块提供了 JDBC 抽象层,它消除了冗长的 JDBC 编码和对数据库供应商特定错误代码的解析。
  • ORM 模块提供了对流行的对象关系映射 API 的集成,包括 JPA、JDO 和 Hibernate 等。通过此模块可以让这些 ORM 框架和 Spring的其它功能整合,比如前面提及的事务管理。
  • OXM 模块提供了对 OXM 实现的支持,比如 JAXB、Castor、XML Beans、JiBX、XStream 等。
  • JMS 模块包含生产(produce)和消费(consume)消息的功能。从 Spring 4.1 开始,集成了Spring-messaging 模块。
  • 事务模块为实现特殊接口类及所有的 POJO 支持编程式和声明式事务管理。

4.3 Web

  • Web 模块提供面向 web 的基本功能和面向 web 的应用上下文,比如多部分(multipart)文件上传功能、使用 Servlet 监听器初始化 IoC 容器等。它还包括 HTTP 客户端以及 Spring 远程调用中与web 相关的部分。
  • Web-MVC 模块为 web 应用提供了模型视图控制(MVC)和 REST Web服务的实现。Spring 的MVC 框架可以使领域模型代码和 web 表单完全地分离,且可以与 Spring 框架的其它所有功能进行集成。
  • Web-Socket 模块为 WebSocket-based 提供了支持,而且在 web 应用程序中提供了客户端和服务器端之间通信的两种方式。
  • Web-Portlet 模块提供了用于 Portlet 环境的 MVC 实现,并反映了 Spring-webmvc 模块的功能。

4.4 其他

  • AOP 模块提供了面向方面(切面)的编程实现,允许你定义方法拦截器和切入点对代码进行干净地解耦,从而使实现功能的代码彻底的解耦出来。
  • Aspects 模块提供了与 AspectJ 的集成,这是一个功能强大且成熟的面向切面编程(AOP)框架。
  • Instrumentation 模块在一定的应用服务器中提供了类 instrumentation 的支持和类加载器的实现。
  • Messaging 模块为 STOMP 提供了支持作为在应用程序中 WebSocket 子协议的使用。它也支持一个注解编程模型,它是为了选路和处理来自 WebSocket 客户端的 STOMP 信息。
  • 测试模块支持对具有 JUnit 或 TestNG 框架的 Spring 组件的测试。

二,Spring核心-IoC

1,概念

Ioc—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。

IoC 是指在程序开发中,实例的创建不再由调用者管理,而是由 Spring 容器创建。Spring 容器会负责控制程序之间的关系,而不是由程序代码直接控制,因此,控制权由程序代码转移到了 Spring 容器中,控制权发生了反转,这就是 Spring 的 IoC 思想。

以往的实例创建方法:构造方法(new)、克隆、反射、序列化、动态代理

思考:Javaweb中的servlet对象并没有手动创建的过程,但是我们可以直接使用其方法,如doGet、doPost等,这是因为tomcat帮助我们实例化了对象(容器创建servlet)。

2,入门案例

2.1 在一个工程中创建多个项目 

将多个项目整合到一个工程中,这样就可以方便的切换多个项目了。

1,创建空工程

11-SSM_Spring_IoC与DI
11-SSM_Spring_IoC与DI

2,通过Maven创建model

11-SSM_Spring_IoC与DI
11-SSM_Spring_IoC与DI
11-SSM_Spring_IoC与DI

3,项目结构

11-SSM_Spring_IoC与DI

4,再次创建项目Spring02

11-SSM_Spring_IoC与DI
11-SSM_Spring_IoC与DI
11-SSM_Spring_IoC与DI

5,项目结构

11-SSM_Spring_IoC与DI

2.2 创建实例的方法

1,引入依赖

<groupId>com.xxy</groupId>
    <artifactId>Spring01</artifactId>
    <version>1.0-SNAPSHOT</version>    
    <dependencies>
        <!--spring 核心依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.13.RELEASE</version>
        </dependency>
        <!--测试依赖-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <!--编译插件-->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.0</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>      

2,编写实体类Team

11-SSM_Spring_IoC与DI
package com.xxy.pojo;

public class Team {
    private Integer id;
    private String name;
    private String location;

    public Team() {
        System.out.println("Team - 默认的构造方法 id="+id+",name="+name+",location="+location);
    }
}      

3,创建测试类

11-SSM_Spring_IoC与DI

4,Spring通过配置创建对象

11-SSM_Spring_IoC与DI
11-SSM_Spring_IoC与DI
<?xml version="1.0" encoding="UTF-8"?>
<!--spring配置文件
    beans:根标签
        spring中Java的对象称为java bean
        spring-beans.xsd是一个约束文件  约束xml文件中都能编写哪些标签
-->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--创建对象:声明bean,告知spring容器创建哪些对象
        一个bean标签表示一个对象
        id=“对象名”,要求唯一值
        class="完全限定名" spring底层是通过反射方式创建对象,不能写接口
            相当于com.xxy.pojo.Team team1=new com.xxy.pojo.Team();然后将创建的对象放入spring容器的一个集合Map中
            springMap.put(id,对象)例如 springMap.put(“team1",new Team());
    -->
    <bean id="team1" class="com.xxy.pojo.Team" ></bean>

</beans>      
11-SSM_Spring_IoC与DI

2.3 获取Spring容器

Spring 提供了两种 IoC 容器,分别为 BeanFactory 和 ApplicationContext.

1,BeanFactory(new之后不会直接创建实例对象,根据id从容器中获取对象时创建)

BeanFactory 是基础类型的 IoC 容器,是一个管理 Bean 的工厂,它主要负责初始化各种 Bean,并调用它们的生命周期方法。

BeanFactory 接口有多个实现类,最常见的是org.Springframework.beans.factory.xml.XmlBeanFactory,它是根据 XML 配置文件中的定义装配Bean 的。

BeanFactory beanFactory = new XmlBeanFactory(new FileSystemResource(Spring配置文件 的名称));      

配置文件需要写全路径,否则会定位失败。 

BeanFactory beanFactory = new XmlBeanFactory(new FileSystemResource("D:/workspaces/ideaProjects/MySpring/spring01/src/main/resources/application.xml"));
beanFactory.getBean("team1");//根据ID从IOC容器获取对象 这时才创建对象      

2,ApplicationContext(new之后直接创建实例对象)

ApplicationContext 是 BeanFactory 的子接口,也被称为应用上下文。它不仅提供了 BeanFactory 的所有功能,还添加了对 i18n(国际化)、资源访问、事件传播等方面的良好支持。

ApplicationContext 接口有两个常用的实现类:

ClassPathXmlApplicationContext——常用

该类从类路径 ClassPath 中寻找指定的 XML 配置文件(将配置文件放到resources目录下,可以直接通过配置文件名获得对象),找到并装载完成 ApplicationContext 的实例化工作

ApplicationContext applicationContext = new ClassPathXmlApplicationContext(Spring配 置文件的名称);      
String springConfig = "application.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(springConfig);      

FileSystemXmlApplicationContext

它与 ClassPathXmlApplicationContext 的区别是:在读取 Spring 的配置文件时,FileSystemXmlApplicationContext 不再从类路径中读取配置文件,而是通过参数指定配置文件的位置,它可以获取类路径之外的资源,如“D:\application.xml”。 

ApplicationContext applicationContext = new FileSystemXmlApplicationContext(String configLocation);      
ApplicationContext applicationContext = new FileSystemXmlApplicationContext("D:/workspaces/ideaProjects/MySpring/spring01/src/main/resources/application.xml");      

2.4 其他常用的api

package com.kkb.test;
import com.kkb.pojo.Team;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.Date;

public class Test01 {
    @Test
    public void test01(){
        //Team team1=new Team();//原有写法:程序员自己创建对象
        // spring容器创建对象的方式
        String springConfig="application.xml";
        
        //1、获取spring容器
        //方式1:
       // BeanFactory beanFactory=new XmlBeanFactory(new FileSystemResource("D:/workspaces/ideaProjects/MySpring/spring01/src/main/resources/application.xml"));
       //beanFactory.getBean("team1");//根据ID从IOC容器获取对象
        //方式2--常用,推荐:
       ApplicationContext applicationContext=new ClassPathXmlApplicationContext(springConfig);
       
        //2、从容器中根据ID获取对象
        Team team1 = (Team) applicationContext.getBean("team1");
        //方式3:
       // ApplicationContext applicationContext=new FileSystemXmlApplicationContext("D:/workspaces/ideaProjects/MySpring/spring01/src/main/resources/application.xml");

        //3、容器中的其他API
        int beanDefinitionCount = applicationContext.getBeanDefinitionCount();
        System.out.println("容器中的对象的个数:"+beanDefinitionCount);
        System.out.println("容器中所有对象的名称:");
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String name : beanDefinitionNames) {
            System.out.println("\t"+name);
        }

    }
}      

2.5 创建非自定义对象

<!--非自定义对象的创建-->
<bean id="date1" class="java.util.Date"></bean>      
//4、获取非自定义的对象
Date date1 = (Date) applicationContext.getBean("date1");
System.out.println("获取非自定义的对象date="+date1);      

4,bean标签属性

11-SSM_Spring_IoC与DI

4.1 scope

singleton:单例,默认值,容器启动完毕之后单例对象就被创建了,而且容器中只有唯一的一个对象;

prototype:多例,多例的对象是什么时候使用什么时候创建,每次获取的时候都创建新对象;

<bean id="team1"  name="team1" class="com.kkb.pojo.Team" scope="singleton"></bean>
<bean id="team2" name="team2"  class="com.kkb.pojo.Team" scope="prototype"></bean>      
@Test
    public void test02(){
        String springConfig="application.xml";
        ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext(springConfig);
        Team team1 = (Team) applicationContext.getBean("team1");
        Team team11 = (Team) applicationContext.getBean("team1");
        System.out.println(team1);
        System.out.println(team11);
        Team team2 = (Team) applicationContext.getBean("team2");
        Team team22 = (Team) applicationContext.getBean("team2");
        System.out.println(team2);
        System.out.println(team22);
        applicationContext.close();//关闭容器

    }      
11-SSM_Spring_IoC与DI

4.2 lazy-init

true:真懒  获取对象的时候才创建对象。针对单例模式,因为多例模式本来就是用的时候创建;

false:不懒  立即创建对象,不管是否使用(默认值);

<bean id="team1"  name="team1" class="com.kkb.pojo.Team" scope="singleton" lazy-init="true"></bean>      
@Test
    public void test02(){
        String springConfig="application.xml";
        ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext(springConfig);
    }      
11-SSM_Spring_IoC与DI

4.3 init-method与destroy-method

生命周期相关:

init-method:对象创建完毕之后立即调用的初始化方法(自定义名称);

destroy-method:spring容器调用关闭方法的时候执行的方法;

public class Team {
    private Integer id;
    private String name;
    public Team() {
        System.out.println("Team - 默认的构造方法 id="+id+",name="+name+",location="+location);
    }

    public void init(){
        System.out.println("Team---init()-----");
    }

    public void destroy(){
        System.out.println("Team---destroy()-----");
    }
}      
<bean id="team1"  name="team1" class="com.kkb.pojo.Team" scope="singleton" lazy-init="true" init-method="init" destroy-method="destroy"></bean>      
@Test
    public void test02(){
        String springConfig="application.xml";
        // 这里使用ClassPathXmlApplicationContext而不是ApplicationContext
        // 因为ApplicationContext没有定义close方法
        ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext(springConfig);
        Team team1 = (Team) applicationContext.getBean("team1");
        Team team11 = (Team) applicationContext.getBean("team1");
        System.out.println(team1);
        System.out.println(team11);
        Team team2 = (Team) applicationContext.getBean("team2");
        Team team22 = (Team) applicationContext.getBean("team2");
        System.out.println(team2);
        System.out.println(team22);
        applicationContext.close();//关闭容器
    }      

5,创建对象的3种方式

使用默认的构造方法,使用带参数的构造方法,使用工厂类。

5.1 默认的构造方法

<!--1、通过默认构造方法-->
<bean id="team1" class="com.kbb.pojo.Team"></bean>      
@Test
    public void test01(){
        ApplicationContext ac=new ClassPathXmlApplicationContext("createType.xml");
    }      

5.2 带参数的构造方法 

public class Team {
    private Integer id;
    private String name;
    private String location;

    public Team() {
        System.out.println("Team - 默认的构造方法 id="+id+",name="+name+",location="+location);
    }

    public Team(Integer id, String name, String location) {
        this.id = id;
        this.name = name;
        this.location = location;
        System.out.println("Team - 带参数的构造方法 id="+id+",name="+name+",location="+location);
    }

    public void init(){
        System.out.println("Team---init()-----");
    }

    public void destroy(){
        System.out.println("Team---destroy()-----");
    }
}      
<!-- 2、通过带参数的构造方法-->
    <bean id="team2" class="com.kbb.pojo.Team">
        <!--name:表示参数的名称-->
        <constructor-arg name="id" value="1001"/>
        <constructor-arg name="name" value="勇士"/>
        <constructor-arg name="location" value="金州"/>
    </bean>
    <bean id="team3" class="com.kbb.pojo.Team">
        <!--index:表示参数的下标索引-->
        <constructor-arg index="0" value="1002"/>
        <constructor-arg index="1" value="热火"/>
        <constructor-arg index="2" value="迈阿密"/>
    </bean>      
@Test
    public void test01(){
        ApplicationContext ac=new ClassPathXmlApplicationContext("createType.xml");
    }      

5.3 使用工厂方法

 创建工厂类

public class MyFactory {
    /**
     * 实例方法
     * @return
     */
    public Team instanceFun(){
        System.out.println("MyFactory------instanceFun");
        return new Team(1003,"湖人","洛杉矶");
    }

    /**
     * 静态方法
     * @return
     */
    public static Team staticFun(){
        System.out.println("MyFactory------staticFun");
        return new Team(1004,"小牛","达拉斯");
    }

    public static void main(String[] args) {
        Team team1 = MyFactory.staticFun();
        MyFactory factory=new MyFactory();
        Team team = factory.instanceFun();
    }
}      
<!--3、通过工厂方法:
    3.1 静态方法    Team team1 = MyFactory.staticFun();-->
    <bean id="staticTeam" class="com.kbb.pojo.MyFactory" factory-method="staticFun"></bean>

    <!--3、通过工厂方法:
    3.2 实例方法
    MyFactory factory=new MyFactory();
    Team team = factory.instanceFun();-->
    <bean id="factory" class="com.kbb.pojo.MyFactory"></bean>
    <bean id="instanceTeam" factory-bean="factory" factory-method="instanceFun"></bean>      
@Test
    public void test01(){
        ApplicationContext ac=new ClassPathXmlApplicationContext("createType.xml");
    }      

6,基于XML的DI

DI—Dependency Injection,即“依赖注入”:是组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。比如对象A、B、C均需要D,那么在D创建之后,可以自动的注入到A、B、C中。

依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。

通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。

IoC 是一个概念,是一种思想,其实现方式多种多样。依赖注入就是其中用的比较多的一种方式。

IoC和DI是同一个概念的不同角度描述。IoC是一种思想,概念,DI是实现它的手段。Spring框架使用依赖注入实现IoC。

Spring 容器是一个超级大工厂,负责创建、管理所有的 Java 对象,这些 Java 对象被称为 Bean。

Spring 容器管理着容器中 Bean 之间的依赖关系,Spring 使用“依赖注入”的方式来管理 Bean 之间的依赖关系。使用 IoC 实现对象之间的解耦和。

bean 实例在调用无参构造器创建对象后,就要对 bean 对象的属性进行初始化。初始化是由容器自动完成的,称为注入。

6.1 通过set方法注入

1,设计简单的dao和service

public class TeamDao {
    public TeamDao() {
        System.out.println("TeamDao ---- 默认的构造方法");
    }
}      
public class TeamService {
//    private TeamDao teamDao = new TeamDao(); // 原先的做法
    private TeamDao teamDao;// 现在只需要给出声明,对象的创建交给spring完成

    public TeamService() {
        System.out.println("TeamService---默认构造方法");
    }

    // 必须提供get和set方法!!!
    public TeamDao getTeamDao() {
        return teamDao;
    }

    public void setTeamDao(TeamDao teamDao) {
        this.teamDao = teamDao;
    }
}      

2,编写spring配置文件DI.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="newTeamDao" class="com.xxy.dao.TeamDao"></bean>
    <bean id="teamService" class="com.xxy.service.TeamService">
        <!--使用set方法注入属性值-->
        <property name="teamDao" ref="newTeamDao"></property>
    </bean>
</beans>      

3,编写测试文件

@Test
    public void test01() {
        String springConfig = "DI.xml";
        ApplicationContext ac = new ClassPathXmlApplicationContext(springConfig);
    }      
11-SSM_Spring_IoC与DI

6.2 通过构造方法注入

构造注入是指,在构造调用者实例的同时,完成被调用者的实例化。使用构造器设置依赖关系。

1,修改TeamService,添加带有参数的构造方法

package com.xxy.service;

import com.xxy.dao.TeamDao;

public class TeamService {

//    private TeamDao teamDao = new TeamDao(); // 原先的做法
    private TeamDao teamDao;// 现在只需要给出声明,对象的创建交给spring完成

    public TeamService() {
        System.out.println("TeamService---默认构造方法");
    }

    // 带有参数的构造方法
    public TeamService(TeamDao teamDao) {
        System.out.println("TeamService---含参构造方法");
        this.teamDao = teamDao;
    }
}      

2,修改spring配置文件DI.xml,用构造器参数标签替换属性标签

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="newTeamDao" class="com.xxy.dao.TeamDao"></bean>
    <bean id="teamService" class="com.xxy.service.TeamService">
        <!--使用set方法注入属性值-->
        <!--<property name="teamDao" ref="newTeamDao"></property>-->
        <!--使用构造方法注入属性值-->
        <constructor-arg name="teamDao" ref="newTeamDao"></constructor-arg>
    </bean>
</beans>      
11-SSM_Spring_IoC与DI

6.3 自动注入

对于引用类型属性的注入,也可不在配置文件中显式的注入。

可以通过为标签设置 autowire 属性值,为引用类型属性进行隐式自动注入(默认是不自动注入引用类型属性)。根据自动注入判断标准的不同,可以分为两种:

  • byName:根据名称自动注入
  • byType: 根据类型自动注入

byName

当配置文件中被调用者 bean 的 id 值与代码中调用者 bean 类的属性名相同时,可使用byName 方式,让容器自动将被调用者 bean 注入给调用者 bean。

容器是通过调用者的 bean类的属性名与配置文件的被调用者 bean 的 id 进行比较而实现自动注入的。

1,修改修改spring配置文件DI.xml,在调用者的bean标签中添加autowire属性

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="newTeamDao" class="com.xxy.dao.TeamDao"></bean>
    <!--按名称自动注入:查找容器中id名与属性名一致的对象进行注入-->
    <bean id="teamService" class="com.xxy.service.TeamService" autowire="byName"></bean>
</beans>      

2,运行测试方法

11-SSM_Spring_IoC与DI

byType

使用 byType 方式自动注入,要求:配置文件中被调用者 bean 的 class 属性指定的类,要与代码中调用者 bean 类的某引用类型属性类型同源。

即要么相同,要么有 is-a 关系(子类,或是实现类)。但这样的同源的被调用 bean 只能有一个。多于一个,容器就不知该匹配哪一个了。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="newTeamDao" class="com.xxy.dao.TeamDao"></bean>
    <!--按类型自动注入:查找容器中类型与属性类型相同或者符合is-a关系的对象进行注入,但是要求类型相同的对象唯一,否则抛出异常:不知道用哪一个匹配-->
    <bean id="teamService" class="com.xxy.service.TeamService" autowire="byType"></bean>
</beans>      

7,基于注解实现IoC

对于 DI 使用注解,将不再需要在 Spring 配置文件中声明 bean 实例。Spring 中使用注解,需要在原有Spring 运行环境基础上再做一些改变。

7.1 声明Bean的注解 @Component

在类上添加注解@Component表示该类创建对象的权限交给Spring容器。注解的value属性用于指定bean的id值,value可以省略。

@Component 不指定 value 属性时,bean 的 id 是类名的首字母小写。

@Component(value="teamDao")
@Component("teamDao")
@Component    // 默认类名首字母小写      
//@Component 注解标识在类上,表示对象由Spring容器创建 value属性表示创建的id值,value可以省略,值也可省略,默认就是类名的首字母小写
@Component(value="teamDao")
// 相当于xml文件中的额<bean id="teamDao" class="com.kkb.dao.TeamDao"></bean>
public class TeamDao {
    public void add(){
        System.out.println("TeamDao---- add----");
    }

    public TeamDao() {
        System.out.println("TeamDao ---- 默认的构造放方法");
    }
}      

除此之外,Spring中还提供了其他3个用于创建对象的注解:

  • @Repository:用于dao实现类的的注解;
  • @Service:用户service实现类的注解;
  • @Controller:用于controller实现类的注解;

这三个注解与@Component 都可以创建对象,但这三个注解还有其他的含义。

  • @Service创建业务层对象,业务层对象可以加入事务功能;
  • @Controller 注解创建的对象可以作为处理器接收用户的请求。

@Repository,@Service,@Controller 是对@Component 注解的细化,标注不同层的对象。即持久层对象,业务层对象,控制层对象。

@Repository(value="teamDao")
public class TeamDao

@Service("teamService1")
public class TeamService

@Controller
public class TeamController      

7.2 包扫描

需要在 Spring 配置文件中配置组件扫描器(beans标签中添加属性),用于在指定的基本包中扫描注解。如果没有包扫描,添加的创建对象的注解不生效。

如果要扫描的包有多个,可以有以下方式扫描:

方式1,使用多个context:component-scan指定不同的包路径

11-SSM_Spring_IoC与DI

方式2,指定 base-package的值使用分隔符

分隔符可以使用逗号(,)分号(;)还可以使用空格,不建议使用空格。

<!--多个包的扫描: 方式2 : base-package中直接声明要扫描的多个包 ,多个值用逗号,分号或者空格分割,但是空格不推荐-->
<context:component-scan base-package="com.kkb.dao,com.kkb.service,com.kkb.controller"></context:component-scan>      

方式3,base-package是指定到父包名

base-package 的值表是基本包,容器启动会扫描包及其子包中的注解,当然也会扫描到子包下级的子包。所以 base-package 可以指定一个父包就可以。

但不建议使用顶级的父包,扫描的路径比较多,导致容器启动时间变慢。指定到目标包和合适的。也就是注解所在包全路径。

<!--多个包的扫描: 方式3: base-package中直接声明要扫描的多个包的父包-->
<context:component-scan base-package="com.kkb"></context:component-scan>      

8,属性注入的注解实现

8.1 属性注入@Vaule

需要在属性上使用注解@Value,该注解的 value 属性用于指定要注入的值。

使用该注解完成属性注入时,类中无需 setter。当然,若属性有 setter,则也可将其加到 setter 上。

@Component
public class Team {
    @Value("1001")
    private Integer id;
    @Value("湖人队")
    private String name;
    @Value("洛杉矶")
    private String location;

    // 或者
    // @Value("1001")
    // public void setId(Integer id) {
    //     this.id = id;
    // }
    // @Value("湖人队")
    // public void setName(String name) {
    //     this.name = name;
    // }
    // @Value("洛杉矶")
    // public void setLocation(String location) {
    //     this.location = location;
    // }

    @Override
    public String toString() {
        return "Team{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", location='" + location + '\'' +
                '}';
    }


    public Team() {
        System.out.println("Team - 默认的构造方法 id="+id+",name="+name+",location="+location);
    }

    public Team(Integer id, String name, String location) {
        this.id = id;
        this.name = name;
        this.location = location;
        System.out.println("Team - 带参数的构造方法 id="+id+",name="+name+",location="+location);
    }

    public void init(){
        System.out.println("Team---init()-----");
    }

    public void destroy(){
        System.out.println("Team---destroy()-----");
    }
}      

8.2 byType自动注入@Autowired

需要在引用属性上使用注解@Autowired,该注解默认使用按类型自动装配 Bean 的方式。使用该注解完成属性注入时,类中无需 setter。当然,若属性有 setter,则也可将其加到 setter 上。

8.3 byName自动注入@Autowired和@Qualifier

需要在引用属性上联合使用注解@Autowired 与@Qualifier。

  • @Qualifier 的 value 属性用于指定要匹配的 Bean 的 id 值。类中无需 set 方法,也可加到 set 方法上。
  • @Autowired 还有一个属性 required,默认值为 true,表示当匹配失败后,会终止程序运行。若将其值设置为 false,则匹配失败将被忽略,未匹配的属性值为 null。
@Service("teamService1")
public class TeamService {

    @Autowired(required = false) //自动装配 默认按照类型装配
    //@Qualifier("teamDao")//按照名称自动装配 需要@Qualifier搭配使用
    private TeamDao teamDao;//=new TeamDao();      

8.4 自动注入@Resource

Spring提供了对 jdk中@Resource注解的支持。@Resource 注解既可以按名称匹配Bean,也可以按类型匹配 Bean。默认是按名称注入。使用该注解,要求 JDK 必须是 6 及以上版本

@Resource 可在属性上,也可在 set 方法上。

1,byType注入引用类型属性

@Controller
public class TeamController {
    @Resource(name="teamService1",type = TeamService.class) //JDK版本高于1.6 自动装配默认按照名称  但是如果名称没有相符的,就按照类型自动装配
    private TeamService teamService;

    public void add(){
        teamService.add();
        System.out.println("TeamController---- add ----");
    }

    public TeamController() {
        System.out.println("TeamController ---- 默认的构造放方法");
    }
}