Java开发Spring常见注解
Java开发Spring常见注解
前言
Spring注解方式减少了配置文件内容,更加便于管理,并且使用注解可以大大提高了开发效率。 下面按照分类讲解Spring中常用的一些注解。
一、声明bean的注解
1. @Component
一个通用的注解,用于标识任何 Spring 组件。标注Spring管理的Bean,使用@Component注解在一个类上,表示将此类标记为Spring容器中的一个Bean。
示例代码如下:
1 @Component 2 public class CallBackAfterCreatePolicyProducer { 3 @Resource 4 private YpProducer ypProducer; 5 }
说明:
1)@Component (把普通pojo实例化到spring容器中,相当于配置文件中的<bean id="" class=""/>)
2)@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
3)@Component是一个元注解,意思是可以注解其他类注解,如@Controller @Service @Repository @Aspect。官方的原话是:带此注解的类看为组件,当使用基于注解的配置和类路径扫描的时候,这些类就会被实例化。其他类级别的注解也可以被认定为是一种特殊类型的组件,比如@Repository @Aspect。所以,@Component可以注解其他类注解。
2. @Service
用于标识服务层组件,主要包含业务逻辑。
组合注解(组合了@Component注解),应用在service层(业务逻辑层)
1 @Slf4j 2 @Service 3 @RequiredArgsConstructor(onConstructor_ = {@Autowired}) 4 public class TppAgencyHttpProxyServiceImpl implements TppAgencyHttpProxyService { 5 }
3. @Repository
用于标识数据访问层组件,负责与数据库交互,并提供异常转换功能。
组合注解(组合了@Component注解),应用在dao层(数据访问层)。
1 @Repository 2 public interface InsuranceAgreementMapper extends MPJBaseMapper<InsuranceAgreementDO> { 3 7 }
4. @Mapper
@Mapper注解是mybatis的注解,是用来说明这个是一个Mapper,对应的xxxMapper.xml就是来实现这个Mapper。然后再server层使用@Autowired注解引用进来,会出现这样的情况,但是并不影响使用。
这是因为@Autowired是spring的注解,提示找不到相应的bean。如果有强迫症的同学,可以使用@Resource注解,因为这个是JDK的注解。
二、注入bean的注解
1. @Autowired
@Autowired注解是Spring Framework提供的一种依赖注入方式。可以用于字段、方法和构造函数上,用于指定要注入的依赖。
示例代码:
1 public class MyService { 2 @Autowired 3 private MyDependency dependency; 4 // ... 5 } 6 ```
说明:@Autowired注解用于标记要注入的依赖。Spring会根据依赖的类型(或名称和限定符)自动查找匹配的Bean,并将其注入到目标对象中。
有一点要特别注意:
使用@Autowired 依赖注入静态成员(属性)。
分析:静态变量(成员)它是属于类的,而非属于实例对象的属性;同样的静态方法也是属于类的,普通方法(实例方法)才属于对象。而Spring容器管理的都是实例对象,包括它的@Autowired依赖注入的均是容器内的对象实例,所以对于static成员是不能直接使用@Autowired注入的。
比如下面:
1 @Component 2 public class SonHolder { 3 4 @Autowired 5 private static Son son; 6 7 public static Son getSon() { 8 return son; 9 } 10 }
这很容易理解:类成员的初始化较早,并不需要依赖实例的创建,所以这个时候Spring容器可能都还没“出生”,更不要提依赖注入了。
2. @Resource
@Resource注解是Java标准库提供的一种依赖注入方式。可以用于字段、方法和构造函数上,用于指定要注入的依赖。
1 public class MyService{ 2 @Resource 3 private MyDependency dependency; 4 // ... 5 }
说明:@Resource注解是Java标准库提供的一种依赖注入方式,在Spring中借助 CommonAnnotationBeanPostProcessor来实现。它可以用于标记要注入的依赖,并根据名称匹配规则或显式指定的名称来查找依赖。
3. @RequiredArgsConstructor
@RequiredArgsConstructor 是一个 Lombok 注解,用于自动生成一个带有所有必需参数的构造函数。这个注解可以用在类级别上,会生成一个构造函数,用于初始化被 @NonNull 或者 final 标记的成员变量。
示例代码:
1 @Slf4j 2 @Service 3 @RequiredArgsConstructor(onConstructor_ = {@Autowired}) 4 public class BrowseBizServiceImpl implements BrowseBizService { 5 6 private final BrowseRpcProxyService browseRpcProxyService; 7 8 }
说明:Spring 提供了几种注入模式,一种是属性注入(Filed injection),一种是通过 Setter 方法,一种是构造器注入。Spring 从 4.0 开始, 就不推荐使用属性注入模式了 ,原因是它可以让我们忽略掉一些代码可能变坏的隐患。
所以,构造器的方法就成了我们的首选。但是使用构造器注入时,代码会很多。构造器注入通常结合private final字段来使用。使用Lombok的@RequiredArgsConstructor注解可以简化构造器的生成。
4. @inject:JSR-330提供的注解。
5. @Resource和@Autowired的区别
1)区别一:所属不同。
@Autowired 是 spring-beans 模块提供的注解。
@Resource 是 JSR 250 规范提出的注解,由 JDK 自带。
2)区别二:装配方式不同。两者都可以标注在属性或 setter 方法上。
@Autowired 注解默认是按照类型进行自动装配的。
如果同一个类型的 Bean 有多个实例,那么直接使用 @Autowired 会导致 Spring 无法确定需要注入哪个实例,从而抛出异常。
此时可以配合 @Qualifier 注解来指定 Bean 名称,以便按名称进行注入。
所以,当需要按名称装配时,可以在 @Autowired 后面加上 @Qualifier 注解,例如:
@Autowired @Qualifier("beanName") private YourBeanType yourBean;
@Resource 默认依赖 bean 的名称为属性名,并且可以通过其属性 name 进行指定。默认依赖的 bean 的类型为属性的类型,并且可以通过 type 属性进行指定。 如果未指定依赖的 bean 的名称并且属性名对应的 bean 在容器中不存在时才会按照类型进行注入,否则按照名称进行注入依赖。(先按name再按type)
3)区别三:是否强依赖不同。
@Autowired 指定的依赖默认必须存在,可以通过 required 属性指定不存在。
示例代码如下:
@Autowired(required = false)
private AdminInsuranceEventService adminInsuranceEventService;
@Resource 指定的依赖必须存在。
6. @Qualifier
通过名称指定需要注入的 Bean,特别是在同一个类型有多个实现的情况下(容器中有多个相同类型的bean)。
@Qualifier 的值必须与 Bean 的名称一致,通常在 @Component 或 @Bean 中定义。
1)方式一:假设我们有两个实现类 ServiceA 和 ServiceB,都实现了接口 MyService,如果要注入 ServiceA,可以这样写:
1 @Component("serviceA") 2 public class ServiceA implements MyService { 3 // Implementation 4 } 5 6 @Component("serviceB") 7 public class ServiceB implements MyService { 8 // Implementation 9 } 10 11 @Autowired 12 @Qualifier("serviceA") 13 private MyService myService;
2)方式二:
配置类中定义@Bean
1 @Configuration 2 public class AppConfig { 3 4 @Bean(name = "serviceA") 5 public MyService myServiceA() { 6 return new ServiceA(); 7 } 8 9 @Bean(name = "serviceB") 10 public MyService myServiceB() { 11 return new ServiceB(); 12 } 13 }
在需要注入ServiceA的地方,使用 @Qualifier 指定名称:
1 @Component 2 public class MyComponent { 3 4 @Autowired 5 @Qualifier("serviceA") 6 private MyService myService; 7 8 // 或者使用构造函数注入 9 // public MyComponent(@Qualifier("serviceA") MyService myService) { 10 // this.myService = myService; 11 // } 12 }
当然,也可以用@Resource来注入
1 import javax.annotation.Resource; 2 3 @Component 4 public class MyComponent { 5 6 @Resource(name = "serviceA") 7 private MyService myService; 8 9 // 或者使用构造函数注入方式 10 // public MyComponent(@Resource(name = "serviceA") MyService myService) { 11 // this.myService = myService; 12 // } 13 }
7. @Primary
当发生依赖注入的歧义时,我们也可以用@Primary注解来决定要注入哪个 bean。当存在多个相同类型的 bean 时,此注解定义了首选项。除非另有说明,否则将使用与 @Primary 注释关联的 bean
例如:
1 @Bean 2 public Employee tomEmployee() { 3 return new Employee("Tom"); 4 } 5 6 @Bean 7 @Primary 8 public Employee johnEmployee() { 9 return new Employee("john"); 10 }
在此示例中,两个方法都返回相同的 Employee类型。Spring 将注入的 bean 是方法 johnEmployee 返回的 bean。这是因为它包含 @Primary 注解。
8. @Qualifier 和 @Primary的区别
当我们想要指定默认情况下应该注入特定类型的 bean 时,@Primary注解很有用。
如果我们在某个注入点需要另一个 bean,我们需要专门指出它。我们可以通过 @Qualifier 注解来做到这一点。
值得注意的是,如果 @Qualifier 和 @Primary 注释都存在,那么 @Qualifier 注释将具有优先权。基本上,@Primary 是定义了默认值,而 @Qualifier 则非常具体。
例如:
1 @Component 2 @Primary 3 public class FooFormatter implements Formatter { 4 public String format() { 5 return "foo"; 6 } 7 } 8 9 @Component 10 public class BarFormatter implements Formatter { 11 public String format() { 12 return "bar"; 13 } 14 }
在这种情况下,@Primary 注解指定了默认注入的是 FooFormatter,消除了场景中的注入歧义。
三、配置类相关注解
1. @Configuration
声明当前类为配置类,相当于xml形式的Spring配置
示例代码如下:
1 @Configuration 2 @ComponentScan("com.yp") 3 public class SpringConfig { 4 5 }
2. @Bean
注解在方法上,声明当前方法的返回值为一个bean,替代xml中的方式
Spring的@Bean注解用于告诉方法,产生一个Bean对象,然后这个Bean对象交给Spring管理。产生这个Bean对象的方法Spring只会调用一次,随后Spring将会将这个Bean对象放在自己的IOC容器中。
1 @Configuration 2 public class AppConfig { 3 4 // 使用@Bean 注解表明myBean需要交给Spring进行管理 5 // 未指定bean 的名称,默认采用的是 "方法名" + "首字母小写"的配置方式 6 @Bean 7 public MyBean myBean(){ 8 return new MyBean(); 9 } 10 } 11 12 public class MyBean { 13 14 public MyBean(){ 15 System.out.println("MyBean Initializing"); 16 } 17 }
说明:@Bean 更适合在配置类中集中管理 Bean 的创建,适合定义更加灵活或需要初始化逻辑的 Bean。
3. @ComponentScan
配置组件扫描通常使用 @ComponentScan 注解。
Spring 通过组件扫描机制自动检测并注册带有这些特定注解的类为 Spring Bean。
1 import org.springframework.context.annotation.ComponentScan; 2 import org.springframework.context.annotation.Configuration; 3 4 @Configuration 5 @ComponentScan(basePackages = "com.example") 6 public class AppConfig { 7 // 其他配置 8 }
比如:指定了spring扫描的包路径为:com.example,这将说明在此包下的所有spring识别的注解都会被解析
四、切面(AOP)相关注解
1. @Aspect
声明一个切面(类上) 使用@After、@Before、@Around、@AfterReturning、@AfterwThrowing定义通知(advice),可直接将拦截规则(切点)作为参数。
示例代码如下:
1 @Component 2 @Aspect 3 public class MyAspectjAdvice { 4 5 @Pointcut("execution(* com.yp.dao.BookDao.*(..))") 6 private void pt() { 7 } 8 9 /** 10 * 前置通知 11 */ 12 @Before("pt()") 13 public void myBefore() { 14 System.out.println("前置通知..."); 15 } 16 17 /** 18 * 后置通知 19 */ 20 @After("pt()") 21 public void myAfter() { 22 System.out.println("后置通知..."); 23 } 24 }
2. @Pointcut: 声明切点
五、Spring MVC常用注解
1. @Controller
用于标识控制器层组件,处理 HTTP 请求和响应。
在使用 Spring MVC 框架开发 Web 应用程序时,@Controller 注解是用来标识一个类为控制器(Controller)的注解。控制器层负责接收用户请求,并根据请求处理逻辑选择合适的业务逻辑进行处理,最终返回响应给用户。
示例代码如下:
1 import org.springframework.stereotype.Controller; 2 import org.springframework.web.bind.annotation.RequestMapping; 3 import org.springframework.web.bind.annotation.ResponseBody; 4 5 @Controller 6 @RequestMapping("/example") 7 public class ExampleController { 8 9 @RequestMapping("/hello") 10 @ResponseBody 11 public String hello() { 12 13 return "Hello, World!"; 14 } 15 }
2. @RequestMapping
@RequestMapping 注解是 Spring MVC 框架中的一个核心注解,用于将请求映射到相应的处理方法。
示例代码如下:
1 @Controller 2 @RequestMapping("/example") 3 public class ExampleController { 7 @RequestMapping(value = "/hello", method = RequestMethod.GET) 8 @ResponseBody 9 public String hello() { 10 11 return "Hello, World!"; 12 } 13 }
除了@RequestMapping,还可以使用@PostMapping和@GetMapping。示例代码如下:
1 package com.controller; 2 import org.springframework.stereotype.Controller; 3 import org.springframework.ui.Model; 4 import org.springframework.web.bind.annotation.GetMapping; 5 import org.springframework.web.bind.annotation.PostMapping; 6 @Controller 7 public class HelloWorldController { 8 //只接受get方式的请求 9 @GetMapping("/testGetMapping") 10 public String testGetMapping(Model model) { 11 model.addAttribute("msg","测试@GetMapping注解"); 12 return "success"; 13 } 14 //只接受post方式的请求 15 @PostMapping("/testPostMapping") 16 public String testPostMapping(Model model) { 17 model.addAttribute("msg","测试@PostMapping注解"); 18 return "success"; 19 } 20 }
它可以用在类级别和方法级别上,具体作用如下:
1) 类级别的 @RequestMapping: 用于指定该类中所有处理方法的公共请求路径前缀。当用户请求的 URL 匹配该前缀时,会进入该类中的处理方法进行处理。
2) 方法级别的 @RequestMapping: 用于指定处理请求的方法和请求路径。当用户请求的 URL 匹配该路径时,会调用该方法进行处理。
3. @RequestParam
@RequestParam 注解用于将 HTTP 请求中的参数绑定到控制器方法的参数上,即获取请求中的参数值并映射到方法参数。它支持几乎所有的数据类型,包括基本数据类型和复杂数据类型。
代码示例如下:
假设我们有一个接口 /api/foos,它接受一个名为 id 的查询参数:
1 @GetMapping("/api/foos") 2 @ResponseBody 3 public String getFoos(@RequestParam String id) { 4 return "ID: " + id; 5 }
通过 GET 请求来调用 getFoos:
http://localhost:8080/spring-mvc-basics/api/foos?id=abc
----
ID: abc
4. @PathVariable
@PathVariable 注解用于获取 URL 中的动态参数,即将 URL 中的变量映射到控制器方法的参数上。这样就可以通过 URL 传递参数,而不是通过查询字符串的方式来传递参数。
示例代码如下:
1 @Controller 2 @RequestMapping("/example") 3 public class ExampleController { 4 5 6 @RequestMapping(value = "/hello/{name}", method = RequestMethod.GET) 7 @ResponseBody 8 public String hello(@PathVariable("name") String name) { 10 11 return "Hello, " + name + "!"; 12 } 13 }
5. @RequestBody
@RequestBody 注解用于将 HTTP 请求体中的数据绑定到控制器方法的参数上,即获取 POST 请求中的数据并映射到方法参数。它通常用于处理 JSON 或 XML 格式的请求体数据。
示例代码如下:
1 @PostMapping(value = "/collaborate") 2 public BeneficiaryCollaborateResp collaborate(@RequestBody @Valid BeneficiaryCollaborateReq req) { 3 4 //... 5 }
6. @ResponseBody
@ResponseBody 注解用于将方法的返回值直接作为 HTTP 响应的内容,而不是通过视图解析器返回一个视图。它通常与 @RequestMapping 注解一起使用。
7. @RestController
@RestController 是一个组合注解,它是 @Controller 和 @ResponseBody 两个注解的整合。它表示控制器类中的所有方法都会返回 JSON、XML 或其他格式的数据,而不是视图。
1 @RestController 2 @RequestMapping(value = "/insurance/v1/admin/event") 3 @RequiredArgsConstructor(onConstructor_ = {@Autowired}) 4 public class AdminInsuranceEventController { 5 private final AdminInsuranceEventService adminInsuranceEventService; 6 7 @PostMapping(value = "/statistics") 8 public AdminEventStatisticsResp eventStatistics(@RequestBody @Valid EventQueryReq req) { 9 10 //... 11 } 12 }
8. @ModelAttribute
@ModelAttribute 注解用于绑定请求参数到方法的参数或方法级别的模型属性上。
9. @SessionAttributes
@SessionAttributes 注解是用于将模型属性暂时存储在会话(Session)中的注解。它可以用在控制器类级别或控制器方法级别。
10. @ExceptionHandler
@ExceptionHandler 注解用于定义一个处理异常的方法。它可以用在控制器类级别或控制器方法级别。
示例代码:
在控制器类级别使用 @ExceptionHandler
1 @ControllerAdvice 2 public class GlobalExceptionHandler { 3 4 @ExceptionHandler(Exception.class) 5 public ModelAndView handleException(Exception e) { 6 7 ModelAndView mv = new ModelAndView(); 8 mv.addObject("errMsg", "系统异常:" + e.getMessage()); 9 mv.setViewName("error"); 10 return mv; 11 } 12 }
六、@Enable*注解说明
这些注解主要用来开启对xxx的支持。
1. @EnableAspectJAutoProxy:开启Spring对AspectJ自动代理的支持。
示例代码如下:
1 @Configuration 2 @ComponentScan("com.yp") 3 @EnableAspectJAutoProxy 4 public class SpringConfig { 5 6 }
@EnableAsync: 开启异步方法的支持。
@EnableScheduling: 开启计划任务的支持。
@EnableWebMvc :开启Web MVC的配置支持。
@EnableConfigurationProperties :开启对@ConfigurationProperties注解配置Bean的支持。
@EnableJpaRepositories:开启对SpringData JPA Repository的支持。
@EnableTransactionManagement:开启注解式事务的支持。
@EnableTransactionManagement: 开启注解式事务的支持。
@EnableCaching: 开启注解式的缓存支持。
七、常用的特殊注解
1. @PostConstruct
1)相关介绍
从Java 5 开始引入的注解,指的是在项目启动的时候执行这个方法,也可以理解为在spring容器启动的时候执行,可作为一些数据的常规化加载,比如数据字典之类的。
被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次。
2)执行顺序
通常我们会是在Spring框架中使用到@PostConstruct注解,该注解的方法在整个Bean初始化中的执行顺序:
Constructor(构造方法) -> @Autowired(依赖注入) -> @PostConstruct(注释的方法)
3)应用场景
如果想在生成对象时候完成某些初始化操作,而偏偏这些初始化操作又依赖于依赖注入,那么就无法在构造函数中实现。为此,可以使用@PostConstruct注解一个方法来完成初始化,@PostConstruct注解的方法将会在依赖注入完成后被自动调用。
举个例子:
1 @Component 2 public class MyUtils { 3 4 private static MyUtils staticInstance = new MyUtils(); 5 6 @Autowired 7 private MyMethorClassService myService; 8 9 @PostConstruct 10 public void init(){ 11 staticInstance.myService = myService; 12 } 13 }
参考链接:
https://developer.aliyun.com/article/1357291
https://cloud.tencent.com/developer/article/2350497
https://juejin.cn/post/6844904035342893063