Spring3.X学习笔记-基于注解和Java类的配置

上一篇文章里我们主要介绍了基于XML Schemal的配置方式。本篇文章里将介绍另外两种提供Bean定义的方式,基于注解和基于Java类的配置。

1、基于注解的配置

不管是XML还是注解,他们都是表达Bean定义的载体,其实质都是为Spring容器提供Bean定义的信息,表现形式上是将XML定义的东西通过类注解进行描述。Spring从2.0开始引入基于注解的配置方式,在3.0时得到进一步的完善。
下面是使用注解定义一个DAO的Bean:

package com.hhxs.bbt.dao;
import org.springframework.stereotype.Component;

// 1.通过Repository定义一个DAO的Bean
@Component("userDao")
public class UserDao {
    ...
}

在上面1处,使用@Component注解在UserDao类声明处对类进行标注,它可以被Spring容器识别,Spring容器自动将POJO转换为容器管理的Bean。它和以下的XML配置是等效的:

"userDao" class="com.hhxs.bbt.dao.UserDao">

除了@Component以外,Spring提供了三个功能基本和@Component等效的注解,它们分别用于对DAO、Service及Web层的Controller进行注解,所以也称这些注解为Bean的衍型注解:

  • @Repository:用于对DAO实现类进行标注;
  • @Service:用于对Service实现类进行标注;
  • @Controller:用于对Controller实现类进行标注。

在@Component之外提供这三个注解,是为了让注解类本身的用途更加清晰,此外Spring还赋予了它们一些特殊功能。

1.1 使用注解配置信息启动Spring容器

Spring在2.5 后提供了一个context的命名空间,它提供了通过扫描类包以应用注解定义Bean的方式:

"1.0" encoding="UTF-8"?>
"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.1.xsd
    http://www.springframework.org/schema/context
  http://www.springframework.org/schema/context/spring-context-3.1.xsd>
    Spring公共配置 

    
    package="com.hhxs.bbt" />

在上面1处通过context命名空间的compnent-scan的base-package属性指定一个需要扫描的基类包,Spring容器将会扫描这个基类包里的所有类,并从类的注解信息中获取Bean的定义信息。

如果仅希望扫描特定的类而非基包下的所有类,那么可以使用resource-pattern属性过滤特定的类,如下所示:

package="com.hhxs.bbt" resource-pattern="dao/*.class"/>

