Spring原理简介

Spring简介

Spring的历史

 Spring的基础架构起源于2000年早期,创始人为毕业于悉尼大学的音乐学博士RodJohnson。2003年2月,Spring架构正式成为开源项目,并发布于SourcesForge中。

Spring工作原理

 Spring是一个轻量级的控制反转(IoC) 和面向切面(AOP)的容器框架。我们不需要通过new关键词创建对象,而是在配置文件中配置JavaBean。当对象与对象之间有依赖关系的时候,我们也只需要在配置文件中把依赖关系体现出来,这些被配置的Bean将会纳入Spring管理,放置于Spring容器中。我们只需要写很少量的代码便可得到Spring容器,并且从Spring容器中得到配置的JavaBean。这种解决依赖性的方法即控制反转(IOC, 即Inversion of Control)或者依赖注入(Dependency Injection), 从技术上来说,就是用某种容器组织相互依赖的对象。除了10C之外,Spring还可以将分散在系统的公共代码统一组织起来,在运行的时候加入到系统中,这就是AOP(面向切面编程)。

Spring框架简介

Spring是用于简化企业应用程序开发过程的开源框架,属于轻量级的控制反转(I0C)和面向切面编程(AOP, 即Aspeet Oriented Proraming)的容器框架,解决了J2EE开发中许多常见的问题。我们需要了解一 下Spring中的一 些名词:
(1)轻量级:以所占大小及系统开销分析,Spring属于轻量级。整个Spring框架可以打包为1M左右的JAR包,且系统开销较小。同时,Spring为非侵入式,若系统基于Spring开发,其所含的对象一般不依赖于Spring的类。
(2)I0C: IOC使对象被动接受依赖类, 而并非主动获取。也就是说,告诉Spring“你”是什么,“你”需要什么对象,然后Spring会在系统运行到适当的时候,把“你”要的对象主动给“你”,同时也把“你”交给其他需要“你”的对象。所有的类的创建、销毁都由Spring来控制,控制对象生存周期的不再是引用它的对象,而是Spring。对于某个具体的对象而言,使用Spring之前是它控制其他对象,现在是所有对象都被Spring控制,所以叫控制反转。在系统运行中,动态的向某个对象提供它所需要的其他对象,这一点是通过DI (依赖注入)实现的。
(3)AOP:面向切面编程(也叫面向方面编程),关注系统的横向切面。通俗点说就是把代码“切开”,然后在需要的位置上动态加入公共代码。比如日志或者事务支持。
(4)容器: Spring 是一个包含且管理系统对象生命周期和配置的容器,在使用Spring应用开发的时候,几乎所有的JavaBean 对象都需要Spring来“盛放”。Spring容器的作用是管理对象。
(5)Spring框架: Spring能够通过简单的组件组合为复杂的系统。Spring框架为分层架构,由7个定义良好的模块组成,各模块构建于核心容器之上,核心容器定义了创建、配置及管理Bean的方式。

  1. Spring Core,核心容器,用于提供Spring框架的其主要基本功能,其主要为组件为BonFoctory,是工厂 模式的实现。BeanFactory使用反向控制(ioc将模式将应用程序的配置及依赖性规范与实际应用程序代码分开。
  2. Sping Context: 核心楼块的BanFatory使Spring成为容器,上下文(Context)模块使其成为框架。此模块扩展TBeanFactory的概念,增加了对国际化18即Internationalization)消息、事件的传播以及验证的支持: 同时,此模块提供诸多企业服务,如电子邮件、 JNDI访问、 EJB集成、 远程以及时序调度(Scheduling)服务,支持对模版框架(如Velocity、 FreeMarker)的集成。
  3. Spring AOP :通过配置管理特性,Spring AOP模块将面向切面编程功能集成至框架中,使Spring框 架管理的任何对象均支持AOP. Spring AOP模块向基于Spring的应用程序中的对象提供事务管理服务。此模块无需依赖于EJB组件,可以使用Spring AOP将声明式事务管理集成至应用程序中。
  4. Spring DAO: JDBC DAO抽象层提供了意义重大的异常层次结构,简化了错误处理过程并极大地减少了需要编写的异常代码(如打开或关闭连接),运用此结构可以管理异常、处理不同数据库供应商抛出的错误消息。SpringDAO的面向JDBC异常遵从通用的DAO异常层次结构。
  5. Spring ORM :Spring框架中插入了若FORM框架,提供ORM的对象关系工具,包括JDO. Hibernate以及iBatis sqL Map,都遵从Spring的通用事务及DAO弄常层次结构。
  6. Spring Web: Web上下文模块建立在应用程序上下文模块之上,向基于eb的应用程序提供上下文,因而Sprig框架 支持5truts集成。同时, Teb模块简化了清求的处理过程以及将请求参数绑定至域对象的工作。
  7. Sprins wC iwC 柜架是个全功能的构建 Veb应用程序的WVC 实现。通过家略接口,mvc框架变为高度可匹配,它容纳了大量试图技术,包括jsp、Velocity、Titles、iText及POI。

