Spring bean配置的六种方式

本文将详细介绍Spring Bean配置的六种不同方式的特点与使用条件。

一,Spring 的配置文件概述

       其实,Spring的配置文件是Spring容器对Bean进行生产以及关系注入的图纸,他是Spring的基础。如果我们没有配置文件的话,则Spring的容器将无从谈起。
        Spring 的配置文件是用于指导 Spring 工厂进行 Bean 的生产、依赖关系注入及 Bean 实例分发的“图纸”, J2EE 程序员必须学会并灵活应用这份“图纸”,准确地表达自己的“生产意图”。它是一个或多个标准的XML文档,其ApplicationContext.xml是Spring的默认配置文件,当容器启动时找不到其他的配置文件时,则会尝试加载这个默认的配置文件。

Spring容器成功启动需要以下三方面的条件同时具备:

  1. Spring的类包必须已经放在Spring的类容器下面
  2. 应用程序应当为Spring提供完备的Bean的配置信息
  3. Bean的类都已经放在Spring的类容器下面    

Spring启动时读取应用程序提供的Bean的配置信息,并在Spring容器中生成一份相应的Bean的配置注册表,然后根据这张注册表来实例化Bean,装配好Bean之间的依赖关系,为上层应用提供准备就绪的运行环境。
而bean的配置信息就是Bean的元数据信息,他由以下五个方面来组成:spring

  1. Bean的实现类
  2. Bean的属性信息 比如:数据源的连接数,用户名和密码等等。
  3. Bean的依赖关系 Spring根据依赖关系配置完成Bean之间的装配
  4. Bean的行为配置 比如:生命周期范围以及生命周期各个过程的回调函数等
  5. Bean的创建方式定义 主要说明是通过构造器还是工厂方法来构造Bean

接下来是他们之间的相互关系:


有时,一个项目中可能存在多个配置文件,那么Spring项目加载多个配置文件的方法:

  1. 在配置文件中使用import来导入所需的配置文件。
  2. 将多个配置文件构造为一个数组,然后传递给ApplicationContext实现加载多个配置文件。

这两种方式都是通过调用BeanDefinitionReader来读取定义文件的,在内部实现上没有任何的区别。
      在大型的Spring项目当中,所有的bean配置在一个配置文件当中很不容易管理且也不利于团队的开发。通常在开发过程当中,我们会按照功能模块和开发人员来将配置文件分成多个。这样会有利与模块的划分。接下来我们需要使用import属性来引入多个配置文件到项目当中。
假如我们的项目需要用到多个配置文件,且配置文件位于不同的文件夹下,比如:
Spring-Common.xml位于common文件夹下
Spring-Connection.xml位于connection文件夹下
Spring-Module.xml位于module文件夹下


传统加载方式:

ApplicationContext context = new ClassPathXmlApplicationContext(new String[]
    {"Spring-Common.xml","Spring-Connection.xml","Spring-ModuleA.xml"});

但是这种方法不宜组织,且不宜维护。
则我们使用整合配置文件:Spring-All-Module.xml

<beans .....>
    <import resource="common/Spring-Common.xml"/>
    <import resource="connection/Spring-Connection.xml"/>
    <import resource="module/Spring-Module.xml"/>
</beans>

在文件当中使用import直接将其他的配置文件导入到这个文件当中就好了。
整合后加载方式:

ApplicationContext context = new ClassPathXmlApplicationContext(“Spring-All-Module.xml”);

可以看到配置文件是整个Spring项目的灵魂,我们先来看一下Spring配置文件的一般结构:

<beans>//Bean定义的开始和结束
    <import  resource=“resource1.xml” />//导入其他配置文件Bean的定义
    <import  resource=“resource2.xml” />
    <bean id=“bean1” class=“***”></bean>
    <bean name=“bean2” class=“***”></bean>
    <alias alias=“bean3” name=“bean2” />//alias用于定义Bean的别名
</beans>

可以看到一个简单的Spring配置文件就是这样。
其中:
Import标签可以放在Beans标签下的任何位置,没有顺序关系。
bean3和bean2是同一个Bean,bean3是bean2的别名。

        Spring 的配置文件是基于XML格式的,Spring1.0的配置文件采用DTD格式,Spring2.0以后使用Schema的格式,后者让不同类型的配置拥有了自己的命名空间,使配置文件更具有扩展性。
采取基于Schema的配置格式,文件头的声明会复杂一些,请看一个简单示例:

<?xml version="1.0" encoding="UTF-8" ?>
<beans
<!--标准命名空间-->
xmlns="http://www.springframework.org/schema/beans"
<!--xsi标准命名空间,用于指定自定义命名空间的Schema文件-->
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<!—aop表示自定义命名空间,aop是该命名空间的简称,而后面是命名空间的全称。必须在xsi命名空间为其指定的命名空间对应的Schema文件-->
    xmlns:aop="http://www.springframework.org/schema/aop"
 
<!—下面这四行代码,是为每个命名空间指定具体的schema文件-->
    xsi:schemaLocation="
           http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/context/spring-aop-3.0.xsd">
<!—默认命名空间的配置 -->
    <bean id = "app" class="cn.lovepi.App" />
<!—aop命名空间的配置 -->
    <aop:config>
        <aop:pointcut id="mycut" expression="execution(* cn.love*(..))"/>
    </aop:config>
</beans>

注:
Xml Schema:Schema在文档根节点中通过xmlns对文档当中的命名空间进行命名。

我们在上面的代码中定义了三个命名空间,

  1. 首先我们定义了一个默认命名空间,他没有空间名,用于Spring Bean的定义。
  2. 接下来我们命名了一个xsi命名空间,这个命名空间用于为每个文档中命名空间指定相对应的schema的样式文件。是标准组织定义的标准命名空间。
  3. 我们还命名了一个aop的命名空间,这个命名空间是Spring配置aop的命名空间,是用户自定义的命名空间。

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

  1. 指定命名空间的名称,需要指定命名空间的缩类名和全名
  2. 指定命名空间的schema文档样式文件的位置,用空格或回车行来进行分割。

指定命名空间schema地址有两个用途:

  1. xml解析器可以获取schema文件,并对文档进行格式合法性验证
  2. 在开发环境下,IDE可以用schema文件来对文档编辑器进行诱导功能。

Spring3.0 的配置Schema文件分布在各模块类包中,如果模块拥有对应的Schema文件,则可以在模块类包中找到一个config目录,Schema文件就位于该目录中,如下是对这些Schema文件的用途进行了简单说明:
示例说明:Spring-beans-3.0.xsd
命名空间:http://www.springframework.org/schema/beans
Schema 文件:http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
可以看出在Spring3.0当中,所有的Schema文件的命名空间以及对应的位置都和Beans这个Schema文件是类似的。
那么接下来来了解以下Spring当中其他Schema文件的用途:

spring-beans-3.0.xsd:Spring3.0最主要的配置文件,主要是用于配置Bean
spring-aop-3.0.xsd:aop配置定义的schema
spring-tx-3.0.xsd:声明式事物配置定义的Schema
spring-mvc-3.0.xsd:Spring3.0当中新增的
spring-util-3.0.xsd:是为简化某些复杂的标准配置而提供的Schema
spring-jee-3.0.xsd:是为简化J2EE中EJB等功能的配置而提供的Schema
spring-jdbc-3.0.xsd:为Spring内接数据库而提供的Schema,3.0新增
spring-jms-3.0.xsd:jms配置的Schema
spring-lang-3.0.xsd:增加了对动态语言的支持,为集成动态语言而定义
spring-oxm-3.0.xsd:配置对象xml映射到schema,3.0新增
spring-task-3.0.xsd:任务调度的Schema
spring-tool-3.0.xsd:为集成Schema一些有用工具而提供的Schema

二,spring配置bean的集中方式

  • 基于XML的配置方式
  • 基于注解的配置方式
  • 基于Java类的配置方式

1,基于XML的配置方式,以及各参数的含义

