01.Spring IoC

第一章 Spring简介

在这里插入图片描述

1.1什么是Spring

Spring是一个开源轻量级的应用开发框架,其目的是用于简化企业级应用程序开发,降低侵入性;

Spring提供的IOC和AOP功能,可以将组件的耦合度降至最低,即解耦,便于系统日后的维护和升级;

Spring为系统提供了一个整体的解决方案,开发者可以利用它们本身提供的功能外,也可以与第三方框架和技术整合应用,可以自由选择采用哪种技术进行开发。

为什么使用Spring?

Spring的本质是管理软件的对象,即创建对象和维护对象之间的关系

1.1.1 Spring的主要功能

在这里插入图片描述

1.1.2 下载:

下载地址:https://repo.spring.io/simple/libs-release-local/org/springframework/spring/

  1. 打开Spring官网:https://spring.io,点击PROJECTS

  2. 点击SPRING FRAMEWORK
    在这里插入图片描述

  3. 点击GitHub图标

在这里插入图片描述

  1. 找到Access to Binaries,点击Spring Framework Artifacts

在这里插入图片描述

  1. 点击Spring Artifactory
    在这里插入图片描述

  2. 点击libs-release-local

在这里插入图片描述

  1. 点击org/,点击springframework,点击spring

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

  1. 就可以选择你想要的版本进行下载

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

1.2Spring容器

在Spring中任何的java类和JavaBean都被当成Bean处理,这些Bean通过容器管理和使用。

Spring容器实现IOC和AOP机制,这些机制可以简化Bean对象的创建和Bean对象之间的解耦;

Spring容器有BeanFactory和ApplicationContext两种类型;

BeanFactory

lBeanFacotry接口,是基于IoC容器他提供了完善的IoC服务支持。

lBeanFacotry提供了几个实现类,其中最常用的XmlBeanFactory。

这种方式在实际项目开发中用的很少

BeanFactory ac =
new XmlBeanFactory(new FileSystemResource("D:/work/tools/applicationContext.xml"));

Spring容器的实例化通过ClassPathXmlApplication

ApplicationContext继承自BeanFactory接口,拥有更多的企业级方法,推荐使用该类型,实例化方法如下:

//加载工程calsspath下配置文件实例化
ApplicationContext ac1 = new ClassPathXmlApplicationContext("applicationContext.xml");

该类会从类路径classPath中寻找指定的XML配置文件。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context" 
	xmlns:jdbc="http://www.springframework.org/schema/jdbc"  
	xmlns:jee="http://www.springframework.org/schema/jee" 
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:aop="http://www.springframework.org/schema/aop" 
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:util="http://www.springframework.org/schema/util"
	xmlns:jpa="http://www.springframework.org/schema/data/jpa"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
		http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
		http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
		http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
		http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd">

	<bean id="obj1" class="java.util.GregorianCalendar"></bean>
</beans>

通过FileSystemXmlApplicationContext创建

FileSystemXmlApplicationContext会从指定的文件系统路径(绝对路径)中寻找指定的XML配置文件,找到并装在完成ApplicationContext的实例化工作,其使用方法如下:

ApplicationContext ac2 = 
new FileSystemXmlApplicationContext("D:/work/tools/applicationContext.xml");

与ClassPathXmlApplication不同在于读取配置文件时不再从类路径读取,而实通过参数指定配置文件的位置。

1.2.1 Srping容器的使用

从本质上讲,BeanFactory和ApplicationContext仅仅只是一个维护Bean定义以及相互依赖关系的高级工厂接口。

通过BeanFactory和ApplicationContext我们可以访问bean定义。

  1. 首先在容器配置文件applicationContext.xml中添加Bean定

    <bean id="标识符" calss="Bean类型">
    
  2. 然后在创建BeanFactory和ApplicationContext容器对象,

    a. 调用Object getBean(String name):根据bean的id或name来获取指定Bean,获取之后需要进行强制类型转换。

    b. getBean(ClassrequiredType):根据类的类型来获取Bean的实例。由于此方法为泛型方法,因此获取Bean之后不需要进行强制类型转换。

