SpringBoot中那些常用注解分析-1

简介: SpringBoot中那些常用注解分析-1

这里我们尝试总结开发中常用的那些注解使用与区别。

【1】定义/注入bean的注解

① @Component


标明带该注解的类是“组件”。当使用基于注解的配置和类路径扫描时,此类类被视为自动检测的候选类。@Component 注解作用于类,通常是通过路径扫描来自动侦测以及自动装配到 Spring 容器中(我们可以使用 @ComponentScan 注解定义要扫描的路径从中找出标识了需要装配的类自动装配到 Spring 的 bean 容器中)。如下所示,其只有一个属性value用来定义组件名称。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component {
  String value() default "";
}


对应的xml配置标签<context:component-scan>


base-package 属性指定一个需要扫描的基类包,Spring 容器将会扫描这个基类包里及其子包中的所有类。当需要扫描多个包时, 可以使用逗号分隔。

如果仅希望扫描特定的类而非基包下的所有类,可使用 resource-pattern 属性过滤特定的类,示例:

<context:include-filter> 子节点表示要包含的目标类

<context:exclude-filter> 子节点表示要排除在外的目标类

<context:component-scan> 下可以拥有若干个 <context:include-filter> 和 <context:exclude-filter> 子节点。


<context:component-scan> 元素还会自动注册 AutowiredAnnotationBeanPostProcessor 实例, 该实例可以自动装配具有 @Autowired 和 @Resource 、@Inject注解的属性。

② @Bean

作用于方法上的注解,用来定义/产生一个bean注入到spring容器中。

如下所示,注入一个bean到spring容器中,默认名字为myBean。

@Bean
public MyBean myBean() {
     // instantiate and configure MyBean obj
    return obj;
}


如下所示,注入一个bean到spring容器中,自定义bean名称

// bean名称可以是一个数组
@Bean({"b1", "b2"})
public MyBean myBean() {
     // instantiate and configure MyBean obj
    return obj;
}


与Profile, Scope, Lazy, DependsOn, Primary, Order结合,如下所示:

@Bean({"b1", "b2"})
@Profile("production")
@Scope("prototype")
@Lazy
@Primary
@Order(1)
public MyBean myBean() {
     // instantiate and configure MyBean obj
    return obj;
}

通常,标注@Bean的方法是应用在标注@Configuration的类中,如下所示:

@Configuration
public class AppConfig {
  @Bean
  public MyBean myBean() {
       // instantiate and configure MyBean obj
      return obj;
  }
}


当然,标注@Bean的方法并非一定要在标注@Configuration的类,可以在一个标注@Component或者甚至一个普通类中。在这种情况下,在这种情况下,@Bean方法将以所谓的'lite'模式进行处理。将会被作为一个类似的“工厂方法”进行调用,如下所示:

@Component
public class Calculator {
  public int sum(int a, int b) {
       return a+b;
  }
  @Bean
  public MyBean myBean() {
     return new MyBean();
  }
}


如果想通过@Bean方法自定义一些BeanFactoryPostProcessor,如PropertySourcesPlaceholderConfigurer。那么建议使用静态方法以避免问题(因为这些处理器必须在容器生命周期早期阶段实例化):

@Bean
 public static PropertySourcesPlaceholderConfigurer pspc() {
    // instantiate, configure and return pspc ...
}


源码如下所示,属性比@Component多,表示其有更高的自定义性。

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
  @AliasFor("name")
  String[] value() default {};
   // bean的名称
  @AliasFor("value")
  String[] name() default {};
   // 是否允许通过名字或者type被其他bean注入,默认不允许
  @Deprecated
  Autowire autowire() default Autowire.NO;
   // 是否作为自动注入的候选者
  boolean autowireCandidate() default true;
   // 初始化方法,默认为空
  String initMethod() default "";
   // 销毁方法
  String destroyMethod() default AbstractBeanDefinition.INFER_METHOD;
}



③ @Controller、@Service、@Repository

这三个与@Component作用一样,都是注入bean到容器中。不同的是,这三个是针对不同的使用场景所采取的特定功能化的注解组件。而@Component则可以应用于所有场景,是一个通用的Spring容器管理的单例bean组件。

① @Controller

标明当前组件是一个“Controller”,通常与@RequestMapping注解配合使用。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
   // 组件名称
  @AliasFor(annotation = Component.class)
  String value() default "";
}


② @Service

标明当前组件是一个“Service”最初由领域驱动设计(Evans,2003)定义为“作为模型中独立的接口提供的操作,没有封装状态。”还可表示类是“业务服务外观”(在核心J2EE模式意义上)或类似的东西。

