SpringBean的配置详解

SpringBean

Spring开发中主要是对Bean的配置,Bean的常用配置一览如下:

Xml配置方式功能描述
<bean id=“” class=“”>Bean的id和全限定名配置
<bean name=“”>通过name设置Bean的别名,通过别名也能直接获取到Bean实例
<bean scope=“”>Bean的作用范围,BeanFactory作为容器时取值singleton和prototype
<bean lazy-init=“”>Bean的实例化时机,是否延迟加载。BeanFactory作为容器时无效
<bean init-method=“”>Bean实例化后自动执行的初始化方法,method指定方法名
<bean destroy-method=“”>Bean实例销毁前的方法,method指定方法名
<bean autowire=“byType”>设置自动注入模式,常用的有按照类型byType,按照名字byName
<bean factory-bean=“” factory-method=“”/>指定哪个工厂Bean的哪个方法完成Bean的创建

基础配置

配置UserDaoImpl由Spring容器负责管理

<bean id="userDao" class="com.rqz.dao.impl.UserDaoImpl"/>

此时存储到Spring容器(singleObjects单例池)中的Bean的beanName是userDao,值是UserDaoImpl对象,可以根据beanName获取Bean实例

applicationContext.getBean("userDao");

如果不配置id,则Spring会把当前Bean实例的全限定名作为beanName

applicationContext.getBean("com.rqz.dao.impl.UserDaoImpl");

范围配置

默认情况下,单纯的Spring环境Bean的作用范围有两个:Singleton和Prototype

  • singleton:单例,默认值,Spring容器创建的时候,就会进行Bean的实例化,并存储到容器内部的单例池中,每次getBean时都是从单例池中获取相同的Bean实例;
  • prototype:原型,Spring容器初始化时不会创建Bean实例,当调用getBean时才会实例化Bean,每次getBean都会创建一个新的Bean实例。

当scope设置为singleton时,获得两次对象打印结果是一样的

<bean id="userDao" class="com.rqz.dao.impl.UserDaoImpl" scope="singleton"/>
Object userDao = applicationContext.getBean("userDao");
Object userDao2 = applicationContext.getBean("userDao");
System.out.println(userDao); //com.rqz.dao.impl.UserDaoImpl@55040f2f
System.out.println(userDao2); //com.rqz.dao.impl.UserDaoImpl@55040f2f

通过断点调试,观察可以发现单例池中存在 userDao 实例
范围配置

当scope设置为prototype时,获得两次对象打印结果是不一样的

<bean id="userDao" class="com.rqz.dao.impl.UserDaoImpl" scope="prototype"/>
Object userDao = applicationContext.getBean("userDao");
Object userDao2 = applicationContext.getBean("userDao");
System.out.println(userDao); //com.rqz.dao.impl.UserDaoImpl@55040f2f
System.out.println(userDao2); //com.rqz.dao.impl.UserDaoImpl@64c87930

通过断点调试,观察可以发现单例池中不存在 userDao 实例,但是 userDao的信息已经被存储到beanDefinitionMap中了
范围配置

延迟加载

当lazy-init设置为true时为延迟加载,也就是当Spring容器创建的时候,不会立即创建Bean实例,等待用到时在创建Bean实例并存储到单例池中去,后续在使用该Bean直接从单例池获取即可,本质上该Bean还是单例的

<bean id="userDao" class="com.rqz.dao.impl.UserDaoImpl" lazy-init="true"/>

初始化和销毁方法配置

Bean在被实例化后,可以执行指定的初始化方法完成一些初始化的操作,Bean在销毁之前也可以执行指定的销毁方法完成一些操作,初始化方法名称和销毁方法名称通过

<bean id="userService" class="com.rqz.service.impl.UserServiceImpl" init-method="init" destroy-method="destroy">
    <property name="userDao" ref="userDao"/>
</bean>
public class UserServiceImpl implements UserService {
	public UserServiceImpl() { System.out.println("UserServiceImpl..."); }
	public void init(){ System.out.println("初始化方法..."); }
	public void destroy(){ System.out.println("销毁方法..."); }
}

除此之外,我们还可以通过实现 InitializingBean 接口,完成一些Bean的初始化操作,如下:

public class UserServiceImpl implements UserService, InitializingBean {
    private UserDao userDao;
    public void setUserDao(UserDao userDao) {
        System.out.println("userDao设置完毕...");
        this.userDao = userDao;
    }
    public UserServiceImpl() {
        System.out.println("UserServiceImpl创建了...");
    }
    public void init() {
        System.out.println("初始化方法...");
    }
    public void destroy() {
        System.out.println("销毁方法...");
    }
    //执行时机早于init-method配置的方法
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean...");
    }
}
//执行顺序,构造方法 -> 属性set方法 -> InitializingBean的实现方法 -> init-method -> destroy-method
UserServiceImpl创建了...
userDao设置完毕...
InitializingBean...
初始化方法...
销毁方法...

