Java 注解

一、注解的概念

注解(Annotation),也叫元数据(Metadata),是 Java5 的新特性,JDK5引入了 Metadata 很容易的就能够调用 Annotations。注解与类、接口、枚举在同一个层次,并可以应用于包、类型、构造方法、方法、成员变量、参数、本地变量的声明中,用来对这些元素进行说明注释。

二、注解的语法与定义形式

  1. 以 @interface 关键字定义
  2. 注解包含成员,成员以无参数的方法的形式被声明。其方法名和返回值定义了该成员的名字和类型。
  3. 成员赋值是通过 @Annotation(name=value) 的形式。
  4. 注解需要标明注解的生命周期,注解的修饰目标等信息,这些信息是通过元注解实现。
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = { ElementType.ANNOTATION_TYPE } )
public @interface Target {
    ElementType[] value();
}

三、注解的分类

3.1 元注解

meta-annotation。

负责注解其他注解的注解。JDK 1.5 及以后版本定义了 4 个标准的元注解类型:

  1. @Documented

    标记注解,用于描述其它类型的注解应该被作为被标注的程序成员的公共API,因此可以被例如 javadoc 此类的工具文档化。

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Documented {
    }
  2. @Inherited

    标记注解,允许子类继承父类的注解

    @Inherited
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Inherited {
    }
  3. @Retention

    指注解被保留的时间长短,标明注解的生命周期。

    public enum RetentionPolicy {
        /**
    * 注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃.
    * 这意味着:Annotation仅存在于编译器处理期间,编译器处理完之后,该Annotation就没用了
    */
    SOURCE,
    /**
    * 注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期.
    */
    CLASS,
    /**
    * 注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在,
    * 保存到class对象中,可以通过反射来获取
    */
    RUNTIME
    }
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Retention {
    RetentionPolicy value();
    }
  4. @Target

    标明注解的修饰目标。

    // ElementType取值
    public enum ElementType {
    /* 类、接口(包括注解类型)或枚举 */
    TYPE,
    /* field属性,也包括enum常量使用的注解 */
    FIELD,
    /* 方法 */
    METHOD,
    /* 参数 */
    PARAMETER,
    /* 构造函数 */
    CONSTRUCTOR,
    /* 局部变量 */
    LOCAL_VARIABLE,
    /* 注解上使用的元注解 */
    ANNOTATION_TYPE,
    /* 包 */
    PACKAGE
    }

3.2 XStream

  1. @XStreamAlias()

    给类取别名。等同于 stream.alias("student", Student.class);

    @XStreamAlias("student")  // define class level alias
    class Student { 
    }

    给属性取别名。等同于 stream.aliasField("name", Student.class, "studentName");

    class Student {
        @XStreamAlias("name")   // define field level alias
    @XStreamAsAttribute // define field as attribute
    private String studentName;
    }
  2. @XStreamImplicit

    隐藏集合类节点。等同于 stream.addImplicitCollection(Student.class, "notes");

    class Student {
        @XStreamImplicit  // define list as an implicit collection
    private List<Note> notes = new ArrayList<Note>();
    }

3.3 Hibernate

  1. @Entity

    映射实体类。将一个类声明为一个实体 bean,映射到指定的数据库表。

    必须使用。

    @Entity(name = "tableName")
    public class Student {
    }
    • name - 可选,对应数据库中的一个表。若表名与实体类名相同,则可以省略。
  2. @Table

    映射数据库表。通常和 @Entity 配合使用,只能标注在实体的 class 定义上,表示实体对应的数据库表的信息。

    可选使用。

    @Entity(name = "tableName")
    @Table(name = "t_student", catalog = "", schema = "")
    public class Student {
    }
    • name - 可选,表示表的名称,默认的表名和实体名称一致,只有在不一致的情况下才需要指定表名
    • catalog - 可选,表示 Catalog 名称,默认为 Catalog("")
    • schema - 可选 , 表示 Schema 名称 , 默认为Schema("")
  3. @Id

    映射生成主键。定义了映射到数据库表的主键的属性,一个实体只能有一个属性被映射为主键,置于 getXxx() 前。

  4. @GeneratedValue

    定义主键生成策略

  5. @SequenceGenerator

    声明了一个数据库序列

  6. @Version

    定义乐观锁

  7. @Basic

    声明属性的存取策略

  8. @Column

    映射表的列

  9. @Transient

    定义暂态属性

    Hibernate的注解方法的使用