<?xml version="1.0" encoding="UTF-8"?>
<!--suppress ALL -->
<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-3.2.xsd
	">
    <!--
        使用无参构造器来创建对象。
        id属性:要求唯一 。
        class属性:要写类的完整的名称。
     -->
    <bean id="a1" class="first.Apple"/>

    <bean id="date1" class="java.util.Date"/>

    <!--
        使用静态工厂方法来创建对象。
        factory-method属性:用来指定静态方法名。
        注:
            Spring容器会调用该类的静态方法来创建
            一个对象。
     -->
    <bean id="cal1" class="java.util.Calendar" factory-method="getInstance"/>

    <!--
        使用实例工厂方法来创建对象:
        factory-bean属性:指定要调用的bean的id,
        factory-method属性:指定要调用的实例方法。
        注:
            Spring容器会调用该bean的实例方法来
            创建对象。
            在Spring框架里面,所谓的bean指的是由
            Spring容器管理的对象。
     -->
    <bean id="date2" factory-bean="cal1" factory-method="getTime"/>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<!--suppress ALL -->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:jee="http://www.springframework.org/schema/jee"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
		http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
		http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd">
    <!--
        scope属性:用来指定bean的作用域。
        缺省值是"singleton"(单例),如果值为
        "prototype"(原型),则创建多个实例。
     -->
    <bean id="sb1" class="basic.ScopeBean" scope="prototype"/>

    <!--
        init-method属性:用来指定初始化方法。
        destroy-method属性:用来指定销毁方法。
        注:
            Spring容器关闭之前,会删除它所管理的
            bean,在删除bean之前,会调用destroy
            方法。
            销毁方法只针对作用域为singleton的bean。
     -->
    <bean id="mb1" class="basic.MessageBean"
          init-method="init"
          destroy-method="destroy"
          scope="singleton"/>

    <!--
        lazy-init属性:如果值为true,表示延迟加载。
        即容器启动之后,不会立即创建该实例,只有等
        到调用时(getBean)才创建。
     -->
    <bean id="lb1" class="basic.LazyBean"
          lazy-init="true"/>


</beans>

2,基于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"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd">

    <bean id="now" class="java.util.Date"/>

    <!-- 通过SET方式注入属性的值 -->
    <!-- 通过SET方式注入属性的值 -->
    <!-- property节点用于配置属性的值 -->
    <bean id="user" class="cn.tedu.spring.User">
        <property name="name" value="Mike"/>
        <property name="from" value="Beijing"/>
        <property name="age" value="26"/>
        <property name="regTime" ref="now"/>
    </bean>

    <!-- 通过构造方法注入属性的值 -->
    <!-- constructor-arg节点用于配置构造方法的参数 -->
    <bean id="person" class="cn.tedu.spring.Person">
        <constructor-arg index="0" value="Shenzhen"/>
    </bean>

    <!-- 注入集合类型的值 -->
    <bean id="sampleBean" class="cn.tedu.spring.SampleBean">
        <!-- 注入List类型的值 -->
        <property name="names">
            <list>
                <value>Tom</value>
                <value>Kate</value>
                <value>Mary</value>
                <value>David</value>
            </list>
        </property>
        <!-- 注入Set类型的值 -->
        <property name="cities">
            <set>
                <value>Hangzhou</value>
                <value>Beijing</value>
                <value>Shanghai</value>
                <value>Guangzhou</value>
                <value>Shenzhen</value>
            </set>
        </property>
        <!-- 注入Map类型的值 -->
        <property name="session">
            <map>
                <entry key="uid" value="9527"/>
                <entry key="username" value="Jack"/>
                <entry key="password" value="1234"/>
            </map>
        </property>
        <!-- 注入数组类型的值 -->
        <property name="numbers">
            <array>
                <value>7</value>
                <value>3</value>
                <value>9</value>
            </array>
        </property>
        <!-- 注入来自.properties中的配置 -->
        <property name="properties" ref="dbConfig"/>
    </bean>

    <!-- 读取.properties文件 -->
    <!-- classpath表示src/main/resources文件夹 -->
    <util:properties id="dbConfig" location="classpath:db.properties"/>

    <!-- 使用Spring表达式 -->
    <bean id="valueBean" class="cn.tedu.spring.ValueBean">
        <property name="username" value="#{user.name}"/>
        <property name="realname" value="#{sampleBean.names[1]}"/>
        <property name="password" value="#{sampleBean.session['password']}"/>
    </bean>

</beans>

2,基于注解的配置方式,以及各参数的含义

1)首先在spring配置文件中开启注解扫描

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

    <!-- 组件扫描 -->
    <!-- base-package:根包 -->
    <!-- resource-pattern:正则匹配 -->
    <context:component-scan base-package="cn.tedu.spring" resource-pattern="anno/*.class"/>

</beans>

Spring2.0开始引入基于注解的配置方式,即Bean的定义信息可以通过在Bean的实现类上标注注解实现。

@Component是Spring容器中的基本注解,表示容器中的一个组件(bean),可以作用在任何层次,下面的示例介绍该注解的使用方法。

注解配置示例

@Component("userDao")
public class userDao{......}

他等效于XML配置

<bean id="userDao" class="cn.lovepi.***.userDao"/>

此外,还有一些其他的可以被用来注解bean的注解,这些可以让注解类本身的用途更加清晰,此外,特定的注解也具备特定的功能。

