1. 概述

本教程,我们将学习Spring中有关Bean定义的常用注解。

2. @ComponentScan

我们知道Spring 会自动扫描package下的bean。

使用@ComponentScan可指定需要扫描的包,通过basePackagesvalue参数指定扫描路径(valuebasePackages的别名):

@Configuration
@ComponentScan(basePackages = "com.baeldung.annotations")
class VehicleFactoryConfig {}

此外,我们还可以通过 basePackageClasses 参数指向扫描某个class所在的包:

@Configuration
@ComponentScan(basePackageClasses = VehicleFactoryConfig.class)
class VehicleFactoryConfig {}

这两个参数都是数组,因此我们可以添加多个包路径。

如果没有指定参数,扫描将从包含@ComponentScan注解的类所在的包中进行。

@ComponentScan 支持在同一个类上多次使用,这里利用了Java 8的重复注解(Repeating Annotations)的特性:

@Configuration
@ComponentScan(basePackages = "com.baeldung.annotations")
@ComponentScan(basePackageClasses = VehicleFactoryConfig.class)
class VehicleFactoryConfig {}

或者通过@ComponentScans指定多个@ComponentScan也是一样的:

@Configuration
@ComponentScans({ 
  @ComponentScan(basePackages = "com.baeldung.annotations"), 
  @ComponentScan(basePackageClasses = VehicleFactoryConfig.class)
})
class VehicleFactoryConfig {}

XML配置方式:

<context:component-scan base-package="com.baeldung" />

3. @Component

@Component是一个类级别的注解。在组件扫描过程中,Spring框架会自动检测带有@Component注解的类:

@Component
class CarUtility {
    // ...
}

默认情况下,bean的名字与类名相同,首字母小写。可通过value参数自定义bean名称。

值得一提的是@Repository@Service@Configuration@Controller都是@Component的元注解,所以它们具有相同的bean命名行为。Spring还会在组件扫描过程中自动识别它们。

4. @Repository 注解

DAO或Repository类通常代表应用程序的数据库访问层,并应使用@Repository注解:

@Repository
class VehicleRepository {
    // ...
}

使用这个注解的一个优点是它启用了自动持久化异常转换。当使用如Hibernate这样的持久化框架时,被@Repository注解的类内部抛出的异常将自动转换为Spring的DataAccessException子类。

要启用异常转换,我们需要声明自己的PersistenceExceptionTranslationPostProcessor bean:

@Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
    return new PersistenceExceptionTranslationPostProcessor();
}

请注意,在大多数情况下,Spring会自动完成上述步骤。

或者通过XML配置:

<bean class=
  "org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>

5. @Service 注解

应用的业务逻辑通常位于服务层,使用@Service注解来标记一个类属于该层:

@Service
public class VehicleService {
    // ...    
}

6. @Controller 注解

@Controller表明个类在Spring MVC中充当控制器角色

@Controller
public class VehicleController {
    // ...
}

7. @Configuration 注解

@Configuration类可以包含带有@Bean注解的bean定义方法:

@Configuration
class VehicleFactoryConfig {

    @Bean
    Engine engine() {
        return new Engine();
    }

}

8. Stereotype注解和AOP

当我们使用Spring的Stereotype注解时(即上面提到的几个组件),创建针对特定Stereotype类型类的切点非常容易。

Stereotype 直翻为“刻板印象”,Spring 官网文档中给出了解释,stereotype annotation 是用来表示这个类或方法在系统架构中的角色和用途。 上面提到的@Repository、@Service、@Controller都是属于Stereotype注解,开发者看到注解就能知道该类所属层级,见名知意。

例如,我们要统计DAO层方法的执行时间:

@Aspect
@Component
public class PerformanceAspect {
    @Pointcut("within(@org.springframework.stereotype.Repository *)")
    public void repositoryClassMethods() {};

    @Around("repositoryClassMethods()")
    public Object measureMethodExecutionTime(ProceedingJoinPoint joinPoint) 
      throws Throwable {
        long start = System.nanoTime();
        Object returnValue = joinPoint.proceed();
        long end = System.nanoTime();
        String methodName = joinPoint.getSignature().getName();
        System.out.println(
          "Execution of " + methodName + " took " + 
          TimeUnit.NANOSECONDS.toMillis(end - start) + " ms");
        return returnValue;
    }
}

在这个例子中,我们创建了一个匹配所有被@Repository注解类的方法的切点。然后,我们在@Around advice里计算调用耗时。

此外,通过这种方法,我们可以在每个应用层添加日志、性能管理、审计和其他行为。

9. 总结

在这篇文章中,我们学习了Spring常用的Stereotype注解,并讨论了它们各自代表的语义。

我们也了解了如何使用组件扫描告诉容器在哪里找到带有注解的类。

最后,我们了解到这些注解如何引导出清晰的分层设计,以及在应用中分离关注点。它们还使配置更简洁,因为我们不再需要手动显式地定义所有bean。

管理,示例代码可在GitHub上找到。


» 下一篇: Java周报, 44