3.4 校验

  1. @Valid

    用于验证注解是否符合要求,直接加在变量之前,在变量中添加验证信息的要求,当不符合要求时就会在方法中返回 message 的错误提示信息。

    @RestController
    @RequestMapping("/user")
    public class UserController {
    @PostMapping
    public User create (@Valid @RequestBody User user) {
    user.setId("1");
    return user;
    }
    }
  2. @NotBlank

    public class User {
        private String id;  
    @NotBlank(message = "密码不能为空")
    private String password;
    }

    当密码为空时,@Valid 验证失败,会将 message 字段的信息返回。

    其他验证信息的要求:

    限制 说明
    @Null 限制只能为 null
    @NotNull 限制必须不为 null
    @AssertFalse 限制必须为 false
    @AssertTrue 限制必须为 true
    @DecimalMax(value) 限制必须为一个不大于指定值的数字
    @DecimalMin(value) 限制必须为一个不小于指定值的数字
    @Digits(integer, fraction) 限制必须为一个小数,且整数部分的位数不能超过 integer,小数部分的位数不能超过fraction
    @Future 限制必须是一个将来的日期
    @Past 限制必须是一个过去的日期
    @Max(value) 限制必须为一个不大于指定值的数字
    @Min(value) 限制必须为一个不小于指定值的数字
    @Pattern(value) 限制必须符合指定的正则表达式
    @Size(max,min) 限制字符长度必须在 min 到 max 之间
    @Past 验证注解的元素值(日期类型)比当前时间早
    @NotEmpty 验证注解的元素值不为 null 且不为空(字符串长度不为 0、集合大小不为 0)
    @NotBlank 验证注解的元素值不为空(不为null、去除首位空格后长度为0),不同于 @NotEmpty,@NotBlank 只应用于字符串且在比较时会去除字符串的空格
    @Email 验证注解的元素值是 Email,也可以通过正则表达式和 flag 指定自定义的 email 格式
  3. 自定义验证信息

    @Constraint(validatedBy = {MyConstraintValidator.class})
    @Target({ELementtype.METHOD, ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyConstraint {
    String message();
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
    }

    校验器:

    public class MyConstraintValidator implements ConstraintValidator<MyConstraint, Object> {
        @Autowired
    private UserService userService;
    @Override
    public void initialie(@MyConstraint constarintAnnotation) {
    System.out.println("my validator init");
    }
    @Override
    public boolean isValid(Object value, ConstraintValidatorContext context) {
    userService.getUserByUsername("seina");
    System.out.println("valid");
    return false;
    }
    }

3.5 Spring

  1. @Controller

    控制器(注入服务)。用于标注控制层,相当于 struts 中的 action 层。

  2. @Service

    服务(注入 dao)。用于标注服务层,主要用来进行业务的逻辑处理。

  3. @Repository

    实现 dao 访问。用于标注数据访问层,也可以说用于标注数据访问组件,即 DAO 组件。

  4. @Component

    把普通 pojo 实例化到 spring 容器中,相当于配置文件中的 <bean id="" class=""/>。泛指各种组件,就是说当类不属于各种归类的时候(不属于 @Controller、@Service等时),就可以使用 @Component 来标注这个类。

  5. @Configuration

    标识类可以使用 Spring IoC 容器作为 bean 定义的来源,配合 @Bean 使用。使用这两个注解就可以创建一个简单的 spring 配置类,可以用来替代相应的 xml 配置文件。

    <beans> 
        <bean id = "car" class="com.test.Car"> 
    <property name="wheel" ref = "wheel"></property>
    </bean>
    <bean id = "wheel" class="com.test.Wheel"></bean>
    </beans>
    @Configuration 
    public class Conf { 
    @Bean
    public Car car() {
    Car car = new Car();
    car.setWheel(wheel());
    return car;
    }
    @Bean
    public Wheel wheel() {
    return new Wheel();
    }
    }
  6. @Bean

    告诉 Spring,一个带有 @Bean 的注解方法将返回一个对象,该对象应该被注册为在 Spring 应用程序上下文中的 bean。

  7. @EnableAspectJAutoProxy

    开启 AOP。

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Import(AspectJAutoProxyRegistrar.class)
    public @interface EnableAspectJAutoProxy {
    /**
    * Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
    * to standard Java interface-based proxies. The default is {@code false}.
    */
    boolean proxyTargetClass() default false;
    /**
    * Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
    * for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
    * Off by default, i.e. no guarantees that {@code AopContext} access will work.
    * @since 4.3.1
    */
    boolean exposeProxy() default false;
    }

    proxyTargetClass 控制 aop 的具体实现方式。为 true 的话使用 cglib,为 false 的话使用 java 的 Proxy。

    exposeProxy 控制代理的暴露方式,解决内部调用不能使用代理的场景。

    spring @EnableAspectJAutoProxy背后的那些事(spring AOP源码赏析)

  8. @EnableTransactionManagement

    开启 spring 事务管理。

  9. @EnableCaching

    开启 spring 缓存。

  10. @EnableWebMvc

    开启 webMvc。

  11. @Resource 与 @Autowired 用法区别

    共同点:

    • @Resource 和 @Autowired 都可以作为注入属性的修饰,在接口仅有单一实现类时,两个注解的修饰效果相同,可以互相替换,不影响使用。

    不同点:

    • @Resource 是 Java 的注解,@Resource 有两个属性是比较重要的,name 和 type;Spring 将 @Resource 注解的 name 属性解析为 bean的名字,而 type 属性则解析为 bean 的类型。如果一个 bean 的name 和另外一个 bean 的 property 相同,就自动装配;如果一个bean 的数据类型和另外一个 bean 的 property 属性的数据类型兼容,就自动装配。
    • @Autowired 是 spring 的注解,是 spring2.5 版本引入的,@Autowired 只根据 type 进行注入,不会去匹配 name。如果涉及到 type 无法辨别注入对象时,那需要依赖 @Qualifier 或 @Primary 注解一起来修饰。

    @Resource与@Autowired用法区别

3.6 SpringBoot

  1. @ServletComponentScan

    在 SpringBootApplication 上使用 @ServletComponentScan 注解后,Servlet、Filter、Listener可以直接通过 @WebServlet、@WebFilter、@WebListener 注解自动注册,无需其他代码。

    @SpringBootApplication
    @ServletComponentScan
    public class Application {
    public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
    }
    }
    @WebServlet(name="TestServlet", urlPatterns="/test")
    public class TestServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException {
    }
    }
  2. @ComponentScan

    Spring是一个依赖注入(dependency injection)框架。所有的内容都是关于 bean 的定义及其依赖关系。

    ComponentScan 要做的就是告诉 Spring 从哪里找到 bean。

    @ComponentScan({ "com.a.aa", "com.a.bb" })
    @ComponentScan(basePackages = { "com.a.aa", "com.a.bb" })
    @ComponentScan("com.a")
    @ComponentScan(value = "com.a")
    @ComponentScan(basePackages = {"com.a"})
    @ComponentScan(basePackageClasses=Test.class)
    • SpringBoot 在写启动类的时候如果不使用@ComponentScan 指明对象扫描范围,默认指扫描当前启动类所在的包里的对象
    • 如果当前启动类没有包,则在启动时会报错:Your ApplicationContext is unlikely to start due to a @ComponentScan of the default package 错误,因为启动类不能直接放在 main/java 文件夹下,必须要建一个包把它放进去或者使用 @ComponentScan 指明要扫描的包;
    • 如果有一些 bean 所在的包,不在主类的包及其下级包,那么你需要手动加上 @ComponentScan 注解并指定那个bean 所在的包。
    <context:component-scan base-package="com.a.aa, com.a.bb" />
    
  3. @SpringBootApplication

    @SpringBootApplication = (默认属性)@Configuration + @EnableAutoConfiguration + @ComponentScan

    @SpringBootApplication 
    public class ApplicationMain { 
    public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
    }
    }
  4. @EnableAutoConfiguration

    能够自动配置 spring 的上下文,试图猜测和配置你想要的 bean 类,通常会自动根据你的类路径和你的 bean 定义自动配置。

原文地址:https://www.cnblogs.com/dins/p/java-annotation.html