1.2.2Bean的实例化

Spring容器创建Bean对象的方法有一下3种

  • 构造器来实例化

  • 静态工厂方法实例化

  • 实例工厂方法实例化

    1.用构造器来实例化

    <bean id="calendarObj1"     class="java.util.GregorianCalendar"/>
    <bean id="calendarObj1"   class="java.util.GregorianCalendar"/>
    

    id或name属性用于指定Bean名称,用于Spring中查找这个Bean对象

    calss用于指定Bean类型,会自动调用无参数构造器创建对象。

    2.使用静态工厂方法实例化

    <bean id="calendarObj02" class="java.util.Calendar" factory-method = "getInstance"/>
    

    id属性用于指定Bean名称;

    class属性用于指定工厂类型;

    factory-method属性用于指定工厂中创建对象的静态方法

    3.使用实例化工厂方法实例化

    <bean id="calendarObject3" class="java.util.GregorianCalendar"/>
    <bean id= "dateObject" factory-bean="calendarObject3" factory-method="getTime"/>
    

    id用于指定Bean名称;

    factory-bean属性用于指定工厂Bean对象;

    facatory-method属性用于指定工厂中创建对象的方法

1.2.3Bean

1.2.3.1Bean的名称

在Spring容器中,每个Bean都需要有名字(即标识符),该名字可以用元素的id或name属性指定

bean的别名

为已定义好的Bean,再增加另外以一个名字引用,可以使用指定

<alias name="formName" alias="toName"/>
1.2.3.2Bean的作用域

Spring容器在实例化Bean时,可以创建以下作用域的Bean对象

作用域描述
singleton在每个SpringIoC容器中一个bean定义对应一个对象实例,默认项
prototype一个bean定义对应多个对象实例
Request在一次HTTP请求中,容器返回该Bean的同一个实例。对不同的Http请求会产生一个新的Bean,仅限于HTTP Request内有效。
Session在一次HTTP Session中,容器返回该Bean的同一个实例。对不同的Http请求会产生一个新的Bean,仅限于HTTP Session内有效。
globalSession在一个全局的HTTP Session中,容器返回该bean的同一个实例;仅在基于portlet上下文时有效。
Application为每一个ServletContext对象创建一个实例。仅在Web相关的ApplicationContext中生效
Websocket为每一个websocket对象创建一个实例。仅在Web相关的ApplicationContext中生效

上面的Bean作用域,可以通过在标签中定义scope属性指定

1.2.3.3Bean的生命周期回调

指定初始化回调方

<bean id="exampleBean"   class="com.foo.ExampleBean" init—method="init">

指定销毁回调方法,仅适用于singleton模式的bean

<bean id="exampleBean"   class="com.foo.ExampleBean" destroy—method="destroy">

在顶级的元素中的default-init-method属性,可以为容器所有指定初始化回调方法

<beans default-init-method="init">
  <bean id = "exampleBean" class="com.foo.ExampleBean"/>
</beans>

在顶级的元素中的default-destroy-method属性,可以为容器所有指定销毁回调方法

<beans default-destory-method="destory">
  <bean id = “exampleBean" class="com.foo.ExampleBean"/>
</beans>
1.2.3.4 Bean延迟实例化

在ApplicationContext实现默认行为就是启动时将所有singletonbean提前进行实例化

如果不想让一个singleton bean在ApplicationContext初始化时被提前实例化,可以使用元素lazy-init=“true”属性改变

一个延迟初始化bean将在第一次被用到时实例化

<bean id="exampleBean" lazy-init="true" class="com.foo.ExampleBean"/>

在顶级的元素中的default-lazy-init属性,可以为容器所有指定延迟实例化特性

第二章 Spring IoC

2.1IOC概念

IoC全程是Inversion of Control ,被翻译为:控制反转;

IoC是指程序中对象的获取方式发生反转,由最初的new方式创建,转变为由第三方框架创建、注入(DI),它降低了对象之间的耦合度。