Spring在2.5后提供了一个context的命名空间,它提供了通过扫描类包来加载利用注解定义的Bean的方式。

在context中可以使用resource-pattern来过滤出特定的类。

<context:component-scan base-package="cn.lovepi.spring" resource-pattern="anno/*.class"/>  

默认情况下加载的是package下的*.class即扫描全部类,在使用了resource-pattern之后,则只扫描package下的anno子包下的所有类。

不过使用resource-pattern并不能提供给我们完善的功能,所有我们得使用过滤子元素的方法。

<context:component-scan base-package="cn.lovepi.spring">
   <context:include-filter type="regex" expression="cn.lovepi.spring.*"/>
   <context:exclude-filter type="aspectj" expression="cn.lovepi..*Controller+"/>
</context:component-scan>

其中:

include-filter表示要包含的目标类,

exclude-filter表示要排除在外的目标类

一个component-scan标签下可以有多个include-filter和exclude-filter,

过滤表达式所支持的类型如下表所示:

在这些类型当中,除了Custom外,aspectj的过滤功能最强大,他能轻易的实现其他类别的过滤规则。

Spring3.0提供了一系列的针对依赖注入的注解,这使得Spring IoC在XML文件之外多了一种可行的选择,主要包含如下注解类型:

  • Bean的定义注解
  • Bean的生命周期注解
  • Bean的依赖检查注解
  • Bean的自动装配注解

1.Bean的定义注解

Spring自2.0开始,陆续引入了一些注解用于简化Spring的开发。

@Repository注解便属于最先引入的一批,用于将数据访问层(DAO层)的类标识为Spring Bean。具体使用如下:

①首先使用@Repository将DAO类声明为Bean

@Repository
public class UserDaoImpl implements UserDao{......}

②在XML配置文件中启动Spring的自动扫描功能

<beans ...>
    <context:component-scan base-package="cn.lovepi.dao"/>
    ......
<beans/>

如此的话,我们便不在需要在XML当中显式使用bean来进行bean的配置。Spring容器在初始化的时候便会自动扫描base-package所指定的包以及子包下面的所有class文件。所有标注为Repository的类将被自动注册为bean。

为什么Repository只能标注在DAO类上面呢?

       因为该注解的作用不只是将类识别为bean,同时他还能将所标注的类中所抛出的数据访问异常封装为Spring的数据访问异常类型。Spring本身提供了一个丰富的,并且是与具体的访问技术无关的数据访问异常结构,用于封装不同的持久层框架所抛出的异常,使得异常独立与底层的框架。

Spring2.5在@Repository的基础上增加了功能类似的额外三个注解,总共有如下四种注解:

  • @Component:一个泛化的概念,表示一个组件(Bean),可作用在任何层次
  • @Controller:用于对Controller实现类进行标注,目前该功能与Component相同
  • @Repository:用于对DAO实现类进行标注
  • @Service:用于对Service实现类进行标注,目前该功能与Component相同

这三个注解除了作用于不同软件层次的类,其使用方式与Repository是完全相同的。

2.Bean的生命周期注解

在某些情况下,可能需要我们手工做一些额外的初始化或者销毁操作,例如资源的获取和是否操作,Spring1.x为此提供了两种方式供用户指定执行生命周期回调的方法:

  1. 实现Spring提供的两个接口:initializingBean 和 DisposableBean,这种方法是要求bean类实现Spring的接口,但增加了bean和Spring容器的耦合度,因此不推荐使用。
  2. 在XML文件中使用<bean>的init-method 和 destory-method 属性,指定初始化之后和回调之前的回调方法。这两个属性的取值是bean中相应的初始化和销毁方法的名称。方法名称任意,但是方法不能有参数。

示例如下:

<bean id="userService" class="cn.lovepi.***.UserService"
   init-method="init" destory-method="destory">
</bean>

在这里,我们指定了userService 这个bean的初始化方法为:init     销毁方法为:destory

Spring2.5在保留以上两种方式的基础上,提供了对JSR-250的支持。

JSR-250规范定义了两个用于指定声明周期方法的注解:

  • @PostConstruct:初始化之后的执行的回调方法
  • @PreDestroy:销毁之前的回调方法

注解示例说明:

public class PersonService{
   @PostConstruct
   public void init(){......}
   @PreDestory
   public void destory(){......}
}

在这里init方法是初始化之后执行的方法,而destory方法为销毁之前执行的方法