MyEclipse添加spring支持如下图:

1.右键选择需要添加spring的项目:选择MyEclipse
在这里插入图片描述2.然后选择Add Spring
在这里插入图片描述
3.选择spring的版本号
在这里插入图片描述
这样就可以完成所需要的项目spring添加。

Spring Bean封装机制

Spring Bean

 Spring以Bean的方式管理所有的组件,J2EE 的全部组件都使用Bean管理。在Spring中,除了标准的JavaBean,其他任何对象和组件都可以作为Bean.应用中各层的对象均由Spring管理,对象以Bean方式存在。Spring负责创建Bean的实例并管理其生命周期,Bean运行于Spring的容器。Spring上下 文是生产Bean的工厂,Bean是Spring工厂生产的实例。Spring产生工厂时,需要确定每个Bean的实现类; Bean实例的使用者面向接口,因此无须关心Bean实例的实现类。Spring工厂负责维护Bean实例的实例化,使用者则无须关心。Bean的定义通常使用XML配置文件,正确定义的Bean由Spring提 供实例化以及依赖关系的注入等。最简单的Spring配置文件代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans
	xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
</beans>

 Spring的schemaLocation详细规定了Spring配置文件的合法元素,各元素出现的先后顺序、各元素的合法子元素以及合法属性等。
 增加对实体对象管理的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"
	xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
	<bean id="user" class="com.hr.entity.UserVo" abstract="false" lazy-init="default" autowire="default"/>
</beans>

上述代码中定义了UserVo对象。xml中Bean节点的部分属性如下:

<bean 
id="beanId" 
name="beanName" 
class="beanClass" 
parent="parentBean" 
abstract="true | false" 
scope="prototype | singleton"
lazy-init="no | btName | by Type | construcyor | auto detect |default"/>
</beans>

Bean的属性如下表:

属性含义
idBean的唯一标识名,必须为合法的XML ID, 在整个XML文档中唯,如果没 有特殊需要,我们在标识一个Bean的时候,一般推荐使用id.
name用于为id创建一个或多 个别名,可以是任意字母或者符号,多个别名之间以逗号或空格分隔。
class用于定义类的全限定名(包名加类名),Spring在创建对象的时候需要用到此属性,因此该属性不能指定接口。
parent子类Bean定义其所引用的父类Bean,继承父类的所有属性。值得一提的是,在写代码的时候,即便是两个类之间没有继承关系,我们同样可以使用该属性。
abstract用于定义Bean是否为抽象Bean,默认为false,表示此Bean将不会被实例化。一般用于父类Bean,可以在子类继承的时候使用。
scope用于定义Bean的作用域,singleton表示 在每个Spring IoC容 器中一个bean定义对应一个对象实例,即Spring使用 单例模式获取实例。prototype表示一个bean定义对应多个对象实例,即非单例模式
lazy-init用于定义Bean是否实现初始化,默认为default。若为true,将在BeanFactory启动时初始化所有Singleton Bean; 若为false, 则在Bean请求时创建Singleton Bean
autowire用于定义Bean的自动装配方式,默认为default,包括不使用自动装配功能、通过Bean的属性名实现自动装配、通过Bean的类型实现自动装配、通过Bean类的反省(Introspection)机制决定选择使用constructor或者byType。

Application Context

 Spring包括两种不同的容器: BeanFactory 和ApplicationContexto.BeanFactory提供基本的I0C支持; ApplicationContext则基于BeanFactory,提供应用程序框架服务。Spring提供了BeanFactory与ApplicationContext 的多个实现。ApplicationContext包括BeanFactory 的全部功能,除非应用程序对性能要求很高时才考虑BeanFactory,其他情况下建议优先使用ApplicationContext。