默认情况下resource-pattern属性的值为**/*.class,即基包里的所有类。这里我们设置为dao/*.class,则Spring仅会扫描基包里dao子包中的类。通过resource-pattern属性仅可按资源名称对基包中的类进行过滤,如果需要更详细的过滤,则需要用到的过滤子元素:

package="com.hhxs.bbt">
    "regex" expression="com.\hhxs.\bbt.*"/>
    "aspectj" expression="com.hhxs.bbt..*Controller+"/>
  • 表示要包含的目标类
  • 表示要排除在外的目标类

一个下可以包含若干个元素。这两个过滤元素均支持多种类型的过滤表达式,如下表所示:

类别 示例 说明
annotation com.hhxs.bbt.XxxAnnotation 所有标注了XxxAnnotation的类。该类型采用目标类是否标注了某个注解进行过滤。
assignable com.hhxs.bbt.XxxService 所有继承或扩展XxxService的类。该类型采用目标类是否继承或扩展某个特定类进行过滤。
aspectj com.hhxs.bbt..*Service+ 所有类名以Service结束的类及继承或扩展它们的类。该类型采用AspectJ表达式进行过滤。
regex com.hhxs.bbt..* 所有com.hhxs.bbt类包下的类。该类型采用正则表达式根据目标类的类名进行过滤。
custom com.hhxs.bbt.XxxTypeFilter 采用XxxTypeFilter通过代码的方式根据过滤规则。该类必须实现org.springframework.core.type.TypeFilter接口

1.2 自动装配Bean

spring使用@Autowired注解实现Bean的依赖注入。@Autowired默认按类型匹配的方式,在容器查找匹配Bean,
**当且仅有一个匹配的**Bean时,Spring将其注入到@Autowired标注的变量中。

package com.hhxs.bbt.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class LogonService {

    @Autowired
    private LogDao logDao;

    @Autowired
    private UserDao userDao;

    ...
}

如果容器中没有一个和标注变量类型匹配的bean,Spring容器启动时将报NoSuchBeanDefinitionException异常。如果希望不抛出异常可以使用@Autowired(required=false)进行标注。默认情况下,@Autowired的required属性值为true。

如果容器中有一个以上匹配的Bean时,可以通过@Qualifier注解限定Bean的名称。

package com.hhxs.bbt.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class LogonService {

    @Autowired
    private LogDao logDao;

    @Autowired
    @Qualifier("userDao")
    private UserDao userDao;

    ...
}

对集合类进行标注

如果对类中集合类的变量和方法入参进行@Autowired标注,Spring会将容器中类型匹配的所有Bean都自动注入进来。这是一个很好的特性,所以在这里介绍下。

package com.hhxs.bbt.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class MyComponent {

    // Spring会将容器中所有类型为Plugin的Bean注入到这个变量中
    @Autowired(required=false)
    private List plugins;

    public List getPlugins() {
        return plugins;
    }
}


Spring如果发现变量是一个集合类,则它会将容器中匹配集合元素类型的所有Bean都注入进来。这里,Plugin为一个接口,它拥有两个实现类,分别是OnePlugin和TwoPlugin,这两个实现类都通过@Component标注为Bean,则Spring会将这两个Bean都注入到plugins中。

2、基于Java类的配置

2.1 使用Java类提供Bean定义信息

JavaConfig是Spring的一个子项目,它旨在通过Java类的方式提供Bean的定义信息。Spring3.0基于Java类配置的核心即取材于JavaConfig。

普通的POJO只要标注@Configuration注解,就可以为Spring容器提供Bean定义的信息了,每个标注了@Bean的类方法都相当于提供一个Bean的定义信息。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

// 1.将一个POJO标注定义为Bean的配置类
@Configuration
public class AppConf {
    // 2.以下两个方法定义了两个Bean,并提供了Bean的实例化逻辑
    @Bean
    public UserDao userDao() {
        return new UserDao();
    }
    @Bean
    public LogDao logDao() {
        return new LogDao()
    }

    @Bean
    public LogonService logonService() {
        LogonServcie logonService = new LogonService();
        // 将上面2处定义的Bean注入到logonService的Bean
        logonService.setLogDao(logDao());
        logonService.setUserDao(userDao());
        return logonService;
    }
}

1处在AppConf类的定义处标注了@Configuration注解,说明这个类可用于为Spring提供Bean信息。类的方法出可以标注@Bean注解,Bean的类型由方法返回值类型决定,名称默认和方法名相同,也可通过@Bean(name=”userDao”)显示指定Bean的名称。

上面的配置和以下XML配置等效:

id="userDao" class="com.hhxs.bbt.dao.UserDao" />
id="logDao" class="com.hhxs.bbt.dao.LogDao" />
id="userDao" class="com.hhxs.bbt.conf.LogonService"  
    p:logDao-ref="userDao" p:userDao-ref="logDao" />

2.2 使用基于Java类的配置信息启动Spring容器

2.2.1 直接通过@Configuration类启动Spring容器

Spring提供了一个AnnotationConfigApplicationContext类,它能够直接通过标注@Configuration的Java类启动Spring容器。以下两种方式是等效的:

第一种:

package com.hhxs.bbt.conf;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class JavaConfigTest {
    public static void main(String[] args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConf.class);
        LogonService logonService = ctx.getBean(logonService.class);
        logonService.printHello();
    }
}


第二种:

package com.hhxs.bbt.conf;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class JavaConfigTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
        // 注册多个@Configuration配置类
        ctx.register(DaoConfig.Class);
        ctx.register(ServiceConfig.class);
        // 刷新容器以应用这些注册的配置类
        ctx.refresh();
        LogonService logonService = ctx.getBean(logonService.class);
        logonService.printHello();
    }
}

可以通过代码一个一个注册配置类,也可以通过@Import将多个配置类组装到一个配置类中,这样仅需要注册这个组装好的配置类就可以启动容器了。

package com.hhxs.bbt.conf;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.Import;

@Configurable
@Import(DaoConfig.class)
public class ServiceConfig {

    @Bean
    public LogonService logonService() {
        LogonService logonService = new LogonService();
        return logonService;
    }
}

我们既可以在XML配置文件中引用@Configuration的配置,也可以通过Configuration配置类中引用XML配置信息。只要不同形式的Bean定义信息能够加载到Spring容器中,Spring就能足够“智能”的完成Bean之间的装配。

3、不同配置方式比较

配置方式比较:

基于XML配置 基于注解配置 基于Java类配置
Bean定义 Bean实现类出通过标注
@Component、@Repository、@Service、@Controller
在标注了@Configuration的Java类中,通过在类方法上标注@Bean定义一个Bean。方法必须提供Bean的实例化逻辑。
Bean名称 通过的id或name属性定义 通过注解的value属性定义,如@Component(“userDao”)。默认名称为小写字母打头的类名(不带包名):userDao 通过@Bean的name属性定义,如@Bean(“userDao”),默认名称为方法名。
Bean注入 通过子元素或通过p命名空间的动态属性 通过在成员变量或方法入参出标注@Autowired,按类型匹配自动注入 可以通过在方法处通过@Autowired使方法入参绑定Bean,然后在方法中通过代码进行注入,还可以通过调用配置类的@Bean方法进行注入
Bean生命过程方法 通过的init-method和destory-method属性指定Bean实现类的方法名。最多只能指定一个初始化方法和一个销毁方法 通过在目标方法上标注@PostConstruct和@PreDestroy注解指定初始化或销毁方法,可以定义任意多个方法 通过@Bean的initmethod或destoryMethod指定一个初始化或销毁方法。
Bean作用范围 通过的scope属性指定 通过在类定义出标注@Scope指定 通过在Bean方法定义处标注@Scope指定
Bean延迟初始化 通过的lazy-init属性指定,默认为default,继承与的default-lazy-init设置,该值默认为false 通过在类定义处标注@Lazy指定,如@Lazy(true) 通过在Bean方法定义处标注@Lazy指定


使用场景建议:

基于XML配置 基于注解配置 基于Java类配置
适合场景 1)Bean实现类来源于第三方类库
2)命名空间的配置
Bean实现类是当前项目开发的,
可以直接在Java类中使用基于注解的配置
基于Java类配置的优势在于
可以通过代码方式控制Bean初
始化的整体逻辑。

————本文结束感谢您的阅读————

你可能感兴趣的:(spring,spring,注解,annotation)