Spring Learning (22) Introduction and Comparison of Three Ways of Bean Configuration (XML, Annotation, Java Class)

This article will introduce the characteristics and usage conditions of three different ways of Spring Bean configuration in detail.
mainly includes:
  • XML-based configuration
  • Annotation-based configuration
  • Java class-based configuration
1. XML-based configuration
2. Annotation-based configuration
Spring 2.0 began to introduce an annotation -based configuration method, that is, the definition information of a bean can be realized by annotating annotations on the implementation class of the bean.
For specific knowledge about annotations, please refer to the introduction of Java annotations (Annotation)
@Component is the basic annotation in the Spring container, which represents a component ( bean ) in the container and can be used at any level. The following example describes the use of this annotation.
Example of annotation configuration:
@Component("userDao")
public class userDao{......}
He is equivalent to XML configuration
<bean id="userDao" class="cn.lovepi.***.userDao"/>
In addition, there are some other annotations that can be used to annotate beans, which can make the purpose of the annotated class itself more clear, in addition, specific annotations also have specific functions.
Spring provides a context namespace after 2.5, which provides a way to load beans defined by annotations by scanning class packages .
You can use resource-pattern in the context to filter out specific classes.
<context:component-scan base-package="cn.lovepi.spring" resource-pattern="anno/*.class"/>

By default, *.class under the package is loaded, that is, all classes are scanned. After resource-pattern is used, only all classes under the anno subpackage under the package are scanned.
However, using resource-pattern does not provide us with complete functionality, so we have to use the method of filtering child elements .
<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>

in:
include-filter indicates the target class to be included,
exclude-filter indicates the target class to be excluded

There can be multiple include-filters and exclude-filters under a component-scan tag ,
过滤表达式所支持的类型如下表所示:

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

Spring3.0提供了一系列的针对依赖注入的注解,这使得Spring IoC在XML文件之外多了一种可行的选择,主要包含如下注解类型:
  • Bean的定义注解
  • Bean的生命周期注解
  • Bean的依赖检查注解
  • Bean的自动装配注解
1.Bea n的定义注解
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提供的两个接口:initializingBeanDisposableBean,这种方法是要求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";
    }
}<strong>
</strong>
然后还需要一个测试类,来查看配置是否成功
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  {……}
总结:不同配置方式比较
我们来看一下不同配置方式在不同方面的使用


其实Spring支持这么多的配置方式,那么这些配置方式必然有其自己独特的舞台

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

  • 第三方类库,如DataSourceJdbcTemplate等;
  • 命名空间,如aopcontext等;
基于注解的配置主要使用场景:
  • Bean的实现类是当前项目开发的,可直接在Java类中使用注解配置
基于Java类的配置主要使用场景
  • 对于实例化Bean的逻辑比较复杂,则比较适合用基于Java类配置的方式
在日常的开发中我们主要是使用XML配置注解配置方式向结合的开发方式,一般不推荐使用基于Java类的配置方式。




















Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325727842&siteId=291194637