由于使用了注解,所以得激活Bean的后处理器,所以得在XML配置文件当中增加

<context:annotation-config/>

3.Bean的依赖检查注解

Spring2.0之前使用dependency-check在配置文件中设置属性用于依赖检查(只会检查Setter方法是否被调用),缺点是粒度较粗,该属性的取值包括以下几种:

  • none: 默认不执行依赖检查
  • simple :对原始基本类型和集合类型进行检查
  • objects :对复杂类型进行检查
  • all :对所有类型进行检查

使用Spring2.0提供的@Required注解,提供了更细粒度的控制,@Required注解只能标注在Setter方法之上,(标注在其他方法之上会被忽略 )用于检查其是否被调用,当Setter方法未被调用的话会抛出异常。

由于使用了注解,所以得激活Bean的后处理器,所以得在XML配置文件当中增加

<context:annotation-config/>

4.Bean的自动装配注解

@Autowired可以对成员变量、方法和构造函数进行标注,来完成自动装配的工作,他根据类型进行自动装配,如果需要按名称进行装配,则需要配合@Qualifier使用。(比如接口多实现的时候)

当标注了@Autowired的方法所需的类型在Spring容器中不存在的话会抛出异常

@Service
public class LoginService{
   @Autowired
   private LogDao logDao;
}

如上面的例子所示,假如Spring容器中没有LogDao这个bean的话便会抛出异常。

解决的办法便是使用required=false属性来标注

public class LoginService{
   @Autowired(required=false)
   private LogDao LogDao;
}

但是假如Spring当中存在多个所需类型的bean,那么便要使用@Qualifier注解来指定名称。

public class LoginService{
   @Autowired
   @Qualifier("userDao")
   private UserDao userDao;
}

@Autowired 可以对类中集合类的变量或方法入参进行标注,此时会将容器中类型匹配的所有Bean都注入进来,如下所示:

public class loginService{
   @Autowired(required=false)
   public List<Plugin> pligins;
   public List<Plugin> getPlugins(){
      return plugins;
   }
}

Spring会将容器中所有类型为Plugin的bean都注入到集合中去。

三,基于java类的配置

基于Java类定义Bean配置元数据,其实就是通过Java类定义Spring配置元数据,且直接消除XML配置文件。
首先让我们看一下基于Java类如何定义Bean配置元数据,具体步骤如下:

  1. 使用@Configuration注解需要作为配置的类,表示该类将定义Bean的元数据
  2. 使用@Bean注解相应的方法,该方法名默认就是Bean的名称,该方法返回值就是Bean的对象。
  3. AnnotationConfigApplicationContext或子类进行加载基于java类的配置

接下来通过示例来演示下如何基于Java类来配置Spring
首先创建一个配置类

@Configuration
public class ApplicationContextConfig {
    @Bean
    public String message() {
        return "hello";
    }
}

然后还需要一个测试类,来查看配置是否成功

public class ConfigurationTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx =
        new AnnotationConfigApplicationContext(ApplicationContextConfig.class);
        System.out.println(ctx.getBean("message"));
    }
}

通过@Configuration注解的类将被作为配置类使用,表示在该类中将定义Bean配置元数据,且使用@Configuration注解的类本身也是一个Bean,使用方式如下所示:

@Configuration("ctxConfig")
public class ApplicationContextConfig {
    ……
}

其中Configuration中的参数值即为该bean的名称。
通过@Bean注解配置类中的相应方法,则该方法名默认就是Bean名,该方法返回值就是Bean对象,并定义了Spring IoC容器如何实例化、自动装配、初始化Bean逻辑,具体使用方法如下:

@Bean(name={},
      autowire=Autowire.NO,
      initMethod="",
      destroyMethod="")

其中name为bean的名称,可以有多个,autowire为是否自动装配,默认值为NO,initMethod为bean的初始化方法,destoryMethod为bean的销毁方法。
bean的注解具体使用如下:

@Bean
public String message() {
    return new String("hello");
}

如上的代码等价与XML配置:

<bean id="message" class="java.lang.String">
    <constructor-arg index="0" value="hello"/>
</bean>

注意:使用bean注解的方法不能是private、final、static的。

基于Java方式的配置方式不是为了完全替代基于XML方式的配置,两者可以结合使用,因此可以有两种结合使用方式:

  • 在基于Java方式的配置类中引入基于XML方式的配置文件
  • 在基于XML方式的配置文件中中引入基于Java方式的配置