Spring容器是采用DI方式实现了IoC控制,IoC是Spring框架的基础和核心;

DI全称是Dependency Injection,被译为依赖注入;

DI的基本原理就是将一起工作具有关系的对象,通过构造方法参数或者方法参数传入建立关联,因此容器的工作就是创建bean时注入那些依赖关系。

IoC是一种思想,而DI是实现IoC的主要技术途径

DI主要有两种注入方式,即Setter注入和构造器注入

2.2 IOC应用

2.2.1Setter注入

通过调用无参构造器或无参static工厂方法实例化bean之后,调用该bean的setter方法,即可实现setter方式的注入。

public class Computer Implements Serializable{
	private String mainboard;//主板
	public String getMainboard(){
		return mainboard;
	}
	public void setMainboard(String mainboard){
		this.mainboard = mainboard;
	}
	//其他代码
}

在容器xml配置文件中,配置注入参数。

<bean id="computer" class="com.xyd.bean.Computer">
   <property name="mainboard" value="技嘉“>
   <property name="hdd" value="希捷“>
   <property name="ram" value="金士顿“>
</bean>

2.2.2构造器注入

基于构造器的注入是通过调用带有参数的构造器来实现的,容器在bean被实例化的时候,根据参数类型执相应的构造器。

Public class ModilePhone implements Serializable{
  private String cpu;
  private String ram;
  public ModilePhone(String cpu,String ram){
      this.cpu = cpu;
      this.ram = ram;
  }
}

构造器注入,可以强制给bean注入某些参数,比setter注入更严格

按构造参数索引指定注入

<bean id="phone" class="com.xyd.bean.MobilePhone"> 
  <constructor-arg index="0" value="ARM" >
  <constructor-arg index="1" value="2G" >
</bean>

2.2.3自动装配

Spring IoC容器可以自动装配(autowire)相互协作bean之间的关联关系,autowire可以针对单个bean进行设置,autowire的方便之处在于减少xml的注入配置

在xml配置文件中,可以在元素中使用autowire属性指定自动装配规则,一共有五种类型值

属性值描述
no禁用自动装配,默认值
byName根据属性名自动装配。此选项将检查容器并根据名字查找属性完全一致的bean,并将其与属性自动装配
byType如果容器中存在一个与指定属性类型相同的bean,那么将与该属性自动装配
constructor与byType的方式类似,不同之处在于它应用于构造器参数 ,使用时需要有一个关联属性的构造器
autodeted通过bean类来决定是使用constructor还是byType方式进行自动装配。如果发现默认的构造器,那么将使用byType

配置示例

<bean id = “computer" class="com.xyd.bean.Comupter">
  <property name=“mainboard”value=“技嘉“>
  <property name=“hdd”value=“希捷“>
  <property name=“ram”value=“金士顿“>
</bean>
<bean id="phone" class="com.xyd.bean.MobilePhone">
  <constructor-arg index="0" value="ARM"/>
  <constructor-arg index="1" value="2G"/>
</bean>
<bean id =“student” class=“com.xyd.bean.Student”
       autowire=“byType”>
</bean>

2.2.4注入基本值

l元素可以通过字符串指定属性或构造器参数的值。容器将字符串从java.lang.String类型转化为实际的属性或参数类型后给Bean对象注入

<bean id =“msg” class=“com.yxd.entity.MessageBean”>
	<property name=“name”>
		<value>张三</value>
	</property>
</bean>

也可以通过value属性指定基本值

<bean id="msg" class="com.xyd.entity.MessageBean">
  <property name="age" value="25">
</bean>

2.2.5注入Bean对象

注入外部Bean(引用方式,方便重用)

<bean id="computer" class="com.xyd.bean.Computer">
  <property name=“mainboard”value=“技嘉“/>
  <property name="hdd" value="希捷“/>
  <property name="ram" value="金士顿“/>
</bean>

<bean id="msg" class="com.xyd.bean.MessageBean">
  <property name="computer" ref="computer"/>
