Spring 基于 xml 方式的 bean 的配置


共计 10577 个字符,预计需要花费 27 分钟才能阅读完成。

一、简介

spring 可以通过读取 xml 配置文件的方式,生成 bean 实例对象。

现有如下 beans.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="userService" class="com.amjun.spring.service.impl.UserServiceImpl">
    </bean>
</beans>

UserService.java

public interface UserService {

    void save();
}

UserServiceImpl.java

package com.amjun.spring.service.impl;

import com.amjun.spring.service.UserService;

public class UserServiceImpl implements UserService {

     @Override
    public void save() {

    }
}

可以通过 BeanFactory 创建容器。

public class BeanFactoryTest {

    public static void main(String[] args) {
        // 创建工程对象
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        // 创建xml文件读取器
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
        // 读取配置文件给工厂
        reader.loadBeanDefinitions("beans.xml");
        // 去工厂获取实例
        UserService userService = (UserService)beanFactory.getBean("userService");
        System.out.println(userService);
    }
}

也可以通过 ApplicationContext 创建容器,但实际上 ApplicationContext 还是通过 BeanFactory 创建,并且他们创建实例的时机不通。

ApplicationContext 在加载配置文件时创建 bean 对象放入容器,BeanFactory 在获取 bean 对象时才创建,并放入容器。

public class BeanFactoryTest {

    public static void main(String[] args) {

        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        UserService userService = (UserService)applicationContext.getBean("userService");
        System.out.println(userService);
    }
}

二、xml配置文件详解

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

Spring 基于 xml 方式的 bean 的配置

/>

1. 基础配置

这里的基础配置比较简单,这里只给出最终的 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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 1. 可以配置 id 或者 别名,如果 id 和别名都不配置则可以通过全限定名进行获取对象
         2. 默认对象是单例模式 singleton,可设置为 prototype 多例模式(springmvc 情况下可以设置 request、session 域)
         3. lazy-init 配置懒加载,对于 beanfactory 无效,因为 beanfactory 是获取时才创建
         4. init-method 指定初始化方法,destroy-method 指定销毁方法 - 当容器显示关闭时执行
            除了指定 init-method,还可以通过实现 InitializingBean 接口的 afterPropertiesSet 方法实现初始化, 并在 init-method 之前执行
    -->
    <bean id="userService" name="alaisName,alaisName2" scope="singleton" lazy-init="false" init-method="init" destroy-method="destory"
          class="com.amjun.spring.service.impl.UserServiceImpl">
          <!--<constructor-arg name="name" value="abc"></constructor-arg>-->
        <property name="userMapper" ref="userMapper"></property>
    </bean>

    <bean id="userMapper" class="com.amjun.spring.mapper.impl.UserMapperImpl"></bean>
</beans>

UserService.java

public interface UserService {

    void save();
}

UserServiceImpl.java

public class UserServiceImpl implements UserService, InitializingBean {

    private String name;

    private UserMapper userMapper;

    public UserServiceImpl() {
        System.out.println("UserService实例化-无参构造");
    }

    public UserServiceImpl(String name) {
        System.out.println("UserService实例化-有参构造");
    }

    public void setUserMapper(UserMapper userMapper) {
        System.out.println("依赖注入userMapper");
        this.userMapper = userMapper;
    }

    public void init(){
        System.out.println("UserService初始化方法");
    }

    public void destory(){
        System.out.println("UserService销毁方法");
    }

    @Override
    public void save() {
        System.out.println("UserService 调用 userMapper 的 insert 方法");
        userMapper.insert();
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("执行afterPropertiesSet方法....");
    }
}

UserMapper.java

public interface UserMapper {

    void insert();
}

UserMapperImpl.java

public class UserMapperImpl implements UserMapper {

    public UserMapperImpl() {
        System.out.println("UserMapper实例化");
    }

    @Override
    public void insert() {
        System.out.println("用户信息入库");
    }
}

测试方法:

public class BeanFactoryTest {

    public static void main(String[] args) {

        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        UserService userService = (UserService)applicationContext.getBean("userService");
        System.out.println(userService);
        userService.save();
        // 设置为多例模式每个对象都是新创建的
        UserService userService2 = (UserService)applicationContext.getBean("userService");
        System.out.println(userService2);
        applicationContext.close();
    }
}

2. 实例化bean的方式

2.1 构造方法实例化