应用中出现多个配置文件时,应采用BeanF actory的子接口ApplicationContext创建Spring容器的代码如示例:

//搜索classpath路径,以classpath路径下的applicationContext . xml创建对象
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext . xml");

 在实际应用中,会将Spring配置分别放在不同的配置文件中,如果一个应用中有两个配置文件application. xml和bean. xml,则创建容器实例的方法如示例1.4所示。

//搜索clsspath路径,以claspath路径 下的
//applicationContext。xm1和bean. xml创建Applicat ionContext.
ApplicationContext applicationContext = new ClassPathXmlApplicationContext (new Stringl]{"pplicationContext.xm1", "bean.xm1");

ApplicationContext接口包括以下3个重要方法:

(1)containsBean (String name)方法。

//判断Spring容器是否包含ID为user 的Bean
boolean flag-applicationContext.containsBean ("user");

(2)getBean(String name)方法。

//返回ID为user的Bean
UserVo userBean = (UserVo) applicationContext.getBean ("user");
//该方法的功能是从Spring容器中获取一个对象,该方法的参数可以是Spring配置文件中Bean的d或者name,如果name指定了多个标识,只需传入一个标识。

(3)getType(String name)方法。

//返回:ID为user的类型
Class beanType= applicationContext.getType ("user");

示例:从Spring容器中获取一个user对象,并输出user的信息。

package com.hr.controller;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.hr.entity.UserVo;

public class test {
	public static void main(String[] args) {
		ApplicationContext application = new ClassPathXmlApplicationContext("applicationContext.xml");
	    UserVo user = (UserVo) application.getBean("user");
	    user.setName("张三");
	    user.setAge(12);
	    System.out.print(user);
	}

}

Spring DI和IOC

什么是Spring的依赖注入

 在生活中,依靠别人或者别的事务而不能独立或者自立,我们称之为依赖。
 依赖指的是二个实例之间的关系。其中一个实例是独立的,另一个实例是非独立的(依赖的),它依靠另一个实例。比如计算机对象,它包含主机对象和显示器对象。如果没有主机对象或者显示器对象,则计算机对象就是不完整的,不能正常使用,我们就说计算机对象依赖于主机对象和显示器对象。
 计算机对象离不开主机对象和显示器对象,程序在运行过程中,我们必须给计算机对象提供它所需要的主机对象和显示器对象,把主机对象和显示器对象像“打针”一样提供给计算机对象,这个过程就叫做注入。也就是说,如果一个对象需要另外一个对象才能正常使用,我们在程序运行的时候,给该对象提供它所需要的对象,这就是“依赖注入”。我们知道,Spring将会管理几乎所有的Bean对象,而对象与对象之间可能存在依赖关系,在程序运行过程中,Spring把我们所需要的对象都拼装好,这就是Spr ing的依赖注入。
 在传统的Java设计中,当Java实例的调用者创建被调用的Java实例时,要求被调用的Jave类出现在调用者的代码中,二者之间无法实现松耦合。工厂 模式则对此进行了改进,使调用者无须关心被调用者的具体实现过程,只要获得符合某种标准(接口)的实侧即可使用。其调用的代码面向接口编程,支持调用者与被调用者解耦,因此工厂模式得以大范围地使用,但在工厂模式中,调用者需要自行定位工厂,与特定工厂耦合,所以仅在一定程度上实现了调用者与被调用者的解耦。Spring 的出现使调用者无须自行定位工厂,当程序运行至需要被调用者时,系统将自动提供被调用者实例。事实上,调用者与被调用者均由Spring管理,二者之间的依赖关系由Spring提供。

示例:
 设计一个主机类(MainFrame)

public class MainFrame {
   private String modelType;
   public void printMainFrameInfo(){
	   System.err.println("主机型号"+modelType);
   }
public String getModelType() {
	return modelType;
}
public void setModelType(String modelType) {
	this.modelType = modelType;
} 
}

 接口(Display)

package com.hr.service;
public interface Display {
   public void printDisplayInfo();
}

 业务实现层(impl)