实例化配置

Spring的实例化方式主要如下两种:

  • 构造方式实例化:底层通过构造方法对Bean进行实例化

构造方式实例化Bean又分为无参构造方法实例化和有参构造方法实例化,Spring中配置的<bean>几乎都是无参构造该方式,此处不在赘述。下面讲解有参构造方法实例化Bean

//有参构造方法
public UserDaoImpl(String name){
}

有参构造在实例化Bean时,需要参数的注入,通过<constructor-arg>标签,嵌入在<bean>标签内部提供构造参数,如下:

<bean id="userDao" class="com.rqz.dao.impl.UserDaoImpl">
    <!-- 参数传递 -->
	<constructor-arg name="name" value="rqz"/>
</bean>
  • 工厂方式实例化:底层通过调用自定义的工厂方法对Bean进行实例化

静态工厂方法实例化Bean

静态工厂方法实例化Bean,其实就是定义一个工厂类,提供一个静态方法用于生产Bean实例,在将该工厂类及其静态方法配置给Spring即可

//工厂类
public class UserDaoFactoryBean {
	//静态工厂方法
	public static UserDao getUserDao(String name){
	//可以在此编写一些其他逻辑代码
		return new UserDaoImpl();
	}
}
<bean id="userDao" class="com.rqz.factory.UserDaoFactoryBean" factory-method="getUserDao">
    <!-- 参数传递 -->
	<constructor-arg name="name" value="rqz"/>
</bean>

<constructor-arg>标签不仅仅是为构造方法传递参数,只要是为了实例化对象而传递的参数都可以通过<constructor-arg>标签完成,例如上面通过静态工厂方法实例化Bean所传递的参数也是要通过<constructor-arg>进行传递的

实例工厂方法实例化Bean

实例工厂方法,也就是非静态工厂方法产生Bean实例,与静态工厂方式比较,该方式需要先有工厂对象,在用工厂对象去调用非静态方法,所以在进行配置时,要先配置工厂Bean,在配置目标Bean

//工厂类
public class UserDaoFactoryBean {
    //非静态工厂方法
    public UserDao getUserDao(String name){
        //可以在此编写一些其他逻辑代码
        return new UserDaoImpl();
    }
}
<!-- 配置实例工厂Bean -->
<bean id="userDaoFactoryBean" class="com.rqz.factory.UserDaoFactoryBean"/>
<!-- 配置实例工厂Bean的哪个方法作为工厂方法 -->
<bean id="userDao" factory-bean="userDaoFactoryBean" factory-method="getUserDao">
    <!-- 参数传递 -->
    <constructor-arg name="name" value="rqz"/>
</bean>

实现FactoryBean规范延迟实例化Bean

上面不管是静态工厂方式还是非静态工厂方式,都是自定义的工厂方法,Spring提供了FactoryBean的接口规范,FactoryBean接口定义如下:

public interface FactoryBean<T> {
    String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
    @Nullable
    T getObject() throws Exception;	//获得实例对象方法
    @Nullable
    Class<?> getObjectType();		//获得实例对象类型方法
    default boolean isSingleton() {
        return true;
    }
}

定义工厂实现FactoryBean

public class UserDaoFactoryBean implements FactoryBean<UserDao> {
    public UserDao getObject() throws Exception {
        return new UserDaoImpl();
    }
    public Class<?> getObjectType() {
        return UserDao.class;
    }
}

配置FactoryBean交由Spring管理即可

<bean id="userDao" class="com.rqz.factory.UserDaoFactoryBean"/>

通过断点观察发现Spring容器创建时,FactoryBean被实例化了,并存储到了单例池singletonObjects中,但是getObject() 方法尚未被执行,UserDaoImpl也没被实例化,当首次用到UserDaoImpl时,才调用getObject() ,此工厂方式产生的Bean实例不会存储到单例池singletonObjects中,会存储到 factoryBeanObjectCache 缓存池中,并且后期每次使用到userDao都从该缓存池中返回的是同一个userDao实例。
fatoryBeanObjectCache

依赖注入配置

Bean的依赖注入有两种方式:

注入方式配置方式
通过Bean的set方法注入<property name=“userDao” ref=“userDao”/>
<property name=“userDao” value=“rqz”/>
通过构造Bean的方法进行注入<constructor-arg name=“name” ref=“userDao”/>
<constructor-arg name=“name” value=“rqz”/>

其中,ref 是 reference 的缩写形式,翻译为:涉及,参考的意思,用于引用其他Bean的id。value 用于注入普通属性值。

依赖注入的数据类型有如下三种:

  • 普通数据类型,例如:String、int、boolean等,通过value属性指定。
  • 引用数据类型,例如:UserDaoImpl、DataSource等,通过ref属性指定。
  • 集合数据类型,例如:List、Map、Properties等。