默认就是使用无参构造方法进行实例化,如果需要有参构造方法实例化需要配置 constructor-arg 标签,且可以配置多个标签。

<bean id="userService" class="com.amjun.spring.service.impl.UserServiceImpl">
    <constructor-arg name="name" value="abc"></constructor-arg>
</bean>

2.2 工厂方式实例化

底层通过调用自定义的工厂方法对Bean进行实例化。

  • 静态工厂实例化
public class MyBeanFactory1 {

    // 如果 userMapper 方法需要参数,同时配置 constructor-arg 即可
    public static UserMapper userMapper(){
        return new UserMapperImpl();
    }
}

xml 文件。

<bean id="userMapper1" class="com.amjun.spring.factory.MyBeanFactory1" factory-method="userMapper"></bean>

测试方法:

public class BeanFactoryTest {

    public static void main(String[] args) {

        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        UserMapper userMapper1 = (UserMapper)applicationContext.getBean("userMapper1");
        System.out.println(userMapper1);
    }
}

静态工厂可以不创建工厂实例,通过静态方法创建对象。

Spring 基于 xml 方式的 bean 的配置

/>

原理是 spring 解析配置文件时发现,需要生成的不是 MyBeanFactory1 对象,而是 userMapper 方法返回的对象。

好处:

  1. bean 创建前后可以进行一些其他操作
  2. 可以通过这种方式创建非自定义的 bean 交给 spring 进行管理(通过静态方法创建的bean)
  • 实例工厂实例化
public class MyBeanFactory2 {

    // 如果 userMapper 方法需要参数,同时配置 constructor-arg 即可
    public UserMapper userMapper(){
        return new UserMapperImpl();
    }
}

xml 文件。

<bean id="myBeanFactory2" class="com.amjun.spring.factory.MyBeanFactory2"></bean>

<bean id="userMapper2" factory-bean="myBeanFactory2" factory-method="userMapper"></bean>

测试方法:

public class BeanFactoryTest {

    public static void main(String[] args) {

        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        UserMapper userMapper2 = (UserMapper)applicationContext.getBean("userMapper2");
        System.out.println(userMapper2);
    }
}

可以看见先创建了工厂实例,再通过工厂方法创建实例。

Spring 基于 xml 方式的 bean 的配置

/>

好处:

  1. bean 创建前后可以进行一些其他操作
  2. 可以通过这种方式创建非自定义的 bean 交给 spring 进行管理(通过实例对象创建的bean)
  • 实现FactoryBean规范延迟实例化Bean

FactoryBean 是工厂 Bean, 注意和 BeanFactory 区分开。

FactoryBean 是一个接口。

public interface FactoryBean<T> {
    String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";

    @Nullable
    T getObject() throws Exception;

    @Nullable
    Class<?> getObjectType();

    default boolean isSingleton() {
        return true;
    }
}

创建一个 MyBeanFactory3 实现 FactoryBean。

public class MyBeanFactory3 implements FactoryBean<UserMapper> {

    @Override
    public UserMapper getObject() throws Exception {
        return new UserMapperImpl();
    }

    @Override
    public Class<?> getObjectType() {
        return UserMapper.class;
    }
}

xml 文件。

<bean id="userMapper3" class="com.amjun.spring.factory.MyBeanFactory3"></bean>

测试方法:

public class BeanFactoryTest {

    public static void main(String[] args) {

        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        UserMapper userMapper3 = (UserMapper)applicationContext.getBean("userMapper3");
        System.out.println(userMapper3);
    }
}

为什么叫延迟实例化bean?

当加载配置文件时,可以看见并没有创建 UserMapper 实例,而是创建了工厂 Bean,并且此时 factoryBeanObjectCache 里面没有任何东西。

Spring 基于 xml 方式的 bean 的配置

/>

当去容器里面获取实例时,FactoryBean 才调用 getObject 方法进行实例化 bean,并将实例放入 factoryBeanObjectCache 中。

Spring 基于 xml 方式的 bean 的配置

/>

3. bean的依赖注入

3.1 手动装配

bean 的依赖注入有两种方式。

Spring 基于 xml 方式的 bean 的配置

/>

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

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

前面两种数据类型比较常见,这里说下 list 数据类型的注入,配置 set 将 list 标签替换为 set 即可。

现 UserServiceImpl.java 如下:

public class UserServiceImpl implements UserService {