package com.hr.service.impl;
import com.hr.service.Display;
public class SamSungDisplay implements Display{
	public void printDisplayInfo() {
		// TODO Auto-generated method stub
		System.err.println("显示器:三星");
	}
}
package com.hr.service.impl;
import com.hr.service.Display;
public class LgDisplay implements Display{
	public void printDisplayInfo() {
		// TODO Auto-generated method stub
		System.err.println("显示器:Lg");
	}
}

 计算机类

package com.hr.controller;
import com.hr.entity.MainFrame;
import com.hr.service.Display;
public class Computer {
   private MainFrame mainFrame;
   private Display display;
   public void printComputerInfo(){
	   System.err.println("计算机配置如下:");
	   mainFrame.printMainFrameInfo();
	   display.printDisplayInfo();
   }

public MainFrame getMainFrame() {
	return mainFrame;
}
public void setMainFrame(MainFrame mainFrame) {
	this.mainFrame = mainFrame;
}
public Display getDisplay() {
	return display;
}
public void setDisplay(Display display) {
	this.display = display;
}  
}

applicationContext.xml

<bean id="samsung" class="com.hr.service.impl.SamSungDisplay"/>
<bean id="lg" class="com.hr.service.impl.LgDisplay"/>
<bean id="mainFrame" class="com.hr.entity.MainFrame">
   <property name="modelType" value="三星高配主机"/>
</bean>
<!-- 计算机的配置 -->
<bean id="computer" class="com.hr.controller.Computer">
  <!-- 设置注入主机,name对应计算机的属性,ref对应所依赖的bean -->
  <property name="mainFrame" ref="mainFrame"/>
  <property name="display" ref="lg"/>
</bean>

输出

package com.hr.controller;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class appCon {
    public static void main(String[] args) {
		ApplicationContext application = new ClassPathXmlApplicationContext("applicationContext.xml");
		Computer computer = (Computer)application.getBean("computer");
		computer.printComputerInfo();
	}
}

结果如图:
在这里插入图片描述

设值注入方式

 设值注入是指通过setter方式传入被调用者的实例,所以Bean的属性要求有对应的setter和getter方法。此方式因简单直观而得以广泛使用。配置文件如下:

<!-- 计算机的配置 -->
<bean id="computer" class="com.hr.controller.Computer">
  <!-- 设置注入主机,name对应计算机的属性,ref对应所依赖的bean -->
  <property name="mainFrame" ref="mainFrame"/>
  <property name="display" ref="lg"/>
</bean>

构造注入方式

 构造注入是指通过构造方法完成依赖关系的注入,并非setter方法。将以上设值注入按构造注入重新实现,则需要在computer中增加带参构造方法,配置文件如下:

<!-- 计算机的配置 -->
<bean id="computer" class="com.hr.controller.Computer">
  <!-- 设置注入主机,ref对应所依赖的bean -->
  <constructor-arg index="0" ref="mainFrame"/>
  <constructor-arg index="0" ref="samsung"/>
</bean>

自动注入

 Spring容器可以自动注入(autowire)相互协作bean之间的关联关系。因此,如果可能的话,可以自动让Spring通过检查BeanFactory中的内容,来替我们指定bean的协作者(其他被依赖的bean)。由于autowire可以针对单个bean进行设置,因此可以让有些bean使用autowire,有些bean不采用。autowire的方便之处在减少或者消除属性或构造器参数的设置,这样可以简化配置文件,如果直接使用property和constructor-arg注入依赖的话,那么将总是覆盖自动装配,在xml配置文件中,可以在元素中使用autowire属性指定,如下表所示。

模式说明
no不使用自动装配。必须通过ref元素指定依赖,这是默认设置。由于显式指定协作者可以使配置更灵活、更清晰,因此对于较大的部署配置,推荐采用该设置。
byName根据属性名自动装配。此选项将检查容器并根据名字查找与属性完全一致 的bean, 并将其与属性自动装配。
byType如果容器中存在一个与指定属性类型相同的bean,那么将与该属性自动装配。如果存在多个该类型的bean,那么将会抛出异常,并指出不能使用byType方式进行自动装配。若没有找到相匹配的bean,则属性不会被设置。

配置文件如下:

<bean id="computer" autowire="byName" class="com.hr.controller.Computer">
  <property name="mainFrame" ref="mainFrame"/>
  <property name="display" ref="lg"/>
