1. Overview
1.概述
In this tutorial, we’ll discuss the most common Spring bean annotations used to define different types of beans.
在本教程中,我们将讨论最常见的Spring Bean注释,用于定义不同类型的Bean。
There are several ways to configure beans in a Spring container. Firstly, we can declare them using XML configuration. We can also declare beans using the @Bean annotation in a configuration class.
有几种方法可以在Spring容器中配置Bean。首先,我们可以使用XML配置来声明它们。我们还可以在配置类中使用@Bean注解来声明Bean。
Finally, we can mark the class with one of the annotations from the org.springframework.stereotype package, and leave the rest to component scanning.
最后,我们可以用org.springframework.stereotype包中的一个注解来标记这个类,剩下的就留给组件扫描。
2. Component Scanning
2.组件扫描
Spring can automatically scan a package for beans if component scanning is enabled.
如果启用了组件扫描,Spring可以自动扫描包中的Bean。
@ComponentScan configures which packages to scan for classes with annotation configuration. We can specify the base package names directly with one of the basePackages or value arguments (value is an alias for basePackages):
@ComponentScan配置哪些包来扫描具有注释配置的类。我们可以用basePackages或value参数之一直接指定基础包名(value是basePackages的别名)。
@Configuration
@ComponentScan(basePackages = "com.baeldung.annotations")
class VehicleFactoryConfig {}
Also, we can point to classes in the base packages with the basePackageClasses argument:
另外,我们可以用basePackageClasses参数指向基础包中的类。
@Configuration
@ComponentScan(basePackageClasses = VehicleFactoryConfig.class)
class VehicleFactoryConfig {}
Both arguments are arrays so that we can provide multiple packages for each.
两个参数都是数组,这样我们就可以为每个参数提供多个包。
If no argument is specified, the scanning happens from the same package where the @ComponentScan annotated class is present.
如果没有指定参数,扫描将从@ComponentScan注释的类所在的同一个包中进行。
@ComponentScan leverages the Java 8 repeating annotations feature, which means we can mark a class with it multiple times:
@ComponentScan利用了Java 8的重复注释功能,这意味着我们可以用它多次标记一个类。
@Configuration
@ComponentScan(basePackages = "com.baeldung.annotations")
@ComponentScan(basePackageClasses = VehicleFactoryConfig.class)
class VehicleFactoryConfig {}
Alternatively, we can use @ComponentScans to specify multiple @ComponentScan configurations:
另外,我们可以使用@ComponentScans来指定多个@ComponentScan配置。
@Configuration
@ComponentScans({
@ComponentScan(basePackages = "com.baeldung.annotations"),
@ComponentScan(basePackageClasses = VehicleFactoryConfig.class)
})
class VehicleFactoryConfig {}
When using XML configuration, the configuring component scanning is just as easy:
当使用XML配置时,配置组件的扫描也同样简单。
<context:component-scan base-package="com.baeldung" />
3. @Component
3.@Component
@Component is a class level annotation. During the component scan, Spring Framework automatically detects classes annotated with @Component:
@Component是一个类级注解。在组件扫描过程中,Spring Framework会自动检测带有@Component:注解的类。
@Component
class CarUtility {
// ...
}
By default, the bean instances of this class have the same name as the class name with a lowercase initial. In addition, we can specify a different name using the optional value argument of this annotation.
默认情况下,这个类的Bean实例具有与类名相同的名称,并带有小写的首字母。此外,我们可以使用这个注解的可选value参数指定一个不同的名字。
Since @Repository, @Service, @Configuration, and @Controller are all meta-annotations of @Component, they share the same bean naming behavior. Spring also automatically picks them up during the component scanning process.
由于@Repository、@Service、@Configuration和@Controller都是@Component的元注解,它们共享相同的bean命名行为。在组件扫描过程中,Spring也会自动拾取它们。
4. @Repository
4.@Repository
DAO or Repository classes usually represent the database access layer in an application, and should be annotated with @Repository:
DAO或Repository类通常代表应用程序中的数据库访问层,应该用@Repository:来注释。
@Repository
class VehicleRepository {
// ...
}
One advantage of using this annotation is that it has automatic persistence exception translation enabled. When using a persistence framework, such as Hibernate, native exceptions thrown within classes annotated with @Repository will be automatically translated into subclasses of Spring’s DataAccessExeption.
使用该注解的一个好处是,它启用了自动持久化异常转换功能。当使用持久化框架(如 Hibernate)时,在用 @Repository 注释的类中抛出的本地异常将被自动翻译成 Spring 的 DataAccessExeption 的子类。
To enable exception translation, we need to declare our own PersistenceExceptionTranslationPostProcessor bean:
为了启用异常翻译,我们需要声明我们自己的PersistenceExceptionTranslationPostProcessorbean。
@Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
Note that in most cases, Spring does the above step automatically.
注意,在大多数情况下,Spring会自动完成上述步骤。
Or via XML configuration:
或者通过XML配置。
<bean class=
"org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
5. @Service
5.@Service
The business logic of an application usually resides within the service layer, so we’ll use the @Service annotation to indicate that a class belongs to that layer:
应用程序的业务逻辑通常位于服务层中,所以我们将使用@Service注解来表示一个类属于该层。
@Service
public class VehicleService {
// ...
}
6. @Controller
6.@Controller
@Controller is a class level annotation, which tells the Spring Framework that this class serves as a controller in Spring MVC:
@Controller是一个类级别的注解,它告诉Spring框架这个类在Spring MVC中充当控制器。
@Controller
public class VehicleController {
// ...
}
7. @Configuration
7.@Configuration(配置)
Configuration classes can contain bean definition methods annotated with @Bean:
Configuration类可以包含用@Bean注解的bean定义方法。
@Configuration
class VehicleFactoryConfig {
@Bean
Engine engine() {
return new Engine();
}
}
8. Stereotype Annotations and AOP
8.定型注释和AOP
When we use Spring stereotype annotations, it’s easy to create a pointcut that targets all classes that have a particular stereotype.
当我们使用Spring定型注释时,很容易创建一个针对所有具有特定定型的类的点式。
For instance, suppose we want to measure the execution time of methods from the DAO layer. We’ll create the following aspect (using AspectJ annotations), taking advantage of the @Repository stereotype:
例如,假设我们想测量DAO层的方法的执行时间。我们将利用@Repository定型,创建以下方面(使用AspectJ注解)。
@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;
}
}
In this example, we created a pointcut that matches all the methods in classes annotated with @Repository. Then we used the @Around advice to target that pointcut, and determine the execution time of the intercepted methods calls.
在这个例子中,我们创建了一个切点来匹配所有用@Repository注释的类中的方法。然后我们使用@Around建议来定位该点切,并确定拦截的方法调用的执行时间。
Furthermore, using this approach, we can add logging, performance management, audit, and other behaviors to each application layer.
此外,使用这种方法,我们可以在每个应用层添加日志、性能管理、审计和其他行为。
9. Conclusion
9.结论
In this article, we examined the Spring stereotype annotations and discussed what type of semantics they each represent.
在这篇文章中,我们研究了Spring定型注释,并讨论了它们各自代表什么类型的语义。
We also learned how to use component scanning to tell the container where to find annotated classes.
我们还学习了如何使用组件扫描来告诉容器在哪里找到注释的类。
Finally, we learned how these annotations lead to a clean, layered design, and separation between the concerns of an application. They also make configuration smaller, as we no longer need to explicitly define beans manually.
最后,我们了解到这些注解如何导致干净、分层的设计,以及应用程序中各关注点之间的分离。它们还使配置变得更小,因为我们不再需要明确地手动定义Bean。
As usual, the examples are available over on GitHub.
像往常一样,这些例子可以在GitHub上找到over。