【面试必问】Java经常使用注解及原理

注解是什么?

Java 注解是Java5添加的,用于为 Java 代码提供元数据。做为元数据,注解不直接影响你的代码执行,但也有一些类型的注解能够用于这一目的。java

注解是一种元数据,能够将它理解为一种特殊的注释,它为咱们在代码中添加信息提供了一种形式化的方法,它用于帮助咱们更快捷的写代码。spring

简单来讲,注解主要有四个部分的做用编程

  • 生成文档:即将元数据生成为Javadoc文档;
  • 编译检查:编译器在编译阶段会对代码进行检查,例如@override注解会提示编译器查看其是否重写了父类的方法;
  • 编译动态处理:主要是用做动态生成代码,例如一些帮助类、方法,经过注解实现自动生成;
  • 运行动态处理:典型的例子是使用反射来注入实例;

Java提供了三种注解:自带的标准注解(见下)、元注解(指修饰注解的注解,是最基准的注解)、自定义注解(用户能够自定义注解,如@Retention、@Target、@Inherited、@Documented、@Repeatable 等)markdown

在实际的项目开发中见到的注解通常是来自Java自带的注解、元注解、Spring等框架的注解(如@Resource、@Bean等,lombok的@data、@Slf4j等)。框架

常见注解

一些Java及Spring等常见的注解以下:ide

  1. @Deprecated – 所标注内容再也不被建议使用;
  2. @Override – 只能标注方法,表示该方法覆盖父类中的方法;
  3. @SuppressWarnings – 所标注内容产生的警告,编译器会对这些警告保持静默;
  4. @interface用于定义一个注解
  5. @Documented --将所标注内容包含到javadoc中;
  6. @Inherited – 只能被用来标注“Annotation类型”,它所标注的Annotation具备继承性,跟类的继承形式赞成;
  7. @Retention – 只能被用来标注“Annotation类型”,并且它被用来指定Annotation的RetentionPolicy属性,它表示注解存在阶段是保留在源码(编译期),字节码(类加载)或者运行期(JVM中运行),关于注解声明周期的概念能够看看下图:

img

通常来讲,若是retention设置为source和class,那么就须要被继承并实现,由于加载到JVM时,这二者的注解就被抹除了,也就失去了效果。(lombok的@Data注解就是在这个过程当中,加入了get/set方法)函数

  1. @Target – 只能被用来标注“Annotation类型”,并且它被用来指定Annotation的ElementType属性,它是经过枚举类类来表示注解的做用范围,如做用于TYPE(接口、类、枚举、注解)、FIELD(字段、枚举常量)、METHOD(方法)、PARAMETER(方法参数)、ANNOTATION_TYPE(注解)、CONSTRUCTOR(构造函数)、LOCAL_VARIABLE(局部变量)、PACKAGE(包)等
  2. @Repeatable-代表该注解所修饰的注解能够同时做用一个对象屡次,但每次的含义能够不一样;

下面是Spring的一些重要注解:oop

  1. @Configuration

标注在类上,至关于把该类做为spring的xml配置文件中的,用来配置spring容器(上下文)。spa

  1. @Bean

标注在方法上(返回某个实例的方法),等价于spring的xml配置文件中的,做用为:注册bean对象。@Bean注解默认做用域为单例singleton做用域。.net

  1. @ComponentScan

标注在类上,用于对Component进行扫描;

  1. @WishlyConfiguration

组合注解,能够替代注解2-3;

上述1-4,是配置类的相关注解;

  1. @Component

通常是在类上,代表其是一个组件,告知Spring该类会建立Bean;

  1. @Repository

代表该对象是数据访问层(DAO)使用的;

  1. @Service

代表该对象是业务逻辑层(SERVICE)使用的;

  1. @Controller

这是控制器的声明,代表该对象在展示层使用;

以上5-8都是有关声明bean的注解;

  1. @Resource:自动依赖注入

  2. @Autowired:自动依赖注入;

注:二者的用法很类似,都是用做依赖注入,可是Resource是默认按照Name注入,而Autowired是按照Type注入的

  1. @Inject:手动依赖注入;

这里补充一下Spring启动容器与组件之间的具体过程:

  • 在启动spring的时候,首先要启动容器
  • 启动spring容器时,会默认寻找容器扫描范围内的可加载bean,而后查找哪些bean上的属性和方法上有@Resource注解
  • 找到@Resource注解后,判断@Resource注解括号中的name属性是否为空,若是为空:看spring容器中的bean的id与@Resource要注解的那个变量属性名是否相同,如相同,匹配成功;若是不相同,看spring容器中bean的id对应的类型是否与@Resource要注解的那个变量属性对应的类型是否相等,若相等,匹配成功,若不相等,匹配失败;
  • 若是@Resource注解括号中的name属性不为空,看name的属性值和容器中的bean的id名是否相等,如相等,则匹配成功;如不相等,则匹配失败。

其余一些注解以下:

  1. @profile

指定类或方法在特定的 Profile 环境生效,任何@Component或@Configuration注解的类均可以使用@Profile注解。在使用DI来依赖注入的时候,可以根据@profile标明的环境,将注入符合当前运行环境的相应的bean。

  1. @Data :注在类上,提供类的get、set、equals、hashCode、canEqual、toString方法

  2. @AllArgsConstructor :注在类上,提供类的全参构造

  3. @NoArgsConstructor :注在类上,提供类的无参构造

  4. @Setter : 注在属性上,提供 set 方法;

  5. @Getter :注在属性上,提供 get 方法

  6. @EqualsAndHashCode :注在类上,提供对应的 equals 和 hashCode 方法;

  7. @Log4j/@Slf4j : 注在类上,提供对应的 Logger 对象,变量名为 log

  8. @After: 代表该方法在其余方法执行以后执行;

  9. @Before: 代表该方法在其余方法执行以前执行;

  10. @Around: 代表该方法在其余方法执行以前和以后都执行;

自定义注解?

上述的这些常见的注解能够减小代码量,使得代码结构更加简洁和清晰,可是光用这些注解是不够的,有时在业务场景须要或者保持代码结构清晰等状况下,就须要使用自定义注解了。

举个例子,通常项目中都要设置日志系统,或是监控告警系统,就须要上传或者提供一些QPS、RT等,若是将这些代码直接写在项目代码中,那么就会使得项目代码被污染,并且,在项目中会大量存在这些重复代码,这个时候自定义注解就有用咯!

如何解?那就是利用APO切面编程以及反射的思想!将AOP相关的配置信息写入注解里,就能够实现优雅地解决这个问题了。

反射是为了获取Java运行时的相关信息,AOP切面编程是为了可以在Spring的AOP中中直接判断某一个方法是否带有自定义的注解——若是有,那么自定义注解就会将相关的监控逻辑加载在相关的方法上。

有关这个案例,能够详细看一下这篇博客结尾的代码

参考资料

常见注解

Java自定义注解

Java3y写的注解,很棒

相关文章
相关标签/搜索