</bean>

 由于使用byName自动装配,容器会检查ID和Computer的两个属性mainFrame以及display名称匹配的Bean并注入,由于存在ID为mainFrame的Bean, 所以Computer的mainFrame属性被自动注入,而display是 显式注入,所以覆盖了display属性的自动注。

集合属性

 通过< list />、< set />、 < map />及< props />元素可以定义和设置与Java Collection类型对应List、Set、 Map及Properties的值。

示例:

//型对应List、Set、 Map及Properties的值。 
//示例1. 18中定义TestBean类,该类有四个属性,分别是List、Map、Properties, Set类型。
private List list;
private Map map;
private Properties properties;
private Set set;

 对于TestBean类的配置如下:

<bean id="TestBean" class="com.hr.controller.TestBean">
   <!-- list属性的配置 -->
   <property name="list">
     <list>
       <value>v1</value>
       <value>v2</value>
     </list>
   </property>
   <!-- map属性的配置 -->
   <property name="map">
     <map>
       <entry key="k1">
        <value>v1</value>
       </entry>
       <entry key="k2">
        <value>v2</value>
       </entry>
     </map>
   </property>
   <!-- prop属性的配置 -->
   <property name="prop">
     <props>
       <prop key="k1">str1</prop>
       <prop key="k2">str2</prop>
     </props>
   </property>
   <!-- set属性的配置 -->
   <property name="set">
     <set>
      <value>v1</value>
       <value>v2</value>
     </set>
   </property>
</bean>

 程序运行的时候,我们从Spring容器中获取testBean实例,该实例的四个集合属性中将会包含指定的对象。

Spring注入方式的比较

1.设值注入的特点
 对于习惯了传统JavaBean开发的程序员而言,通过setter方法设定依赖关系更加直观自然。当依赖关系(或继承关系)较复杂时,构造注入方式的构造函数相当庞大,且需要在构造函数中设定所有依赖关系,此时使用设值注入方式则简单快捷。除此之外,某些第三方类库要求组件必须提供默认的构造函数(如Struts中的Action),此时构造注入方式的依赖注入机制会突显局限性,难以完成预期的功能,必须通过设值注入实现。
2.构造注入的优点
 在构造期即创建完整、合法的对象,构造注入无疑是此Java设计原则的最佳响应者。
 而且构造注入还避免了编写繁琐的setter方法,所有的依赖关系都在构造函数中设定,使依赖关系集中呈现,可读性增加。由于不存在setter方法,而是在构造时由容器一次性设定依赖关系。因此,组件在创建之后即处于相对稳定状态,无需担心上层代码在调用过程中执行setter方法时破坏组件之间的依赖关系。对于Singleton模式组件,这种破坏将对整个系统产生重大的影响。通过构造注入,可以在构造函数中决定依赖关系的注入顺序。对于大量依赖外部服务的组件而言,依赖关系的获取顺序至关重要。

基于注解的容器配置

 基于注解(Annotation)的配置有越来越流行的趋势,Spring顺应这种趋势,从2.5版起提供了完全基于注解配置Bean、装配Bean的功能,可以使用基于注解的Spring IOC替换原来基于xml的配置。

使用@Component注解配置bean

 只需要在类的定义语句上加上一个@Component注解,就将该类定义为一个bean,如下:

@Component
public class Computer {
   private MainFrame mainFrame;
   private Display display;
   public void printComputerInfo(){
	   System.err.println("计算机配置如下:");
	   mainFrame.printMainFrameInfo();
	   display.printDisplayInfo();
   }
   }
@Component
public class MainFrame {
   private String modelType;
   public void printMainFrameInfo(){
	   System.err.println("主机型号"+modelType);
   }
 }
 @Component
 public class SamSungDisplay implements Display{
	public void printDisplayInfo() {
		// TODO Auto-generated method stub
		System.err.println("显示器:三星");
	}
}
 @Component
 public class LgDisplay implements Display{
	public void printDisplayInfo() {
		// TODO Auto-generated method stub
		System.err.println("显示器:Lg");
	}
}

 我们通过@Component注解分别将Computer 、MainFrame 、SamSungDisplay 、LgDisplay 配置成bean。bean名称默认为将第一个字母转换成小写的类名。如Computer 类的bean默认名称是computer。xml配置如下:

<bean id="computer" class="com.hr.controller.Computer"/>
<bean id="mainFrame" class="com.hr.entity.MainFrame"/>
<bean id="lgDisplay" class="com.hr.service.impl.LgDisplay"/>
<bean id="samSungDisplay" class="com.hr.service.impl.SamSungDisplay"/>

 @Component注解的唯一一个可选参数是value,用于指定bean的名称(即id,所以必须是唯一的),声明Computer类为一个bean,id为computer。如下:

@Component(value="computer")
public class Computer{}

 可以简写为:

@Component("computer")
public class Computer{}

 Spring还提供了更加细化的用于定义bean的注解形式:@Repository、@Service、@Controller,他们分别对应数据访问层bean,业务层bean和视图层bean。目前版本中,这些注解与@Computer的语义是一样的,完全通用,在Spring以后的版本中可能会给他们追加更多的语义。所以,我们推荐使用@Repository、@Service、@Controller来替代@Computer。

扫描@Component标注的类

 在使用@Component注解后,Spring容器必须启用类扫描机制,以找到所有使用@Component标注的类,将他们作为bean来管理。从Spring2.5开始,对context命名空间进行了扩展,提供了这一功能,请如下配置,引入context命名空间,并扫描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"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
	http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
	http://www.springframework.org/schema/context
	http://www.springframework.org/schema/context/spring-context-4.3.xsd
    <context:component-scan base-package="com.hr.controller.computer"></context:component-scan>
    </bean>

 Spring容器在初始化时会扫描<context:component-scan />标签的base-package属性指定的类包及其递归子包中所有的类。找出@Component标注的类,将他们配置成bean。然后,我们就可以通过Spring容器的工厂方法获取并使用bean了。如下:通过Spring容器获取Computer bean。

ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Computer c = ac.getBean(Computer.class);

使用@Scope注解配置bean的作用域

 @Scope用于定义bean的作用域,singleton表示 在每个Spring IoC容器中一个bean定义对应一个对象实例,即Spring使用 单例模式获取实例。prototype表示一个bean定 义对应多个对象实例,即非单例模式,我们常称作多例。默认情况下,Spring bean的作用域为singleton。如下:将Computer类配置成一个“多例”的bean :

@Component
@Scope(value="prototype")
public class Computer{}

可以简写为:

@Component
@Scope("prototype")
public class Computer{}

使用@Autowired注解

 从Spring 2.5版本起,Spring引入了@Autowired注解,它可以对类成员变量、方法及构造函数进行标注,以完成自动装配依赖的工作。如下:使用@Autowired为成员变量自动注入依赖。

@Component
@Scope("prototype")
public class Computer {
   @Autowired
   private MainFrame mainFrame;
   @Autowired
   private Display display;
   public void printComputerInfo(){
	   System.err.println("计算机配置如下:");
	   mainFrame.printMainFrameInfo();
	   display.printDisplayInfo();
   }
   }

 将@Autovired标注于实例凤性ainFrenedisploy上面,Sprin将直按采用Jave反射机制获取mainFrame和display属性的类型,再根据类型查找“唯一”匹配的bean来进行依赖自动注入(如果bean的类型与属性的类型相同,或者bean的类型是属性类型的子类型或接口实现,则类型匹配)。
 由于和mainFrame属性类型匹配的bean只有MainFrame个,所以自动装配依赖可以顺利进行。但是和display属性的类型匹配的bean有两个(SamSungDisplay和LgDisplay都实现了Display接口,而display属性类型正是 Display) ,此时Spring应用容器不知道该用哪一个bean为Computer的display属性注入依赖值,从而导致创建Computer bean失败,抛出BeanCreationException。
 那么如何解决根据类型返回多个ben导数的创建ban失败的问题呢?答案是指定需要注入的bean的名称。要为Computer bean的display属性注入三星显示器,就需要告诉Spring我们需要的是符合Display类型,且id为sanSungDisplay的bean。指定依赖bean名称的方法有二种:

  1. 把属性名称作为依赖bean名称。
  2. 使用@Qualifier注解明确指定依赖bean的名称。
     将display属性改为sanSungDisplay,当Spring应用容器根据属性类型返回多个bean时,会继续以反射的方式获得属性的名称sanSungDisplay,从而找到同名的bean。

如下:

@Component
@Scope("prototype")
public class Computer {
   @Autowired
   private MainFrame mainFrame;
   @Autowired
   private Display display;
   public void printComputerInfo(){
	   System.err.println("计算机配置如下:");
	   mainFrame.printMainFrameInfo();
	   sanSungDisplay.printDisplayInfo();
   }
   }

也可以使用setter方法,构造方法和其他的方法,根据参数类型和名称来注入依赖bean。如下:

@Component
@Scope("prototype")
public class Computer {
   private MainFrame mainFrame;
   private Display display;
   @Autowired
   public Computer(MainFrame mainFrame,Display sanSungDisplay){
	  super();
	  this.mainFrame = mainFrame;
	  this.display = sanSungDisplay;
   }
   .....
   }

使用@Qualifier注解为自动注入指定依赖bean的名称

 Spring允许我们通过@Qualifier注解指定注入Bean名称。
示例:

@Component
@Scope("prototype")
public class Computer {
   @Autowired
   private MainFrame mainFrame;
   @Autowired
   @Qualifier("sanSungDisplay")
   private Display display;
   public void printComputerInfo(){
	   System.err.println("计算机配置如下:");
	   mainFrame.printMainFrameInfo();
	   sanSungDisplay.printDisplayInfo();
   }
   }

使用@Qualifier注解为方法指定要注入的依赖bean的名称

@Component
@Scope("prototype")
public class Computer {
   private MainFrame mainFrame;
   private Display display;
   @Autowired
   public Computer(MainFrame mainFrame,@Qualifier("sanSungDisplay") Display sanSungDisplay){
	  super();
	  this.mainFrame = mainFrame;
	  this.display = sanSungDisplay;
   }
   .....
   }

**总结:**使用@Autowired注解自动装配依赖的过程如下:

  1. 首先根据属性的类型(或方法、构造方法参数的类型)在Spring应用的容器中查找类型匹配的bean。
  2. 如果没有类型匹配bean,抛出BeanCreationExecption;如果只有一个,则注入依赖,完成自动装配,如果不只一个,则继续执行步骤3。
  3. 如果通过@Qualifier指定了bean,则从所有符合类型的bean中返回指定的bean,完成自动装配;如果没有通过@Qualifier制定bean名称。则通过反射技术获取当前属性的名称作为bean名称返回指定的bean,完成自动装配。

使用@Resource注解注入依赖

 Spring不但支持 自己定义的@Component、@Scope、@Autowired、@Qulifier注解,还支持几个由JSR-250规范定义的注解,它们分别是@Resource、PostConstruct以及@PreDestroy。
 @Resource的作用相当于Autowired,只不过Autorired默认按DyType自动注入,@Rescurce默认按byName自动注入罢了。@Resource有两个属性是比较重要的,分别是name和type,Spring将@Resource注解的name属性解析为Bean的名字,面type属性则解析为Bean的类型。所以如果使用name属性,则使用byNane的自动注入策略,而使用type属性时则使用byType自动往入策略。如果既不指定nne也不指定type属性,这时将通过反射机制使用byNeme自动注入策略,如下:

@Component
@Scope("prototype")
public class Computer {
   @Resource
   private MainFrame mainFrame;
   @Resource(name="sanSungDisplay")
   private Display display;
   }

@PostConstruct 和@PreDestroy

 Spring容 器中的Bean是有生命周期的,Spring允 许在Bean在初始化完成后以及Bean销毁前执行特定的操作。JSR 250为初始化之后/销毁之前指定执行方法定义了两个注解类,分别是ePostConstruct和@PreDestroy,这两个注解只能应用于方法上。标注了PostConstruct注解的方法将在类实例化后调用,而标注了@PreDestroy的方法将在类销毁之前调用。如下:

@Component
@Scope("prototype")
public class Computer {
@PostConstruct
public void postConstruct1(){
  System.out.prinyln("执行postConstruct1");
}
@PreDestroy
public void PreDestroy1(){
  System.out.prinyln("执行postConstruct1");
}
}

 执行时,在bean被初始化时,会输出执行postConstruct1。在bean被销毁时,会输出执行postConstruct1。我们通常可以标注@PostConstruct的方法中完成一些资源初始化的工作,在标注了@PreDestroy的方法中完成一些释放资源的操作。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值