</bean>

2.2.6注入集合

通过、、及元素可以定义和设置与java类型种对应List、set、map及properties的属性值。

List集合注入

<bean id="msg" class="com.xyd.bean.Message">
  <property name="langs">
      <list>
          <value>java</value>
          <value>C#</value>
      </list>
  </property>
</bean>

Set集合注入

<bean id=“msg”class=“com.xyd.bean.MessageBean”>
	<property name="cities">
      <set>
          <value>北京</value>
          <value>上海</value>
          <value>广州</value>
      </set>
  	<property>
</bean>

Map集合注入

<bean id="msg" class="com.xyd.bean.MessageBean">
  <property name="score">
      <map>
          <entry key="数学“ value="78"/>
          <entry key="政治“ value="100"/>
          <entry key="英语“ value="40"/>
      </map>
  <property>
</bean>

Properties集合注入

<bean id=“msg” class=“com.xyd.bean.MessageBean”>
	<property name=“props”>
		<props>
			<prop key=“user”>xyd</prop>
			<prop key =“password”>123456</prop>
		</props>
    <property>
</bean>

引用方式list集合注入

<util:list id=“langList”>
	<value>c++</value>
	<value>pytion</value>
</util:list>
<bean id=“msg2”class=“com.xyd.bean.MessageBean”>
	<property name=“langs”ref=“langList”/>
</bean>

Set Map Properties都可以采用引用方式注入

<util:list/><util:set/><util:properties/

2.2.7注入Spring表达式值

Spring引入了一种表达式语言,这和统一的EL在语法上很相似,这种表达式语言可以读取一个bean对象/集合种的数据。

<util:properties id="const" location="classpath:const.properties"/>
<bean id="demo" class="com.xyd.bean.DemoBean">
	<property name="name" value="#{msg.name}“/>
	<property name="lang" value="#{msg.langs[0]}“/>
	<property name="score" value="#{msg.score.数学}“/>
    
	<property name="pageSize" value="#{const.PAGE_SIZE}“/>
</bean>

2.2.8注入null或空字符串

Spring将属性的空参数当作空String,下面给name属性设置了空String值(“”)

<bean id="msg" class="com.xyd.bean.MessageBean">
	<property name="name" value=""/>
</bean>

如果需要注入null值,可以使用元素

<bean id="msg" class="com.xyd.bean.MessageBean">
	<property name="name">
		<null/>
	</property>
</bean>

2.3基于注解的组件扫描

什么是组件扫描(compnent scanning)

指定一个包路径,Srping会自动扫描该包及其自包所有的组件类,当发现组件类定义前有特定的注解标记时,就将该组件纳入到Spring容器。等价于原有XML配置中的定义功能。

组件扫描可以替代大量XML配置的定义

2.3.1指定扫描类路径

使用组件扫描,首先需要在XML配置中指定扫描父级package路径

 <context:component-scan base-package="org.example"/>

上面配置,容器会自动扫描org.example包及其自包下所有组件,并实例化为bean。

自动扫描的注解标记

指定扫描路径后,并不是该路径下所有组件都扫描到Spring容器的,只有在组件类定义前面有一下注解标记时,才会扫描到Spring容器。

注解标记描述
@Component通用注解
@Named通用注解
@Repository持久层组件注解
@Service业务层组件注解
@Controller控制层组件注解

自动扫描组件的命名

当一个组件在扫描过程中被检测到时,会生成一个默认id值,默认id为小写开头的类名。也可以在注解标记中自定义id。下面两个组件id名分别是exampleBean和example。

@Component
public class ExampleBean implements Serializable{

}
@Component("example")
public  class ExampleBean implements Serializable{

}

指定组件的作用域

通常受Spring管理的组件,默认的作用域时“singleton”.如果需要其他的作用域可以使用@Scope注解,只要在注解中提供作用域的名称即可

@Component
@Scope("prototype")
public clsss ExampleBean implements Serializable{
    
}

