ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
# Spring – 原型注解 > 原文: [https://howtodoinjava.com/spring-core/stereotype-annotations/](https://howtodoinjava.com/spring-core/stereotype-annotations/) 在[Spring 自动装配](https://howtodoinjava.com/spring-core/spring-beans-autowiring-concepts/)中,`@Autowired`注解仅处理装配部分。 我们仍然必须定义 bean,以便容器知道它们并可以为我们注入它们。 启用`@Component`,`@Repository`,`@Service`和`@Controller`注解并启用**自动组件扫描**后,Spring 会自动将 bean 导入容器并注入依赖项。 这些注解也称为**原型注解**。 在开始使用这些注解的示例之前,让我们学习有关这些注解的快速事实,这将有助于我们更好地决定何时使用哪种注解。 ## 1\. Spring bean 原型注解 #### 1.1. `@Component`注解 `@Component`注解将 Java 类标记为 Bean,因此 spring 的组件扫描机制可以将其拾取并将其拉入应用程序上下文。 要使用此注解,请将其应用于类,如下所示: ```java @Component public class EmployeeDAOImpl implements EmployeeDAO { ... } ``` #### 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` ```java <context:component-scan base-package="com.howtodoinjava.demo.service" /> <context:component-scan base-package="com.howtodoinjava.demo.dao" /> <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 和管理者层,我们经常有单独的类和接口。 用于定义合同的接口,以及用于定义合同实现的类。 在哪里使用这些注解? 让我们找出答案。 > 始终对**具体类**使用注解; 而不是通过接口。 ```java public interface EmployeeDAO { //... } @Repository public class EmployeeDAOImpl implements EmployeeDAO { //... } ``` 在 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` ```java public interface EmployeeDAO { public EmployeeDTO createNewEmployee(); } @Repository ("employeeDao") public class EmployeeDAOImpl implements EmployeeDAO { public EmployeeDTO createNewEmployee() { EmployeeDTO e = new EmployeeDTO(); e.setId(1); e.setFirstName("Lokesh"); e.setLastName("Gupta"); return e; } } ``` `EmployeeManager.java and EmployeeManagerImpl.java` ```java public interface EmployeeManager { public EmployeeDTO createNewEmployee(); } @Service ("employeeManager") public class EmployeeManagerImpl implements EmployeeManager { @Autowired EmployeeDAO dao; public EmployeeDTO createNewEmployee() { return dao.createNewEmployee(); } } ``` `EmployeeController.java` ```java @Controller ("employeeController") public class EmployeeController { @Autowired EmployeeManager manager; public EmployeeDTO createNewEmployee() { return manager.createNewEmployee(); } } ``` `EmployeeDTO.java` ```java public class EmployeeDTO { private Integer id; private String firstName; private String lastName; } ``` #### 5.2. 运行演示 让我们测试上述配置和注解: `TestSpringContext.java` ```java import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.howtodoinjava.demo.service.EmployeeManager; public class TestSpringContext { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //EmployeeManager manager = (EmployeeManager) context.getBean(EmployeeManager.class); //OR this will also work EmployeeController controller = (EmployeeController) context.getBean("employeeController"); System.out.println(controller.createNewEmployee()); } } ``` 程序输出。 `Console` ```java Jan 22, 2015 6:17:57 PM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1b2b2f7f: startup date [Thu Jan 22 18:17:57 IST 2015]; root of context hierarchy Jan 22, 2015 6:17:57 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions INFO: Loading XML bean definitions from class path resource [applicationContext.xml] Employee [id=1, firstName=Lokesh, lastName=Gupta] ``` 如果需要更多说明,请给我评论/查询。 学习愉快! 阅读更多: [`@Component`与`@Bean`](https://stackoverflow.com/questions/10604298/spring-component-versus-bean) [`@Component`注解](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/stereotype/Component.html) [`@Repository`注解](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/stereotype/Repository.html) [`@Service`注解](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/stereotype/Service.html) [`@Controller`注解](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/stereotype/Controller.html)