原文: https://howtodoinjava.com/spring-core/stereotype-annotations/

Spring 自动装配中,@Autowired注解仅处理装配部分。 我们仍然必须定义 bean,以便容器知道它们并可以为我们注入它们。

启用@Component@Repository@Service@Controller注解并启用自动组件扫描后,Spring 会自动将 bean 导入容器并注入依赖项。 这些注解也称为原型注解

在开始使用这些注解的示例之前,让我们学习有关这些注解的快速事实,这将有助于我们更好地决定何时使用哪种注解。

1. Spring bean 原型注解

1.1. @Component注解

@Component注解将 Java 类标记为 Bean,因此 spring 的组件扫描机制可以将其拾取并将其拉入应用程序上下文。 要使用此注解,请将其应用于类,如下所示:

  1. @Component
  2. public class EmployeeDAOImpl implements EmployeeDAO {
  3. ...
  4. }

1.2. @Repository注解

尽管以上使用@Repository足够好,但是我们可以使用更合适的注解,该注解专门为 DAO 提供额外的好处,即@Repository注解。 @Repository注解是@Component注解的特化,具有相似的用途和功能。 除了将 DAO 导入 DI 容器之外,还使未经检查的异常(从 DAO 方法抛出)有资格将转换为 Spring DataAccessException

1.3. @Service注解

@Service注解也是组件注解的一种特殊形式。 它目前不提供@Component注解以外的任何其他行为,但是最好在服务层类中使用@Service而不是@Component,因为可以更好地指定意图。 此外,将来工具支持和其他行为可能会依赖它。

1.4. @Controller注解

@Controller注解将一个类标记为 Spring Web MVC 控制器。 它也是@Component专长,因此标有它的 bean 将自动导入 DI 容器中。 当我们将@Controller注解添加到类中时,我们可以使用另一个注解,即@RequestMapping; 将 URL 映射到类的实例方法。

实际使用中,我们将遇到非常罕见的情况,需要使用@Component注释。 在大多数情况下,我们将使用@Repository@Service@Controller注解。 如果该类不属于控制器,服务和 DAO 这三个类别中的任何一个,则应使用@Component

如果我们想定义将要在 DI 容器中注册的 bean 的名称,则可以在注解属性本身中传递该名称,例如@Service(employeeManager")

2. 启用组件扫描

以上四个注解仅在由 Spring 框架的 DI 容器扫描时才进行扫描和配置。 要启用此扫描,我们将需要在applicationContext.xml文件中使用context:component-scan标签。

applicationContext.xml

  1. <context:component-scan base-package="com.howtodoinjava.demo.service" />
  2. <context:component-scan base-package="com.howtodoinjava.demo.dao" />
  3. <context:component-scan base-package="com.howtodoinjava.demo.controller" />

context:component-scan元素需要base-package属性,顾名思义,该属性指定了递归组件搜索的起点。 我们可能不希望将顶层软件包交给 spring,所以您应该声明三个component-scan元素,每个元素都具有指向另一个软件包的base-package属性。

声明组件扫描后,您不再需要声明context:annotation-config,因为在启用组件扫描时隐式启用了自动装配。

3. 使用@Component@Repository@Service@Controller注解

正如我已经说过的,您在 DAO,管理器和控制器类上使用@Repository@Service@Controller注解。 但是在现实生活中,在 DAO 和管理者层,我们经常有单独的类和接口。 用于定义合同的接口,以及用于定义合同实现的类。

在哪里使用这些注解? 让我们找出答案。

始终对具体类使用注解; 而不是通过接口。

  1. public interface EmployeeDAO
  2. {
  3. //...
  4. }
  5. @Repository
  6. public class EmployeeDAOImpl implements EmployeeDAO
  7. {
  8. //...
  9. }

在 bean 上具有这些构造型注解后,就可以直接使用在具体类中定义的 bean 引用。 注意引用的类型为接口。 在这种情况下,Spring DI 容器足够聪明,可以注入正确的实例。

4. @Component@Bean注解之间的区别

在 Spring 中,两个注解都大不相同。

@Component用于使用类路径扫描自动检测和自动配置 bean。 在带注解的类和 Bean 之间存在隐式的一对一映射(即每个类一个 Bean)。

@Bean用于显式声明单个 bean,而不是让 Spring 为我们自动完成。

另一个很大的区别是@Component类级别注解,其中@Bean方法级别注解,默认情况下,该方法的名称用作 Bean 名称。

5. 演示

5.1. Bean 定义

EmployeeDAO.java and EmployeeDAOImpl.java

  1. public interface EmployeeDAO
  2. {
  3. public EmployeeDTO createNewEmployee();
  4. }
  5. @Repository ("employeeDao")
  6. public class EmployeeDAOImpl implements EmployeeDAO
  7. {
  8. public EmployeeDTO createNewEmployee()
  9. {
  10. EmployeeDTO e = new EmployeeDTO();
  11. e.setId(1);
  12. e.setFirstName("Lokesh");
  13. e.setLastName("Gupta");
  14. return e;
  15. }
  16. }

EmployeeManager.java and EmployeeManagerImpl.java

  1. public interface EmployeeManager
  2. {
  3. public EmployeeDTO createNewEmployee();
  4. }
  5. @Service ("employeeManager")
  6. public class EmployeeManagerImpl implements EmployeeManager
  7. {
  8. @Autowired
  9. EmployeeDAO dao;
  10. public EmployeeDTO createNewEmployee()
  11. {
  12. return dao.createNewEmployee();
  13. }
  14. }

EmployeeController.java

  1. @Controller ("employeeController")
  2. public class EmployeeController
  3. {
  4. @Autowired
  5. EmployeeManager manager;
  6. public EmployeeDTO createNewEmployee()
  7. {
  8. return manager.createNewEmployee();
  9. }
  10. }

EmployeeDTO.java

  1. public class EmployeeDTO {
  2. private Integer id;
  3. private String firstName;
  4. private String lastName;
  5. }

5.2. 运行演示

让我们测试上述配置和注解:

TestSpringContext.java

  1. import org.springframework.context.ApplicationContext;
  2. import org.springframework.context.support.ClassPathXmlApplicationContext;
  3. import com.howtodoinjava.demo.service.EmployeeManager;
  4. public class TestSpringContext
  5. {
  6. public static void main(String[] args)
  7. {
  8. ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  9. //EmployeeManager manager = (EmployeeManager) context.getBean(EmployeeManager.class);
  10. //OR this will also work
  11. EmployeeController controller = (EmployeeController) context.getBean("employeeController");
  12. System.out.println(controller.createNewEmployee());
  13. }
  14. }

程序输出。

Console

  1. Jan 22, 2015 6:17:57 PM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
  2. INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1b2b2f7f:
  3. startup date [Thu Jan 22 18:17:57 IST 2015]; root of context hierarchy
  4. Jan 22, 2015 6:17:57 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
  5. INFO: Loading XML bean definitions from class path resource [applicationContext.xml]
  6. Employee [id=1, firstName=Lokesh, lastName=Gupta]

如果需要更多说明,请给我评论/查询。

学习愉快!

阅读更多:

@Component@Bean
@Component注解
@Repository注解
@Service注解
@Controller注解