指定初始化和销毁回调

@PostConstruct(初始化方法)和@PreDestroy(销毁方法)注解标记分别用于指定初始化和销毁回调方法,使用示例

@Component
public  class ExampleBean{
	@PostConstruct
	public void init(){//初始化回调方法
	}
	@PreDestroy
	public void destroy(){//销毁回调方法

	}
}

使用注解声明bean

使用Spring注解代替XML配置来声明bean,并使用注解管理bean的作用域和生命周期.

2.3.2Spring的全注解开发

由于在后面的Spring Boot课程当中,因为 Spring Boot是基于注解的开发Spring
IoC,所以我们下面将会介绍Spring的全注解开发,为后续为Spring Boot的学习打下基础。

2.3.4.1Spring注解开发入门

下面我们来看一个最为简单的例子。

1.首先定义一个User类

package com.xyd.entity;
public class User {
	private String name;
	private int age;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	@Override
	public String toString() {
		return "User [name=" + name + ", age=" + age + "]";
	}
}

2.再定义一个Java配置文件

package com.xyd;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.xyd.entity.User;
@Configuration
public class AppConfig {
	@Bean(name="user")
	public User getUser() {
		User user = new User();
		user.setName("刘德华");
		user.setAge(30);
		return user;
	}
	
}

注意以下两个注解的作用:

@Configuration 注解:告诉spring这是一个java配置文件(类),spring会根据这个java文件生成IoC容器

@Bean 注解:将当前方法返回的POJO装配到IoC容器中(作用等同于bean标签),括号中的name属性用于定义这个bean的名称,如果没有配置name,将会默认使用这个方法的名字作为bean的名称保存到Spring的IoC容器中。

3.基于AnnotationConfigApplicationContext获取Spring的IoC容器

package com.xyd.context;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.xyd.AppConfig;
import com.xyd.entity.User;

public class TestCase {
	public static void main(String[] args) {	
		ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
		User user = ctx.getBean("user",User.class);
		System.out.println(user);
	}
}

在这里插入图片描述

当然这只是一个很简单的方法,@Bean 注解也不是唯一创建 Bean
的方法,还有其他的方式可以让 IoC 容器装配 Bean,并且 Bean 之间还有依赖关系需要进一步处理,这些会在下面进行讲解。

2.3.4.2通过扫描装配Bean

如果所有的bean都是通过@Bean注解装配到 Spring IoC容器中,那将是一件很麻烦的事情。在Spring中允许我们进行扫描装配Bean到IoC容器。扫描装配Bean使用的注解是 @Component 和 ComponentScan。

@Component注解:标记哪个类需要被扫描装配到 Spring IoC容器

@ComponentScan注解:标记采用何种策略去扫描装配Bean(默认扫描当前类所在的包及其子包)

1.在实体类上加上@Component注解

package com.xyd.entity;

import org.springframework.stereotype.Component;

@Component
public class User {
	private String name;
	private int age;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	@Override
	public String toString() {
		return "User [name=" + name + ", age=" + age + "]";
	}
}

2.扫描装配Bean:为了让SpringIoC容器装配这个User,改造AppConfig

package com.xyd;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import com.xyd.entity.User;
@ComponentScan
@Configuration
public class AppConfig {
	
}

3.添加测试方法:

package com.xyd.context;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.xyd.AppConfig;
import com.xyd.entity.User;

public class TestCase {
	public static void main(String[] args) {	
		ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
		ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
		String[] beanName = ctx.getBeanDefinitionNames();
		for(String name :beanName) {
			System.out.println(name);
		}
	}
}

测试结果:

2.3.4.3@Scope注解

上面在通过XML
方式配置时说过,可以通过bean标签上的 scope 属性 指定bean的作用域

<bean id="user" scope="singleton" class="com.xyd.pojo.User"></bean>

在使用注解开发中,可以通过@Scope注解达到相同的效果

其中@Scope注解:指定当前Bean是单例作用域还是多例作用域,默认是单例

