Spring之bean标签属性详解

Posted 敲代码的小小酥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring之bean标签属性详解相关的知识,希望对你有一定的参考价值。

一、bean标签属性

id:
bean在spring容器的唯一标识,spring容器中不可能同时存在两个相同的id。

class:
类的全限定名(类名+包名),用“.”号连接

name:
设置别名,在BeanFactory的getBean(“name”)中可以获取相应的bean。

需要注意的是,bean属性的id和name,是bean的唯一标识,同一个spring的配置文件中,不同bean的id和name是不能相同的。否则会报错。不同的spring配置文件中,id和name可以重复。此时spring针对相同的id或name采取的策略是根据DefaultListableBeanFactory类中的allowBeanDefinitionOverriding属性值来判断的。默认为true,即相同的id或name会被覆盖。如果设置为false,则会抛出异常。
通过阅读spring初始化源码可以知道,spring是获取到spring的配置文件后,利用循环遍历读取配置信息的。所以不同的配置文件会循环多次,后面的覆盖前面的。
利用这个特性,我们可以通过spring配置文件的替换或覆盖,来做版本的更新。

abstract&&parent:
abstract:设置bean是否为抽象类,默认为false。如果为true,则该bean不会被实例化。那不被实例化,还定义它有啥用呢?这就要讲parent属性了。
parent: bean标签中的parent属性和java中的继承有些类似,但又不一样。parent属性可以指定一个类。那么bean和parent指定的类可以是继承关系,也可以不是继承关系。 只要指定了parent,那么parent类中的属性名,就可以自动继承到bean类中了。当然bean也可以对parent的属性进行覆盖。同时可以扩展其他的属性。
应用:
对于一些公共的东西,我们设置成abstract属性为true。然后具体应用这些公共属性的类,parent指定为这个abstract属性的bean,这样可以增加代码复用,减少重复代码。

autowire-candidate:
默认为true。如果设置为false,则该bean将不能通过依赖注入,传给需要这个对象类型的地方。也就是@Autowired等注解,无法依赖注入该对象。

应用:我们在开发中,更换service实现类时,又想保留原service的实现类,那就可以把该属性设置为false。那么依赖注入service时,spring就会把新的service实现类注入进去,旧的不会被注入。

autowire:
和@Autowired作用一样,只不过是在xml里的bean里配置的属性,都是用于依赖注入另一个bean作为属性。不推荐使用此属性,因为这么定义类的注入关系不能一目了然,不方便项目的维护。

depends-on:
它的作用是一个bean实例化的过程需要依赖于另一个bean的初始化,也就是说被依赖的bean将会在需要依赖的bean初始化之前加载。多个依赖bean之间用","号分割;

被依赖的类,不一定会被引用到bean的属性,只是先于这个bean初始化。当然销毁时,也是后于这个bean销毁。当遇到类必须有先后加载顺序场景时,可以应用此属性。

destroy-method:
它的作用是在销毁bean之前可以执行指定的方法。注意:必须满足scope=“singleton”,并且destroy方法参数个数不能超过1,并且参数类型只能为boolean。

init-method:
它的作用是在创建一个bean之后调用该方法,初始化方法必须是一个无参方法。

factory-bean&&factory-method:
如果一个bean,类似于工厂模式,生产不同的bean。那么,定义这个bean标签时,就要用factory-bean和factory-method属性了。
简单来说,就是一个工厂类,其内部有一个createInstance方法,来创建不同的对象。我们想定义这个工厂创建出来的不同对象,如何定义呢。这就用到factory-bean和factory-method方法了。factory-bean指定工厂类,factory-method指定工厂方法,无需再写class属性,就可以返回工厂方法返回的对象。
具体详细的用法,请查看属性详解

总之这两个属性是针对工厂类产生不同对象而使用的。

lazy-init:

lazy-init 设置只对scop属性为singleton的bean起作用,非单例不实例化(看源码,研究为啥非单例不实例化)

lazy-init=”false” 立即加载, 在spring启动时,立刻进行实例.

lazy-init=”true” 延迟加载 ,设置为true的bean将不会在ApplicationContext启动时提前被实例化,而是在第一次向容器通过getBean索取bean时实例化的。