@Targ@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {
   // 组件名称
  @AliasFor(annotation = Component.class)
  String value() default "";
}


③ @Repository

标明当前组件是一个“Repository”,最初由领域驱动设计(Evans,2003)定义为“用于封装存储、检索和搜索行为的机制,模拟对象集合”。实现“Data Access Object”等传统JavaEE模式的团队也可以将此原型应用于DAO类,不过在这样做之前,应该注意理解Data Access Object 和DDD-style repositories之间的区别

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Repository {
  @AliasFor(annotation = Component.class)
  String value() default "";
}

④ @Mapper

非Spring体系的,而是mybatis框架的,标记当前接口是MyBatis mappers。

@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER })
public @interface Mapper {
  // Interface Mapper
}

【2】装配类注解

@Autowired 是Spring注解,@Resource(JSR250)和@Inject(JSR330)是JAVA规范的注解。

① @Autowire


将构造函数、字段、setter方法或config方法标记为由Spring的依赖注入,是javax.inject.Inject的替代方案,提供了required属性标明是否必须。

@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
   // 是否必须,默认true
  boolean required() default true;
}


@Autowire注解是被AutowiredAnnotationBeanPostProcessor解析处理的,你不能在BeanPostProcessor类型的bean中使用该注解。

@Authwired 使用注意事项:


默认情况下, 所有使用 @Authwired 注解的属性都需要被设置。

当 Spring 找不到匹配的 Bean 装配属性时, 会抛出异常, 若某一属性允许不被设置, 可以设置 @Authwired 注解的 required 属性为 false。


默认情况下, 当 IOC 容器里存在多个类型兼容的 Bean 时, 通过类型的自动装配将无法工作。

此时可以在 @Qualifier 注解里提供 Bean 的名称. Spring 允许对方法的入参标注 @Qualifiter 已指定注入 Bean 的名称。


① 标记构造方法

作为spring bean使用时,只有一个构造器可以被@Autowired(“true”)声明。也就是使用该注解并且required属性为true只能标准在一个构造器上。


如果多个构造函数使用注解@Autowired(“false”),则它们将被视为自动装配的候选对象。将选择具有通过在Spring容器中匹配bean所能满足的最大数量依赖项的构造函数。如果没有一个候选者能够满足要求,那么将使用primary/default 构造函数(如果存在)。


类似地,如果一个类声明了多个构造函数,但没有一个用@Autowired注解,那么将使用primary/default 构造函数(如果存在)。


如果一个类一开始只声明一个构造函数,那么它将始终被使用,即使没有声明注解。带注解的构造函数不必是public的。

② 标记field

字段在构造bean之后,在调用任何配置方法之前被注入。这样的配置字段不必是public。这种场景也是我们经常使用的,如下所示:

@Controller
@RequestMapping("/course")
public class CourseController {
    private static  final Logger logger= LoggerFactory.getLogger(CourseController.class);
    @Autowired
    SysMajorService majorService;
  //...
}    


③ 标记方法

配置方法可以有任意名称和任意数量的参数,每个参数都将与Spring容器中的匹配bean自动关联。也就是说@Bean的方法参数从容器中获取,这与默认不写@Autowired效果是一样的,都能自动装配。


Bean属性set方法实际上只是这种通用配置方法的一个特例。这样的配置方法不必是公共的。


④ 标记Parameters

尽管{@code@Autowired}从技术上讲可以在SpringFramework 5.0以来的单个方法或构造函数参数上声明,但框架的大多数部分都忽略了此类声明。核心Spring框架中唯一积极支持autowired parameters的部分是spring-test模块中的JUnit Jupiter


⑤ Multiple Arguments and ‘required’ Semantics

对于多参数构造函数或方法,required属性适用于所有参数。单个参数如果声明为Java-8的Java.util.Optional,或者从Spring Framework 5.0开始的@Nullable,或者在Kotlin中声明为NOTNULL参数类型,就会覆盖基本的“required”语义。


⑥ Arrays, Collections, and Maps


对于arrays 、Collection或Map类型,容器自动装配与声明的值类型匹配的所有bean。为此,map的键必须声明为类型 String,该类型将被解析为相应的bean名称。考虑到目标组件的org.springframework.core.ordered和 org.springframework.core.annotation.Order@Order值,将对此类容器提供的集合进行排序,否则将遵循它们在容器中的注册顺序。