示例:

	/* @Component注解:用于标记此类会被Spring IoC容器扫描配置为Bean
	* @Component("userDao"): 其中配置的“userDao”将作为Bean的名称,也可以不指定
	*         如果不指定,IoC容器会将类名第一个字母小写,其余不变作为bean的名称
	* @Scope注解:指定bean的作用域,如果不指定,默认是单例,可以指定为 prototype */
	@Component("userDao")
	@Scope("prototype")
	public class UserDao {
	    
	}

2.3.4.4属性赋值(@Value)

注入Spring表达式

@Value注解可以注入Spring表达式

首先在XML配置中指定要注入的properties文件

<util:properties id ="const" location="classpath:const.properties"/>

然后再属性或Setter方法前使用@Value注解

@Component
public class DemoBean implements Serializable{
	@value("#{const.PAGE_SIZE}")
	private int pageSize;

}

1)例如:为User对象的name属性和age属性赋值

		@Component
		public class User {
		    //提供私有成员变量
		    @Value("赵云")
		    private String name;
		    @Value("24")
		    private Integer age;
		    ...
}

2)测试:获取User的Bean实例并输出到控制台查看

package com.xyd.context;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.xyd.AppConfig;
import com.xyd.entity.User;

public class TestCase {
	public static void main(String[] args) {
		ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
		
        User user = ctx.getBean("user",User.class);
		System.out.println(user);
	}
}

3)运行结果为:可以看出已经成功为User对象的name、age属性赋了值
在这里插入图片描述

2、也可以将属性值写到配置文件中,再通过@Value注解及${ }符为Bean的属性赋值,例如:

1)在项目src/main/resource/下提供config.properties文件,添加两行配置:

config.name=马云 
config.age=28

2)在AppConfig配置类中,通过@PropertySource注解读取config.properties文件中的key/value到运行环境中

/*
@PropertySource注解:读取外部配置文件中的key/value,并保存到运行环境中
*/
@PropertySource("classpath:/config.properties")
@Configuration
@ComponentScan
public class AppConfig {
    ...
}
 

3)修改User类中的代码,通过@Value注解及${}符为Bean的属性赋值

@Component
public class User {
    //提供私有成员变量
    @Value("${config.name}")
    private String name;
    @Value("${config.age}")
    private Integer age;
    ...
}

4)测试:可以看出已经成功为User对象的name、age属性赋了值

User [name=马云, age=28]

2.3.4.5指定依赖注入关系

具有依赖关系的Bean对象,利用下面任意一种注解都可以实现关系注入

自动装配注解

@Autowired是我们使用得最多的注解之一,可以将定义好的Bean作为属性值注入到其他Bean的属性上,而这一过程是自动完成的。

@Autowired自动注入的原则:

1)默认优先按照类型从Spring容器中进行查找bean,如果找到一个则直接注入,如果没有找到,则抛出NoSuchBeanDefinition异常。

2)但如果该类型的bean对象在spring容器中有多个,此时还会基于属性名进行匹配,如果属性名和spring中bean的名字相同,则直接注入,如果都不匹配则直接抛出NoUniqueBeanDefinition异常。

3)当然,我们可以通过@Qualifier注解,显式的为属性指定要注入哪一个名字的bean(此注解必须配合@AutoWired注解使用)。

1、下面测试@Autowired注解的使用

​ 1)修改User类中的代码:添加UserInfo属性(通过@Autowired注解为注入值),并提供对应的getter和setter方法,最后重写toString方法

		@Component
		public class User {
		    //提供私有成员变量
		    ...
		    @Autowired
		    private Animal animal;
		    //提供getter和setter方法
		    ....
		    public Animal getAnimal() { return animal; }
		    public void setAnimal(Animal animal) { this.animal = animal; }
		    //重写toString方法
		    @Override
		    public String toString() {
		        return "User [name=" + name + ", age=" + age + ", animal=" + animal + "]";
		    }
		}

