1. 概述
本教程,我们将学习Spring中有关Bean定义的常用注解。
2. @ComponentScan
我们知道Spring 会自动扫描package下的bean。
使用@ComponentScan
可指定需要扫描的包,通过basePackages
或value
参数指定扫描路径(value
是basePackages
的别名):
@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上找到。