Spring-IoC中装配Bean

2019-03-16  本文已影响0人  czn5991

在Spring-IoC简介中简单介绍了什么是IoC以及一些相关的概念,这里将详细介绍如何通过IoC容器提供的方法进行注入和如何进行注入配置。

依赖注入

IoC提供的依赖注入方法主要有属性注入、构造函数注入和工厂方法注入,这里依次介绍如何通过各个方法注入Bean

属性注入

属性注入要求Bean提供一个默认的构造器,并为需要注入的属性提供对应的setter方法。Spring会检查Bean中是否有setter方法,但不会检查是否有对应的属性成员。
Bean的代码如下。

public class Car{
    private int maxSpeed;
    private String brand;
    //如果要通过属性注入则必须实现setter方法
    public void setXX(<T> XX){
        this.XX=XX;
    }
}

我们这里通过XML文件对Bean进行设置,后面会详细介绍所有的配置方式和配置内容。

<bean id="car" class="Car">
    <property name="maxSpeed"><value>200</value></property>
    <property name="brand"><value>红旗CA72</value></property>
</bean>

这样设置完成后,当Spring启动后,就会自动生成idcarclassCar,属性分别为200红旗CA72Bean
对于属性的命名,要求变量的前两个字母要么全部大写,要么全部小写iCCardiDCode是非法的。如果取非法的变量名,在试图启动Spring时,将会失败。因此命名的建议是像QQ、MSN、ID等正常以大写字母出现的专业术语,在Java中一律使用小写形式

构造函数注入

当想要通过构造函数注入时,需要在Bean中实现相应的构造函数,并以想要注入的属性为参数。
Bean的代码如下。

public class Car{
    private int maxSpeed;
    private String brand;
    public Car(int maxSpeed,String brand){...};
}

然后我们在XML文件中进行配置。

<bean id="car" class="Car">
  <constructor-arg type="java.lang.String">
        <value>红旗</value>
  </constructor-arg>
  <constructor-arg type="double">
        <value>200</value>
  </constructor-arg>
</bean>

在通过构造器注入时,配置文件中arg的顺序与构造器中的参数顺序无关,当只有一个构造器的情况下上述配置文件才会生效。因此建议使用索引匹配入参,即<constructor-arg index="0" value="红旗">
当两个构造器仅有intdouble的区别(如下),则此时还需要在配置文件中加上参数类型以作区分,即<constructor-arg index="0" type="int" value="200"/>

public class Car{
    private int maxSpeed;
    private double averageSpeed;
    private String brand;
    public Car(int maxSpeed,String brand){...};
    public Car(double averageSpeed,String brand){...};
}

如果构造函数的参数的类型是可以辨别的(非基础数据类型且入参类型各异),则可以不提供类型和索引的信息。
构造器注入可能会出现循环依赖的问题,即A类需要注入B类,B类需要注入A类,在这种情况下,使用属性注入就可以解决了。

工厂方法注入

在使用框架的过程中很少会使用到工厂方法注入,以下仅举2个例子。

  1. 非静态工厂类
public class CarFactory{
    public Car createHongQiCar(){}
}
<bean id="carFactory" class="CarFactory"/>

<bean id="car" factory-bean="carFactory" factory-method="createHongQiCar"/>

由于工厂类不是静态的,因此需要先定义工厂类的bean。

  1. 静态工厂类
public class CarFactory{
    public static Car createHongQiCar(){}
}
<bean id="car" class="CarFactory" factory-method="createCar"/>

Bean的配置方式

配置Bean可以通过XML、注解、Java类和Groovy DSL这四种方式,下面来详细介绍各个配置方法的细节。

基于XML的配置

对于基于XML的配置,Spring2.0以后采用Schema格式,使得配置文件更具扩展性,但文件头声明会复杂一些,下面是一个例子。

<?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:aop="http://www.springframework.org/schema/aop"

xsi:schemaLocation=
  "http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
   http://www.springframework.org/schema/aop
   http://www.springframework.org/schema/aop/spring-aop-4.0.xsd"
>
    <!-- 默认命名空间的配置 -->
    <bean id="foo" class="com.smart.Foo"/>

    <!-- aop命名空间的配置 -->
    <aop:config>
        <aop:advisor pointcut="execution(* *..PetStoreFacade.*(..))" advice-ref="txAdvice"/>
    </aop:config>
</beans>

在上面的代码中定义了3个命名空间:

  1. xmlns="http://www.springframework.org/schema/beans",默认命名空间:没有空间名,用于Spring Bean的定义。
  2. xsi标准命名空间:这个命名空间用于指定自定义命名空间的Schema样式文件,是W3C定义的标准命名空间。
  3. xmlns:aop="http://www.springframework.org/schema/aop",aop命名空间:这个命名空间是Spring配置aop的命名空间,即一种自定义的命名空间。