2)添加Animal接口和Dog类,让Dog实现Animal接口,再通过@Component注解将Dog作为bean装配到spring容器中:

		package com.tedu.pojo;
		//Animal接口
		public interface Animal { 
		    
		}
		
		package com.tedu.pojo;
		import org.springframework.stereotype.Component;
		//Dog实现类
		@Component("dog")
		public class Dog implements Animal{ 
		    
		}

3)测试:

		/*
		* 2、测试@Autowired注解
		*     @Autowired注解:将定义好的bean作为属性值注入到其他Bean的属性上
		*/
		@Test
		public void testAutowired(){
		    // 获取Spring的IoC容器
		    ApplicationContext ctx = new AnnotationConfigApplicationContext( AppConfig.class );
		    
		    // 使用getBean方法获取对应的POJO并输出
		    User user = (User)ctx.getBean( "user" );
		    System.out.println( user );
		}

测试结果如下:

			User [name=马云, age=28, animal=com.tedu.pojo.Dog@55040f2f]

从打印结果可以看出,@Autowired注解成功为Animal类型的animal属性注入了一个Dog类型的Bean。底层是根据animal属性的类型(Animal)到Spring容器中寻找该类型的bean,如果刚好找到一个,就可以完成注入。

2、那么,如果UserInfo类型的bean对象在spring容器中有多个,@AutoWired注解该如何注入?

​ 1)再添加一个Cat类并实现Animal接口,再通过@Component注解将Cat作为bean装配到spring容器中:

		package com.tedu.pojo;
		import org.springframework.stereotype.Component;
		
		@Component("cat")
		public class Cat implements Animal{
		    
		}

​ 2)此时Animal类型的bean在Spring容器中有两份(bean的name分别为:dog和cat),再次运行测试,程序会抛出如下异常:

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.tedu.pojo.Animal' available: expected single matching bean but found 2: cat,dog

解决方法1:

​ 可以将User类中的animal属性名改为其中一个bean的名字(dog或cat);

​ 或者将其中一个bean的名字改为User类中的animal属性名,再运行测试。

解决方法2:

​ 也可以通过@Qualifier注解显式的为属性指定要注入哪一个名字的bean

 @Autowired
 @Qualifier("dog")
 private Animal animal;

解决方法3:

​ 还可以通过@Primary注解指定默认首选的Bean。

​ 即注入依赖的过程中,当有多个候选者的时候,

​ 可以指定哪个候选者为主要的候选者。

@Component
@Primary
public class Cat implements Animal {
}

@Autowired/@Qualifier

可以处理构造器注入和setter注入

​ @AutoWried写在set方法前面,声明需要为其注入bean

​ @Qualifiler写在参数前面,声明需要注入的bean的ID值

@Component
Public class Teacher Implements Serializable{
	private Computer computer;
	@Autowired
	public void setComputed(@Qualifier("computer") Computer computer){
		this.computer = computer;
		System.out.println("Teacher");
	}
}

​ 注入的对象单例时,@Qualifier可以省略。此时,Spring按照类型匹配参数。

​ @Autowired也可以写在属性上,作用和写在set方法上类似,

​ 但只会执行一行代码:this.computer = computer;

@Inject/@Named

和@Autowire用法一致,需要额外导包

​ @Inject注解标记是Spring3.0开始增添的对JSR-330标准的支持,使用前需要添加JSR-330的jar包javax.injedct-jar

​ @Inject注解用法和@Autowired一致,其中

​ @Inject等价于@Autowired

​ @Named等价于@Qualifier

@Resource

只能处理setter注入,但大部分情况都是Setter注入

​ @Resource注解只能用于setter注入,但更简单

@Component
Public class Teacher Implements Serializable{
	private Computer computer;
	@Resource(name=“computer”)
	public void setComputed(Computer computer){
		this.computer = computer;
		System.out.println(Manage);
	}
}

注入的对象单例时(name=“computer”)可省略。此时,Spring按照类型匹配参数。

@Resource也可以写在属性上,作用和写在set方法上类似,但只会执行一行代码:

this.computer = computer

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XYDrestart

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值