    private List<String> stringList;

    private List<UserMapper> userMapperList;

    private Map<String, UserMapper> map;

    private Properties properties;

    public void setStringList(List<String> stringList) {
        this.stringList = stringList;
    }

    public void setUserMapperList(List<UserMapper> userMapperList) {
        this.userMapperList = userMapperList;
    }

    public void setMap(Map<String, UserMapper> map) {
        this.map = map;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }
}

则 xml 配置如下:

<bean id="userService" class="com.amjun.spring.service.impl.UserServiceImpl">
    <property name="stringList">
        <list>
            <value>aaa</value>
            <value>bbb</value>
        </list>
    </property>
     <property name="userMapperList">
        <list>
            <!--  方式一 -->
            <!-- <bean class="com.amjun.spring.mapper.impl.UserMapperImpl"></bean>
            <bean class="com.amjun.spring.mapper.impl.UserMapperImpl"></bean>
            <bean class="com.amjun.spring.mapper.impl.UserMapperImpl"></bean>-->
            <!-- 方式二 -->
            <ref bean="userMapper1"></ref>
            <ref bean="userMapper2"></ref>
            <ref bean="userMapper3"></ref>
        </list>
    </property>
    <property name="map">
        <map>
            <entry key="d1" value-ref="userMapper1"></entry>
            <entry key="d2" value-ref="userMapper2"></entry>
        </map>
    </property>
    <property name="properties">
        <props>
            <prop key="p1">ppp1</prop>
            <prop key="p2">ppp2</prop>
        </props>
    </property>
</bean>

<bean id="userMapper1" class="com.amjun.spring.mapper.impl.UserMapperImpl"></bean>
<bean id="userMapper2" class="com.amjun.spring.mapper.impl.UserMapperImpl"></bean>
<bean id="userMapper3" class="com.amjun.spring.mapper.impl.UserMapperImpl"></bean>

3.2 自动装配

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

  • byName:通过属性名自动装配,即去匹配 setXxx 与 id=“xxx”(name=“xxx")是否一致
  • byType:通过 Bean 的类型从容器中匹配,匹配出多个相同 Bean 类型时,报错
<!-- 需要 UserServiceImpl 有 setUserMapper 方法, 有此方法时,自动去容器里面寻找 id 为 userMapper 的对象进行自动装配-->
<bean id="userService" class="com.amjun.spring.service.impl.UserServiceImpl" autowire="byName">
</bean>

<!-- 不管 UserMapperImpl 的 id 为任何值都可以自动装配,但是存在多个时报错-->
<bean id="userService2" class="com.amjun.spring.service.impl.UserServiceImpl" autowire="byType">
</bean>

<bean id="userMapper" class="com.amjun.spring.mapper.impl.UserMapperImpl"></bean>

4. spring的其他配置标签

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

  • 默认标签:就是不用额外导入其他命名空间约束的标签,例如 <bean>标签

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

例如引入 context 命名空间,使用它里面的标签需要添加前缀。

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

    <context:property-placeholder></context:property-placeholder>
</beans>

默认标签如下:

Spring 基于 xml 方式的 bean 的配置

/>

需要注意的是,<beans>标签可以嵌套。

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

    <!-- 默认环境 -->
    <bean id="userService" class="com.amjun.spring.service.impl.UserServiceImpl"></bean>

    <!-- 开发环境 -->
    <beans profile="dev">
        <bean id="userService1" class="com.amjun.spring.service.impl.UserServiceImpl"></bean>
    </beans>

    <!-- 测试环境 -->
    <beans profile="test">
        <bean id="userService2" class="com.amjun.spring.service.impl.UserServiceImpl"></bean>
    </beans>
</beans>

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

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

当激活 test 环境时,可以在 environment 对象中看见。

Spring 基于 xml 方式的 bean 的配置

/>

即使指定激活了 test 环境,还是可以获取到 id 为 userService 的实例,因为它是公共的。

当配置文件很多时,可以通过主配置文件引入其他配置文件。

<!-- 引入数据库配置文件-->
<importresource="classpath:dataSource.xml"></import>
<!-- 引入springmvc配置文件-->
<importresource="classpath:springMvc.xml"></import>

提醒:本文发布于424天前,文中所关联的信息可能已发生改变,请知悉!

Tips:清朝云网络工作室

阅读剩余
THE END