如果一个设置了立即加载的bean1,引用了一个延迟加载的bean2,那么bean1在容器启动时被实例化,而bean2由于被bean1引用,所以也被实例化,这种情况也符合延迟加载的bean在第一次调用时才被实例化的规则。

primary:
autowire-candidate属性提到,当一个类型的对象有多个时,可以设置为true,不对这个bean进行依赖注入。
我们也可以不把这个bean屏蔽掉,而是设置primary,来定义首选依赖注入哪个类。当然primary熟悉只能设置相同类型的一个bean,否则会出问题。

scope:
默认为单例,即BeanFactory的getBean都返回同一个对象。可以设置为多例,每次getBean返回不同的对象。这也就是为何多例不实例化的原因了。

二、子元素

meta:
meta标签在bean的子标签定义。设置key值和value值。它是游离于对象外部的属性值,通过该bean的BeanDefinition对象的getAttribute(“key”)来获取value值。在一些特殊的场景下,可能会用到该需求。可以给一个bean做标签使用。带有某个标签的bean,要做何处理。

lookup-method:
该标签是bean定义的class属性为接口或者抽象类时,要对抽象方法进行动态实现,用到的标签。该标签的name属性写要实现的抽象方法,bean属性写抽象方法返回类型的实例,也就是动态定义抽象方法返回的实例。
例如:
步骤一:定义一个Car类

package org.hope.spring.bean.lookup;

public class Car {
    private String brand;
    private String corp;
    private double price;

    getter()&setter()....
}
 

步骤二:定义一个Boss接口

package org.hope.spring.bean.lookup;

public interface Boss {
    Car haveCar();
}
 

步骤三:在spring的配置文件bean.xml中定义三个bean

<bean id="honeqi" class="org.hope.spring.bean.lookup.Car"
          p:brand="红旗"
          p:price="400000"
          scope="prototype" />

<bean id="bmw" class="org.hope.spring.bean.lookup.Car"
          p:brand="奔驰GLC260"
          p:price="500000"
          scope="prototype" />

<bean id="boss" class="org.hope.spring.bean.lookup.Boss">
    <lookup-method name="haveCar" bean="bmw"/>
</bean>
 

步骤四:写单元测试测试

package org.hope.spring.bean.lookup;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:bean.xml"})
public class LookUpTest {
    @Autowired
    private Boss boss;

    @Test
    public void testBoss() {
        Car car = boss.haveCar();
        System.out.println(car.getBrand());
    }
}

奔驰GLC260

结论:

1、通过lookup-method元素标签可以为Boss的haveCar()提供动态实现,返回prototype类型的car Bean。

2、lookup方法注入是有一定使用范围的,一般在希望通过一个singleton Bean获取一个prototypeBean时使用

3、lookup方法注入需要用到CGLib类包

需要注意的就是指定的bean,必须是该抽象方法实现后的返回值,而不是一个空的bean对象。

replaced-method:
用于替换bean中的某个方法。也就是说,bean标签中定义的class中有一个方法,我们如果不想用这个方法,而想换一个方法的话,可以在bean下面定义replaced-method标签,该标签的name属性就是要被替换的方法,replacer属性就是替换这个方法的类。
需要注意的是,replacer里定义的类,必须实现MethodReplacer接口,然后在reimplement方法中定义替换方法。这样就可以替换原有类的方法了。

应用:如果我们想对框架或其他人的代码进行修改的话,可以使用此标签,做一些定制化修改,而无需修改其jar包中的代码,也就是说spring通过这个标签,为我们修改第三方jar包类提供了入口。(后续详细讲解如何修改jar包源码)

constructor-arg:
构造器参数(顺序注入),此种方式会按照顺序注入构造器的参数。

property:
自动注入jaabean的成员变量。

三、再看BeanDefinition

讲解完bean标签的属性和子标签,我们再看BeanDefinition中的方法:
在这里插入图片描述
可以看出,BeanDefinition就是把bean的属性和子标签,转换成了对象。

以上是关于Spring之bean标签属性详解的主要内容,如果未能解决你的问题,请参考以下文章

Java开发Spring之IOC详解第一篇(xml开发常用APIben标签DI依赖注入)

Spring从入门到精通—Bean标签详解

Spring之@Bean注解详解

[死磕 Spring 12/43] --- IOC 之解析 bean 标签:解析自定义标签

spring配置文件详解以及beans:beans标签

@Bean注解详解