也就是说@Authwired 注解可以应用在数组类型的属性上, 此时 Spring 将会把所有匹配的 Bean 进行自动装配。@Authwired 注解也可以应用在集合属性上, 此时 Spring 读取该集合的类型信息, 然后自动装配所有与之兼容的 Bean。当@Authwired 注解用在 java.util.Map 上时, 若该 Map 的键值为 String, 那么 Spring 将自动装配与之 Map 值类型兼容的 Bean, 此时 Bean 的名称作为键值。

————————————————

⑦ @Primary注解

当没有使用@Qualifier注解,而又找到了多个该类型的bean时,@Primary注解让Spring进行自动装配的时候,默认使用首选的bean。

@Configuration
@ComponentScan({"com.web.service","com.web.dao",
  "com.web.controller","com.web.bean"})
public class MainConifgOfAutowired {
  @Primary
  @Bean("bookDao")
  public BookDao bookDao(){
    BookDao bookDao = new BookDao();
    bookDao.setLable("2");
    return bookDao;
  }


⑧ 回顾xml方式使用

以前我们可能使用xml注入bean并完成bean的依赖:

<bean id="address" class="com.web.autowire.Address" 
   p:city="Beijing" p:street="huilongguan" >
</bean>
<bean id="car" class="com.web.autowire.Car" 
   p:brand="Audi" p:price="500000.0">
</bean>
<!-- 手工装配 -->
<bean id="person" class="com.web.autowire.Person" 
   p:name="Audi" p:address-ref="address" p:car-ref="car">
</bean>

使用Autowire方式

<!-- Autowire byName -->
<bean id="person2" class="com.web.autowire.Person" 
  p:name="Audi" autowire="byName">
</bean>
<!-- Autowire byType -->
<bean id="person3" class="com.web.autowire.Person" 
    p:name="Audi" autowire="byType">
</bean>

② @Resource


Resource 注解标记应用程序所需的资源。此注解可以应用于应用程序组件类,也可以应用于组件类的字段或方法。当注解应用于字段或方法时,容器将在组件初始化时将请求的资源的实例注入应用程序组件。如果注解应用于组件类,则注解将声明应用程序将在运行时查找的资源。

@Target({TYPE, FIELD, METHOD})
@Retention(RUNTIME)
public @interface Resource {
     //资源的JNDI名称。对于字段,默认值为字段名。对于方法,默认值是与方法对应的JavaBeans属性名。
     //对于类注解,没有默认值,这一点必须明确。
    String name() default "";
  // 寻找的资源的名称
    String lookup() default "";
     // 资源的Java type。
    Class<?> type() default java.lang.Object.class;
     //资源的两种可能的验证类型。
    enum AuthenticationType {
            CONTAINER,
            APPLICATION
    }
    AuthenticationType authenticationType() default AuthenticationType.CONTAINER;
     // 资源是否可以被分享
    boolean shareable() default true;
     // 资源映射的名称
    String mappedName() default "";
    String description() default "";
}


@Resource 默认按名称装配,当找不到与名称匹配的 bean 时才按照类型进行装配。名称可以通过 name 属性指定,如果没有指定 name 属性,当注解写在字段上时,默认取字段名,当注解写在 setter 方法上时,默认取属性名进行装配。注意:如果 name 属性一旦指定,就只会按照名称进行装配。@Autowire和@Qualifier配合使用效果和@Resource一样

@Autowired(required = false) 
@Qualifier("myBean")
private MyBean myBean;
@Resource(name = "myBean")
private MyBean myBean;


@Resource 装配顺序


如果同时指定 name 和 type,则从容器中查找唯一匹配的 bean 装配,找不到则抛出异常;


如果指定 name 属性,则从容器中查找名称匹配的 bean 装配,找不到则抛出异常;


如果指定 type 属性,则从容器中查找类型唯一匹配的 bean 装配,找不到或者找到多个抛出异常;


如果不指定,则自动按照 byName 方式装配,如果没有匹配,则回退一个原始类型进行匹配,如果匹配则自动装配。

③ @Inject

需要导入javax.inject的包,和Autowired的功能一样但是没有required=false的功能,支持@Primary注解。

<!-- https://mvnrepository.com/artifact/javax.inject/javax.inject -->
<dependency>
  <groupId>javax.inject</groupId>
  <artifactId>javax.inject</artifactId>
  <version>1</version>
</dependency>


实例如下:

@Service
public class BookService {
  @Inject
  private BookDao bookDao;
  //...
} 


【3】配置类注解

① @Configuration

常见的就是@Configuration。标明一个类声明一个或多个@Bean方法,并可由Spring容器处理以在运行时为这些Bean生成Bean定义和服务请求,如下所示:

@Configuration
 public class AppConfig {  
    @Bean
    public MyBean myBean() {
       // instantiate, configure and return bean ...
   }
}


① Configuration源码

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
  // 组件名称,自定义名称适用于当前类被作为一个组件进行扫描
  //或者直接通过 AnnotationConfigApplicationContext获取
  @AliasFor(annotation = Component.class)
  String value() default "";
   // @Bean方法是否应该被代理
  boolean proxyBeanMethods() default true;
}