List

注入 List<T> 集合 – 普通数据

<bean id="userService" class="com.rqz.service.impl.UserServiceImpl">
    <property name="strList">
        <list>
            <value>r</value>
            <value>q</value>
            <value>z</value>
        </list>
    </property>
</bean>

注入 List<T> 集合 – 引用数据

<bean id="userService" class="com.rqz.service.impl.UserServiceImpl">
    <property name="objList">
        <list>
            <bean class="com.rqz.dao.impl.UserDaoImpl"></bean>
            <bean class="com.rqz.dao.impl.UserDaoImpl"></bean>
            <bean class="com.rqz.dao.impl.UserDaoImpl"></bean>
        </list>
    </property>
</bean>
<!-- or -->
<!--配置UserDao-->
<bean id="userDao" class="com.rqz.dao.impl.UserDaoImpl"/>
<bean id="userDao2" class="com.rqz.dao.impl.UserDaoImpl"/>
<bean id="userDao3" class="com.rqz.dao.impl.UserDaoImpl"/>
<!--配置UserService-->
<bean id="userService" class="com.rqz.service.impl.UserServiceImpl">
    <property name="objList">
        <list>
            <ref bean="userDao"></ref>
            <ref bean="userDao2"></ref>
            <ref bean="userDao3"></ref>
        </list>
    </property>
</bean>

Set

注入 Set<T> 集合

<!-- 注入泛型为字符串的Set集合 -->
<property name="valueSet">
    <set>
        <value>r</value>
        <value>q</value>
        <value>z</value>
    </set>
</property>
<!-- 注入泛型为对象的Set集合 -->
<property name="objSet">
    <set>
        <ref bean="userDao"></ref>
        <ref bean="userDao2"></ref>
        <ref bean="userDao3"></ref>
    </set>
</property>

Map

注入 Map <K,V> 集合

<!--注入值为字符串的Map集合-->
<property name="valueMap">
    <map>
        <entry key="a" value="r" />
        <entry key="b" value="q" />
        <entry key="c" value="z" />
    </map>
</property>
<!--注入值为对象的Map集合-->
<property name="objMap">
    <map>
        <entry key="ud" value-ref="userDao"/>
        <entry key="ud2" value-ref="userDao2"/>
        <entry key="ud3" value-ref="userDao3"/>
    </map>
</property>

Properties

注入 Properties 键值对

<property name="properties">
    <props>
        <prop key="xxx">XXX</prop>
        <prop key="yyy">YYY</prop>
    </props>
</property>

自动装配方式

如果被注入的属性类型是Bean引用的话,那么可以在<bean> 标签中使用 autowire 属性去配置自动注入方式,属性值有两个:

byName:通过属性名自动装配,即去匹配 setXxx 与 id=“xxx”(name=“xxx”)是否一致;

byType:通过Bean的类型从容器中匹配,匹配出多个相同Bean类型时,报错。

<bean id="userService" class="com.rqz.service.impl.UserServiceImpl" autowire="byType">

其他配置标签

Spring 的 xml 标签大体上分为两类,一种是默认标签,一种是自定义标签

  • 默认标签:就是不用额外导入其他命名空间约束的标签,例如 <bean> 标签
  • 自定义标签:就是需要额外引入其他命名空间约束,并通过前缀引用的标签,例如 <context:property-placeholder/> 标签

Spring的默认标签用到的是Spring的默认命名空间

标签作用
<beans>一般作为 xml 配置根标签,其他标签都是该标签的子标签
<bean>Bean的配置标签,上面已经详解了,此处不再阐述
<import>外部资源导入标签
<alias>指定Bean的别名标签,使用较少

<beans>标签

除了经常用的做为根标签外,还可以嵌套在根标签内,使用profile属性切换开发环境

<!-- 配置测试环境下,需要加载的Bean实例 -->
<beans profile="test">
</beans>
<!-- 配置开发环境下,需要加载的Bean实例 -->
<beans profile="dev">
</beans>

可以使用以下两种方式指定被激活的环境:

  • 使用命令行动态参数,虚拟机参数位置加载 -Dspring.profiles.active=test
  • 使用代码的方式设置环境变量 System.setProperty(“spring.profiles.active”,“test”)

<import>标签

用于导入其他配置文件,项目变大后,就会导致一个配置文件内容过多,可以将一个配置文件根据业务某块进行拆分,拆分后,最终通过<import>标签导入到一个主配置文件中,项目加载主配置文件就连同<import> 导入的文件一并加载了

<!--导入用户模块配置文件-->
<import resource="classpath:UserModuleApplicationContext.xml"/>
<!--导入商品模块配置文件-->
<import resource="classpath:ProductModuleApplicationContext.xml"/>
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值