Spring 基于 xml 方式的 bean 的配置

240次阅读
没有评论

共计 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>

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

AD:【腾讯云服务器大降价】2核4G 222元/3年 1核2G 38元/年
正文完
 
阿蛮君
版权声明:本站原创文章,由 阿蛮君 2023-09-07发表,共计10577字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)
Copyright © 2022-2024 阿蛮君博客 湘ICP备2023001393号
本网站由 亿信互联 提供云计算服务 | 蓝易云CDN 提供安全防护和加速服务
Powered by Wordpress  Theme by Puock