② 注入配置类

通过AnnotationConfigApplicationContext或者其web变异体AnnotationConfigWebApplicationContext来注入@Configuration类,如下所示:

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(AppConfig.class);
ctx.refresh();
MyBean myBean = ctx.getBean(MyBean.class);
// use myBean ...

也可以通过xml文件注入配置类如下所示:

<beans>
  <context:annotation-config/>
  <bean class="com.acme.AppConfig"/>
</beans>

上面实例的<context:annotation-config/>标签是必须的,这样才能够使ConfigurationClassPostProcessor和其他注解管理的后置处理器生效以处理@Configuration classes。关于<context:annotation-config/>更多信息可以参考博文SpringMVC中context:annotation-config与mvc:annotation-driven和context:component-scan区别详解。

③ 组件扫描


因为该注解被@Component进行了元注解,故而声明@Configuration注解的类也可以被作为一个普通组件进行扫描如<context:component-scan/>,也可以像 普通的组件一样使用@Autowired或者@Inject。特别是,如果存在单个构造函数,则将透明地为该构造函数应用自动装配语义:

@Configuration
public class AppConfig {
    private final SomeBean someBean;
    public AppConfig(SomeBean someBean) {
        this.someBean = someBean;
    }
    // @Bean definition using "SomeBean"
}















目录
相关文章
|
5天前
|
缓存 Java Sentinel
Springboot 中使用 Redisson+AOP+自定义注解 实现访问限流与黑名单拦截
Springboot 中使用 Redisson+AOP+自定义注解 实现访问限流与黑名单拦截
|
5天前
|
运维 Java 程序员
Spring5深入浅出篇:基于注解实现的AOP
# Spring5 AOP 深入理解:注解实现 本文介绍了基于注解的AOP编程步骤,包括原始对象、额外功能、切点和组装切面。步骤1-3旨在构建切面,与传统AOP相似。示例代码展示了如何使用`@Around`定义切面和执行逻辑。配置中,通过`@Aspect`和`@Around`注解定义切点,并在Spring配置中启用AOP自动代理。 进一步讨论了切点复用,避免重复代码以提高代码维护性。通过`@Pointcut`定义通用切点表达式,然后在多个通知中引用。此外,解释了AOP底层实现的两种动态代理方式:JDK动态代理和Cglib字节码增强,默认使用JDK,可通过配置切换到Cglib
|
3天前
|
Java
Springboot 使用自定义注解结合AOP方式校验接口参数
Springboot 使用自定义注解结合AOP方式校验接口参数
Springboot 使用自定义注解结合AOP方式校验接口参数
|
5天前
|
存储 缓存 Java
【JavaEE】Spring中注解的方式去获取Bean对象
【JavaEE】Spring中注解的方式去获取Bean对象
3 0
|
5天前
|
存储 Java 对象存储
【JavaEE】Spring中注解的方式去存储Bean对象
【JavaEE】Spring中注解的方式去存储Bean对象
8 0
|
5天前
|
JSON 前端开发 Java
【JAVA进阶篇教学】第七篇:Spring中常用注解
【JAVA进阶篇教学】第七篇:Spring中常用注解
|
5天前
|
JavaScript Java 开发者
Spring Boot中的@Lazy注解:概念及实战应用
【4月更文挑战第7天】在Spring Framework中,@Lazy注解是一个非常有用的特性,它允许开发者控制Spring容器的bean初始化时机。本文将详细介绍@Lazy注解的概念,并通过一个实际的例子展示如何在Spring Boot应用中使用它。
21 2
|
5天前
|
前端开发 Java
SpringBoot之自定义注解参数校验
SpringBoot之自定义注解参数校验
19 2
|
5天前
|
Java Spring
springboot自带的@Scheduled注解开启定时任务
springboot自带的@Scheduled注解开启定时任务
|
5天前
|
XML JSON Java
【SpringBoot】springboot常用注解
【SpringBoot】springboot常用注解