命名空间的定义分为两个步骤:

  1. 第一步指定命名空间的名称,如xmlns:aop="http://www.springframework.org/schema/aop"aop为命名空间的别名,而"http://www.springframework.org/schema/aop"是命名空间的全限定名,习惯上用文档发布机构的官方网站和相关网站目录作为全限定名。如果命名空间的别名为空,则表示该命名空间为文档默认的命名空间。
  2. 第二步指定命名空间的Schema文档格式文件的位置,用空格或回车换行进行分隔。定义的语法如下<命名空间1> <命名空间1Schema文件> <命名空间2> <命名空间2Schema文件>(注意之间的分隔符可以为空格或换行符)。Schema地址有2个用途:一是XML解析器可以获取Schema文件并对文档进行格式合法性验证;二是IDE可以引用Schema文件对文档编辑提供自动补全功能。

以上就是一个XML配置文件的结构介绍,接下来将介绍如何对Bean进行定制。

简化XML配置方式
  1. 字面值属性
类型 简化前 简化后
字面值属性 <property name="maxSpeed"><value>200</value></property> <property name="maxSpeed" value="200"/>
构造函数参数 <constructor-arg index="0"><value>200</value></constructor-arg> <constructor-arg index="0" value="200"/>
集合元素 <map>
<entry>
<key><value>AM</value></key>
<value>见客户</value>
</entry>
</map>
<map>
<entry key="AM" value="见客户"/>
</map>
  1. 引用对象属性
类型 简化前 简化后
字面属性值 <property name="car"> <ref-bean="car"/></property> <property name="car" ref="car">
构造函数 <constructor-arg> <ref-bean="car"></property> <constroctor-arg ref="car"/>
集合元素 <entry>
<key><ref bean="keyBean"/></key>
<ref bean="valueBean">
</entry>
<entry key-ref="keyBean" value-ref="valueBean"/>

<ref>的简化形式对应于<ref bean="xxx">,而<ref local>和<ref parent>没有对应的简化形式。

  1. 使用p命名空间
<beans xmlns:p="http://www.springframework.org/schema/p"><!--声明p命名空间-->
  <bean id="car" class="Car"
    p:brand="红旗"
    p:maxSpeed="200"/>
  <bean id="boss" class="Boss"
    p:car-ref="car"/>
</beans>

基于注解的配置

采用基于注解的配置文件,则Bean定义信息通过在Bean实现类上标注注解实现。

//这里定义了一个Dao的Bean
/*
  与@Component功能相似的还有:
    @Repository:用于对DAO实现类进行标注
    @Service:用于对Service实现类进行标注
    @Controller:用于对Controller实现类进行标注
*/
@Component("carDao")    
public class CarDao{
  //..
}

对于通过注解定义的bean需要在Spring配置文件中进行额外设置。

<beans
  xmlns:context="http://www.springframework.org/schema/context"
  xsi:"http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.0.xsd"
>
  <!--扫描类包以应用注解的bean,可以通过resource-pattern进行过滤 -->
  <!-- 其余过滤的方法还有include-filter和exclude-filter -->
  <context:component-scan base-package="package" resource-pattern="./*.class">
</beans>

Bean完成配置后,还需要通过注解进行自动注入

@Service
public class LoginService{
  //注入LogDao的bean
  //对required=false设置,当Spring启动时如果未找到对应的bean则不会报错
  //通过Qualifier可以指定对应bean的名称
  @Autowired(required=false)
  @Qualifier("logDao")
  private LogDao logDao;
  
  //对类方法进行标注
  @Autowired
  @Qualifier("logDao")
  public void setLogDao(LogDao logDao){}
  //或者通过这种形式
  public void setLogDao(@Qualifier("logDao")LogDao logDao){}

  //如果对类中集合类的变量或方法入参进行标注,那么Spring会将容器中类型匹配的所有Bean都注入
  @Autowired
  private List<Plugin> plugins;
  //Spring如果发现变量是一个list和一个map,会将容器中匹配集合元素类型的所有bean都注入
  //这里将会把plugins的bean注入map集合,key是bean的名字,value是所有实现了plugin的bean。
  @Autowired
  private Map<String,Plugin> pluginMaps;
  //如果Plugin有多个实现类,那么可以在不同的实现类前用@Order(value=1)对注入顺序进行设置,越小越先加载
}

基于Java类的配置、基于Groovy DSL的配置

一般来说,使用XML和标注的方式就能解决几乎所有的任务。建议使用XML配置DataSource、SessionFactory等资源bean,在XML中利用aop、context命名空间进行相关主题的配置,其余所有项目中开发的Bean都通过基于注解配置的方式进行配置。

Bean基本配置

Bean的命名

Bean的id属性命名与Java变量的命名要求相同,而name属性命名没有任何字符上的限制。可以通过不设置id属性命名来实例化匿名Bean

<bean class="Car"/>
<bean class="Car"/>
<bean class="Car"/>

这样就实例化了3个匿名Bean,第一个Bean通过getBean("Car")获得,第二个通过getBean("Car#1")获得。

依赖注入

Spring支持属性注入和构造函数注入,除此之外还支持工厂法注入方式。

上一篇 下一篇

猜你喜欢

热点阅读