引入基于XML配置文件:

<bean id="message" class="java.lang.String">
    <constructor-arg index="0" value="test"></constructor-arg>
</bean>
 
 
@Configuration("ctxConfig")
@ImportResource("classpath:com/jike/***/appCtx.xml")
public class ApplicationContextConfig {
  ……
}

可以看到在java程序中使用@ImportResource导入了XML的配置文件

引入基于Java的配置文件:

<context:annotation-config/>
<bean id="ctxConfig" class=“com.jike.***..ApplicationContextConfig"/>
 
//测试类
public void testXmlConfig() {
        String configLocations[] = {" classpath:com/jike/***/appCtx.xml"};
        ApplicationContext ctx = new ClassPathXmlApplicationContext(configLocations);
         ……
}

可以看到在XML的配置文件当中将java的配置类当中Bean来声明,第一行的是开启注解驱动支持。
值得注意的是必须得配置<context:annotation-config/>在XML配置文件中。

Spring提供了一个AnnotationConfigApplicanContext类,能够直接通过标注@Configuration的Java类启动Spring容器:
通过构造函数加载配置类:

ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConf.class);

通过编码方式注册配置类:

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(DaoConfig.class);
ctx.register(ServiceConfig.class);
ctx.refresh();

可以看到ctx注册了多个configuration类,然后通过refresh类来刷新容器以应用这些配置文件。
可以通过代码一个个的引入配置类,当然也可以使用@Import注解来引入配置类
引入多个配置类:

@Configuration
@Import(DaoConfig.class)
public class ServiceConfig  {……}

四,实现 FactoryBean

/**
 * @author liwenchao
 */
@Component("house")
public class HouseFactoryBeanTest implements FactoryBean<House> {

    private static final String HOUSE_NAME = "CoderLwc";

    @Override
    @PostConstruct
    public House getObject() throws Exception {
        House house = new House();
        house.setName(HOUSE_NAME);
        return house;
    }

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

五,实现ImportBeanDefinitionRegistrar

@Component
public class HouseFactoryBeanTest implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        RootBeanDefinition definition = new RootBeanDefinition();
        definition.setBeanClass(House.class);
        MutablePropertyValues propertyValues = new MutablePropertyValues();
        propertyValues.add("name", "lwc");
        definition.setPropertyValues(propertyValues);
        registry.registerBeanDefinition("house", definition);
        ImportBeanDefinitionRegistrar.super.registerBeanDefinitions(importingClassMetadata, registry);
    }
}

六,实现 BeanDefinitionRegistry

/**
 * @author liwenchao
 */
@Component
public class HouseFactoryBeanTest implements BeanDefinitionRegistryPostProcessor {


    /**
     * Modify the application context's internal bean definition registry after its
     * standard initialization. All regular bean definitions will have been loaded,
     * but no beans will have been instantiated yet. This allows for adding further
     * bean definitions before the next post-processing phase kicks in.
     *
     * @param registry the bean definition registry used by the application context
     * @throws BeansException in case of errors
     */
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        RootBeanDefinition definition = new RootBeanDefinition();
        definition.setBeanClass(House.class);
        MutablePropertyValues propertyValues = new MutablePropertyValues();
        propertyValues.add("name", "lwc");
        definition.setPropertyValues(propertyValues);
        registry.registerBeanDefinition("house", definition);
    }

    /**
     * Modify the application context's internal bean factory after its standard
     * initialization. All bean definitions will have been loaded, but no beans
     * will have been instantiated yet. This allows for overriding or adding
     * properties even to eager-initializing beans.
     *
     * @param beanFactory the bean factory used by the application context
     * @throws BeansException in case of errors
     */
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

    }
}

总结:不同配置方式比较
我们来看一下不同配置方式在不同方面的使用


其实Spring支持这么多的配置方式,那么这些配置方式必然有其自己独特的舞台
基于XML的配置主要使用场景:

  • 第三方类库,如DataSource、JdbcTemplate等;
  • 命名空间,如aop、context等;

基于注解的配置主要使用场景:

  • Bean的实现类是当前项目开发的,可直接在Java类中使用注解配置

基于Java类的配置主要使用场景:

  • 对于实例化Bean的逻辑比较复杂,则比较适合用基于Java类配置的方式
  • 在日常的开发中我们主要是使用XML配置和注解配置方式向结合的开发方式,一般不推荐使用基于Java类的配置方式。
  • 19
    点赞
  • 83
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值