美文网首页Java
Java注解(Annotation)中-示例

Java注解(Annotation)中-示例

作者: 丿星纟彖彳亍 | 来源:发表于2020-09-21 17:40 被阅读0次

    1、JDK自带(java.lang)

    "@Deprecated 和 @Override" 类似,"@Documented, @Inherited, @Retention, @Target" 类似。

    1.1 @ Override

    若某个方法被 @Override 的标注,则意味着该方法会覆盖父类中的同名方法。如果有方法被 @Override 标示,但父类中却没有"被 @Override 标注"的同名方法,则编译器会报错。

    public class OverrideTest {
        /**
         * toString() 在java.lang.Object中定义;
         * 因此,这里用 @Override 标注是对的。
         */
        @Override
        public String toString(){
            return "Override toString";
        }
    
        /**
         * getString() 没有在OverrideTest的任何父类中定义;
         * 但是,这里却用 @Override 标注,因此会产生编译错误!
         * 将 getString() 上面的 @Override注释掉",即可解决该错误。
         */
        @Override
        public String getString(){
            return "get toString";
        }
    }
    

    1.2 @Deprecated

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Deprecated {
    /*
    说明:
    (01) @interface -- 它的用来修饰 Deprecated,意味着 Deprecated 实现了 java.lang.annotation.Annotation 接口;即 Deprecated 就是一个注解。 (02) @Documented -- 它的作用是说明该注解能出现在 javadoc 中。
    (03) @Retention(RetentionPolicy.RUNTIME) -- 它的作用是指定 Deprecated 的策略是 RetentionPolicy.RUNTIME。这就意味着,编译器会将Deprecated 的信息保留在 .class 文件中,并且能被虚拟机读取。
    (04) @Deprecated 所标注内容,不再被建议使用。
    */
    }
    

    比如,若某个方法被@Deprecated标注,则该方法不在便建议使用,如果再用或者重写该方法,编译器会有相应的警告信息:

    public class DeprecatedTest {
        // @Deprecated 修饰 getString1(),表示 它是建议不被使用的函数
        @Deprecated
        private static void getString1(){
            System.out.println("Deprecated Method");
        }
        
        private static void getString2(){
            System.out.println("Normal Method");
        }
        
        // Date是日期/时间类。java已经不建议使用该类了
        private static void testDate() {
            Date date = new Date(113, 8, 25);
            System.out.println(date.getYear());
        }
        // Calendar是日期/时间类。java建议使用Calendar取代Date表示"日期/时间"
        private static void testCalendar() {
            Calendar cal = Calendar.getInstance();
            System.out.println(cal.get(Calendar.YEAR));
        }
        
        public static void main(String[] args) {
            getString1(); //建议不再使用 getString1(); 
            getString2();//没有被 @Deprecated 标注,它的显示正常;
            testDate(); //java 已经建议不再使用;
            testCalendar();//调用了 Calendar 的 API 来操作日期/时间,java 建议用 Calendar 取代 Date。因此,操作 Calendar 不会产生 warning。
        }
    }
    

    1.3 @Inherited

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Inherited {
    /*
    说明:
    (01) @interface -- 它的用来修饰 Inherited,意味着 Inherited 实现了 java.lang.annotation.Annotation 接口;即 Inherited 就是一个注解。
    (02) @Documented -- 它的作用是说明该注解能出现在 javadoc 中。
    (03) @Retention(RetentionPolicy.RUNTIME) -- 它的作用是指定 Inherited 的策略是 RetentionPolicy.RUNTIME。这就意味着,编译器会将 Inherited 的信息保留在 .class 文件中,并且能被虚拟机读取。
    (04) @Target(ElementType.ANNOTATION_TYPE) -- 它的作用是指定 Inherited 的类型是 ANNOTATION_TYPE。这就意味着,@Inherited 只能被用来标注 "Annotation 类型"。
    (05) @Inherited 的含义是,它所标注的Annotation将具有继承性。
    */
    }
    

    假设,我们定义了某个 Annotaion,它的名称是 MyAnnotation,并且 MyAnnotation 被标注为 @Inherited。现在,某个类 Base 使用了MyAnnotation,则 Base 具有了"具有了注解 MyAnnotation";现在,Sub 继承了 Base,由于 MyAnnotation 是 @Inherited的(具有继承性),所以,Sub 也 "具有了注解 MyAnnotation"。

    /**
     * 自定义的Annotation。
     */
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    @interface Inheritable {
    }
    
    @Inheritable
    class InheritableFather {
        public InheritableFather() {
            // InheritableBase是否具有 Inheritable Annotation
           System.out.println("InheritableFather:"+InheritableFather.class.isAnnotationPresent(Inheritable.class));
        }
    }
    
    /**
     * InheritableSon 类只是继承于 InheritableFather,
     */
    public class InheritableSon extends InheritableFather {
        public InheritableSon() {
            super();    // 调用父类的构造函数
            // InheritableSon类是否具有 Inheritable Annotation
            System.out.println("InheritableSon:"+InheritableSon.class.isAnnotationPresent(Inheritable.class));
        }
        
        public static void main(String[] args)  {
            InheritableSon is = new InheritableSon();
        }
    }
    

    运行结果:

    InheritableFather:true
    InheritableSon:true
    

    现在,我们对 InheritableSon.java 进行修改:注释掉 "Inheritable 的 @Inherited 注解"。

    InheritableFather:true
    InheritableSon:false
    

    对比上面的两个结果,我们发现:当注解 Inheritable 被 @Inherited 标注时,它具有继承性。否则,没有继承性。

    1.4 @SuppressWarnings

    /*
    说明:
    (01) @interface -- 它的用来修饰 SuppressWarnings,意味着 SuppressWarnings 实现了 java.lang.annotation.Annotation 接口;即 SuppressWarnings 就是一个注解。
    (02) @Retention(RetentionPolicy.SOURCE) -- 它的作用是指定 SuppressWarnings 的策略是 RetentionPolicy.SOURCE。这就意味着,SuppressWarnings 信息仅存在于编译器处理期间,编译器处理完之后 SuppressWarnings 就没有作用了。
    (03) @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) -- 它的作用是指定 SuppressWarnings 的类型同时包括TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE。
    TYPE 意味着,它能标注"类、接口(包括注释类型)或枚举声明"。
    FIELD 意味着,它能标注"字段声明"。
    METHOD 意味着,它能标注"方法"。
    PARAMETER 意味着,它能标注"参数"。
    CONSTRUCTOR 意味着,它能标注"构造方法"。
    LOCAL_VARIABLE 意味着,它能标注"局部变量"。
    (04) String[] value(); 意味着,SuppressWarnings 能指定参数
    (05) SuppressWarnings 的作用是,让编译器对"它所标注的内容"的某些警告保持静默。
    */
    @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
    @Retention(RetentionPolicy.SOURCE)
    public @interface SuppressWarnings {
        String[] value();
    }
    

    例如,"@SuppressWarnings(value={"deprecation", "unchecked"})" 表示对"它所标注的内容"中的 "SuppressWarnings 不再建议使用警告"和"未检查的转换时的警告"保持沉默。示例如下:

    /*
    SuppressWarnings 常用的关键字的表格
    deprecation  -- 使用了不赞成使用的类或方法时的警告
    unchecked    -- 执行了未检查的转换时的警告,例如当使用集合时没有用泛型 (Generics) 来指定集合保存的类型。
    fallthrough  -- 当 Switch 程序块直接通往下一种情况而没有 Break 时的警告。
    path         -- 在类路径、源文件路径等中有不存在的路径时的警告。
    serial       -- 当在可序列化的类上缺少 serialVersionUID 定义时的警告。
    finally      -- 任何 finally 子句不能正常完成时的警告。
    all          -- 关于以上所有情况的警告。
    boxing      -- 禁止与装箱/拆箱操作相关的警告
    cast        -- 强制转换以抑制与强制转换操作相关的警告
    dep-ann     -- 用于抑制相对于已弃用注释的警告
    hiding      -- 隐藏以抑制相对于隐藏变量的本地警告
    incomplete-switch -- 在switch语句(enum案例)中,incomplete-switch用来抑制相对于丢失条目的警告
    javadoc     -- 禁止与javadoc警告相关的警告
    nls         -- 使用nls来抑制相对于非nls字符串的警告。
    null        -- 空值来抑制相对于空值分析的警告
    rawtypes    -- 拒绝与使用原始类型相关的警告
    resource    -- 用于抑制与使用类型为Closeable的资源相关的警告的资源
    restriction --限制禁止与使用不鼓励或禁止引用相关的警告
    static-access   --静态访问,抑制相对于不正确的静态访问的警告
    static-method   --静态方法,用于抑制相对于可以声明为静态的方法的警告
    super       -- 超级-来抑制相对于在没有超级调用的情况下重写方法的警告
    synthetic-access-- 用于抑制相对于内部类的未优化访问的警告的合成访问
    sync-override   -- 在覆盖同步方法时,由于缺少同步而取消警告
    unchecked       -- 未选中以抑制与未选中操作相关的警告
    unqualified-field-access-- 不限定字段访问来抑制与字段访问不限定相关的警告
    unused      -- 不常用来抑制与未使用代码和死代码相关的警告
    */
    public class SuppressWarningTest {
    //没有使用 @SuppressWarnings(value={"deprecation"}) , 而 Date 属于 java 不再建议使用的类。因此,调用 Date 的 API 时,会产生警告。
        //@SuppressWarnings(value={"deprecation"})
        public static void doSomething() {
            Date date = new Date(113, 8, 26);
            System.out.println(date);
        }
    
        public static void main(String[] args) {
            doSomething();
        }
    }
    

    1.5 @SafeVarargs

    堆污染警告。
    出现:使用泛型+可变参数的时候就会出现堆污染警告。

    @SafeVarargs
        public static<T> T useVarargs(T... args){
            return args.length > 0?args[0]:null;
        }
        @Test
        public void testSafeVarargs(){
            System.out.println(useVarargs(Arrays.asList("s1","s2")));
        }
    

    1.6 @FunctionalInterface

    在Java SE 8中引入的 ,申明某个接口是函数式接口(函数式接口是就只含有一个抽象方法的接口)。加上该注解,当你写的接口不符合函数式接口定义的时候,编译器会报错。该注解只是提醒编译器去检查该接口是否仅包含一个抽象方法。

    @FunctionalInterface
        interface GreetingService  {
            void sayMessage(String message);
        }
    //那么就可以使用Lambda表达式来表示该接口的一个实现(注:JAVA 8 之前一般是用匿名类实现的):
    //GreetingService greetService1 = message -> System.out.println("Hello " + message);
    

    2、第三方注解

    2.1 基础注解1(spring-context下org.springframework.stereotype)

    2.1.1 @Component组合注解

    用于标注各个层级的注解,注入到spring容器管理。
    @Controller @Service @Repository @Configuration 都是@Component组合注解,只是区分层级关系:

    • @Controller 标注于控制层
    • @Service 标注于业务层
    • @Repository 标注于dao持久层
    • @Configuration 标注于配置层
    • @Component 泛指组件,当组件不好归类时可用

    2.1.1 @Bean

    @Bean等价于<Bean></Bean>,添加的bean的id为方法名。

    @Configuration
    public class AppConfig {
        //@bean 也可以依赖其他任意数量的bean,如果TransferService 依赖 AccountRepository,我们可以通过方法参数实现这个依赖
        @Bean
        public TransferService transferService(AccountRepository accountRepository) {
            return new TransferServiceImpl(accountRepository);
        }
    }
    

    这个配置就等同于之前在xml里的配置:
    @Configuration可理解为用spring的时候xml里面的<beans>标签
    @Bean可理解为用spring的时候xml里面的<bean>标签

    <beans>
        <bean id="transferService" class="com.acme.TransferServiceImpl"  depends-on="accountRepository"/>
    </beans>
    

    2.2 基础注解2(spring-web下org.springframework.web.bind.annotation)

    2.2.1 @ResponseBody

    被注解的方法返回的结果直接写入 HTTP 响应正文(ResponseBody)中。
    一般在异步获取数据时使用,通常是在使用 @RequestMapping 后,返回值通常解析为跳转路径,加上 @Responsebody 后返回结果不会被解析为跳转路径,而是直接写入HTTP 响应正文中。

    /***********************例子一*******************************/
    @RequestMapping(value="user/login")
    @ResponseBody
    //将ajax(datas)发出的请求写入User对象中,返回json对象响应回去
    public User login(User user) {
        User user = new User();
        user.setUserid(1);
        user.setUsername("MrF");
        user.setStatus("1");    
        return user ;
    }
    /***********************例子二*******************************/
    @Controller 
    public class UserController {
        @GetMapping("/hello") 
        @ResponseBody public String hello() {
            return "hello spring"; 
        } 
    }
    

    2.2.2 @ RequestBody

    将 HTTP 请求正文插入方法中,使用适合的 HttpMessageConverter 将请求体写入某个对象。换句话就是:用于接收前端请求的Json参数,并且封装到对应的JavaBean。

    @RequestMapping(value = "user/login")
    @ResponseBody
    // 将ajax(datas)发出的请求写入User对象中
    public User login(@RequestBody User user) {   
    // 这样就不会再被解析为跳转路径,而是直接将user对象写入 HTTP 响应正文中
        return user;    
    }
    

    提交时, 根据request header Content-Type的值来判断:

    • application/x-www-form-urlencoded -- 可选(GET,POST),必须(PUT)
      GET,POST -- 这种情况的数据@RequestParam,@ModelAttribute也可以处理,当然@RequestBody也能处理
    • multipart/form-data -- 不能处理
      即使用@RequestBody不能处理这种格式的数据
    • 其他格式 -- 必须
      其他格式包括application/json,application/xml等。这些格式的数据,必须使用@RequestBody来处理

    2.2.3 @RequestMapping

    用来处理请求地址映射的注解。

    • @GetMapping = @RequestMapping(method = RequestMethod.GET)
    • @PostMapping = @RequestMapping(method = RequestMethod.POST)
    /**
    RequestMapping注解有六个属性,下面我们把她分成三类进行说明。
    1、value, method
    value: 指定请求的实际地址,指定的地址可以是URI Template 模式(后面将会说明)
    method:指定请求的method类型,GET、POST、PUT、DELETE等
    2、consumes,produces
    consumes: 指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;
    produces: 指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回;
    3、params,headers
    params:指定request中必须包含某些参数值是,才让该方法处理。
    headers:指定request中必须包含某些指定的header值,才能让该方法处理请求。
    */
    //用于类上,可以没有
    @RequestMapping(value = "/controllerDemo")
    public class ControllerDemo {
        // 用于方法上,必须有
        @RequestMapping(value = "/methodDemo")    
        public String methodDemo() {
            return "helloWorld";
        }
    }
    

    2.2.4 @PathVariable、@RequestParam

    用于接受前端url路径参数,通过路径参数作为接口接受的参数,Result风格
    区分:

    • @RequestParam -- URL是这样的:http://host:port/path?参数名=参数值
    • @PathVariable -- URL是这样的:http://host:port/path/参数值
    //访问路径:localhost:8080/hello/1
    @GetMapping("/hello/{id}")
    public String func(@PathVariable String id) {
        return id;
    }
    

    2.2.5 @RequestParam

    用于接受前端提交的参数。

    //访问路径:localhost:8080/hello?name=张三
    @GetMapping("/hello")
    /*
    String  value   name别名
    String  name    请求参数对应的属性
    boolean required    是否必传
    Stirng  defaultValue    默认值
    */
    public String func(@RequestParam(name = "name", required = false, defaultValue = "张三") String name) {
        return "OK";
    }
    

    2.2.6 @RestController

    相当于@ResponseBody + @Controller。

    • Controller中的方法无法返回jsp页面,返回的内容就是Return 里的内容。

    2.3 persistence注解(javax.persistence)

    2.3.1 @Entity,@Table,@Column

    @Entity表明该类是实体类,并且使用默认的orm规则,即class名即数据库表中表名,class字段名即表中的字段名。如果class名和数据库表中名字不一致就用@Table,如果class字段名和表中的字段名不一直就用@Column

    @Column用来标识实体类中属性与数据表中字段的对应关系

    • name:被标注字段在数据库表中所对应字段的名称
    • unique:表示该字段是否为唯一标识,默认为false。也可以使用@Table标记中的@UniqueConstraint。
    • nullable:表示该字段是否可以为null值,默认为true。
    • insertable:表示在使用“INSERT”脚本插入数据时,是否需要插入该字段的值。
    • updatable:表示在使用“UPDATE”脚本插入数据时,是否需要更新该字段的值。insertable和updatable属性一般多用于只读的属性,例如主键和外键等。这些字段的值通常是自动生成的。
    • columnDefinition:表示创建表时,该字段创建的SQL语句,一般用于通过Entity生成表定义时使用。(也就是说,如果DB中表已经建好,该属性没有必要使用。)
    • table:表示当映射多个表时,指定表的表中的字段。默认值为主表的表名。
    • length:表示字段的长度,当字段的类型为varchar时,该属性才有效,默认为255个字符。
    • precision:和scaleprecision属性和scale属性表示精度,当字段类型为double时,precision表示数值的总长度,scale表示小数点所占的位数。

    示例见2.3.2。

    2.3.2 @Id,@Temporal,@GeneratedValue, @Generated

    • @Id表名该字段是主键,如果要开启自增主键就用@GeneratedValue。
    • @Temporal帮Java的Date类型进行格式化,一共有三种注解值:
      -- @Temporal(TemporalType.DATE)— yyyy-MM-dd的 Date类型
      -- @Temporal(TemporalType.TIME)—hh-MM-ss的 Date类型
      -- @Temporal(TemporalType.TIMESTAMP)—yyyy-MM-dd hh:MM:ss”的 Date类型
    • @Generated自动生成:
      -- generated= never 标明此属性值不是从数据库中生成
      -- generated默认值是never
      -- generated= insert 标明此属性值在insert的时候生成,但是不会在随后的 update时重新生成
      -- generated= always 标明此属性值在insert和update时都会被生成
    @Entity
    @Table(name = "batch")
    public class Batch{
    
        @Id
        @GeneratedValue(strategy= GenerationType.AUTO)
        private Integer id;
        
        //在插入的时候自动赋值当前时间
        @Column(insertable = false)
        @Temporal(TemporalType.TIMESTAMP)   
        @Generated(GenerationTime.INSERT)   
        private Date createdTime;
    
        //自动变化更新时间
        @Temporal(TemporalType.TIMESTAMP)
        @Column(insertable = false, updatable = false)
        @Generated(GenerationTime.ALWAYS)
        private Date updatedTime;
        
        //在插入的时候自动赋值1
        @Column(insertable = false ,columnDefinition="Short default 1")
        @Generated(GenerationTime.INSERT)
        private Short status;
    }
    

    2.4 resteasy注解(jaxrs-api下javax.ws.rs)

    resteasy 是java体系中比较成熟的rest框架,也是jax-rs规范的实现之一,dubbox的REST服务框架,就是采用的resteasy实现。

    默认情况下,resteasy使用jackson和jaxb来实现json及xml格式的序列化。应用启动时,会自动扫描带@Provider的包,找到最合适的provider。

    这个可以用来做分布式,可以通过okhttp3协议来进行交互。

    2.4.1 @Path、@POST、@Produces、@Consumes、@Context

    @Path("/td")
    public interface PayIntegrationService {
    
        @Path("/pay")
        @POST
        @Produces({ ContentType.APPLICATION_JSON_UTF_8, ContentType.TEXT_XML_UTF_8})
        @Consumes({ ContentType.APPLICATION_JSON_UTF_8, ContentType.TEXT_XML_UTF_8})
        public JsonResponse pay(@Context HttpServletRequest request);
    }
    

    2.5 validation注解(validation-api下javax.validation)

    用于前端请求参数校验,@Valid需要配合BindingResult使用,以及配合下面各种校验注解进行使用:

    • @Null 限制只能为null
    • @NotNull 限制必须不为null
    • @AssertFalse 限制必须为false
    • @AssertTrue 限制必须为true
    • @DecimalMax(value) 限制必须为一个不大于指定值的数字
    • @DecimalMin(value) 限制必须为一个不小于指定值的数字
    • @Digits(integer,fraction) 限制必须为一个小数,且整数部分的位数不能超过integer,小数部分的位数不能超过fraction
    • @Future 限制必须是一个将来的日期
    • @Max(value) 限制必须为一个不大于指定值的数字
    • @Min(value) 限制必须为一个不小于指定值的数字
    • @Past 限制必须是一个过去的日期
    • @Pattern(value) 限制必须符合指定的正则表达式
    • @Size(max,min) 限制字符长度必须在min到max之间
    • @Past 验证注解的元素值(日期类型)比当前时间早
    • @NotEmpty 验证注解的元素值不为null且不为空(字符串长度不为0、集合大小不为0)
    • @NotBlank 验证注解的元素值不为空(不为null、去除首位空格后长度为0),不同于@NotEmpty,@NotBlank只应用于字符串且在比较时会去除字符串的空格
    • @Email 验证注解的元素值是Email,也可以通过正则表达式和flag指定自定义的email格式
    /**
     * 接受前端的请求并且根据User实体类注解进行校验
     */
    @PostMapping("/hello/user")
    public String hello(@Valid @RequestBody User user, BindingResult result) {
         if (result.hasErrors()) {
                result.getAllErrors().forEach(System.out::println);
         }
         System.out.println(user);
         return "hello spring";
    }
    @Data
    public class User {
        @NotBlank(message = "用户名不能为空")
        private String username;
    
        @NotBlank(message = "密码名不能为空")
        private String password;
    }
    

    2.6 lombok常用注解

    传送门:lombok安装和基本使用介绍

    2.7 tkMapper注解

    没用过,以后更新。

    2.8 springboot常用注解

    2.8.1 @ConfigurationProperties

    将配置文件中配置的每一个属性的值,映射到这个组件中。

    **
     * @ConfigurationProperties:
     *      prefix = "person":配置文件下面的所有属性和类的属性进行一一映射
     *
     * 只有这个组件是容器中的组件,才能容器提供的@ConfigurationProperties功能;
     *
     */
    @Component
    @ConfigurationProperties(prefix = "person")
    public class Person {
    
        private String lastName;
        private Integer age;
        private Boolean boss;
        private Date birth;
    
        private Map<String,Object> maps;
        private List<Object> lists;
        private Dog dog;
    }
    

    配置文件:

    person:
        lastName: hello
        age: 18
        boss: false
        birth: 2017/12/12
        maps: {k1: v1,k2: 12}
        lists:
          - lisi
          - zhaoliu
        dog:
          name: 小狗
          age: 12
    

    导入配置文件处理器,之后编写配置就有提示了

    <!--导入配置文件处理器,配置文件进行绑定就会有提示-->
    <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-configuration-processor</artifactId>
         <optional>true</optional>
    </dependency>
    

    2.8.2 @MapperScan

    扫描接口,放启动类上面

    //扫描dao接口
    @MapperScan("com.test.dao")
    public class TestApplication {
        public static void main(String[] args) {
            SpringApplication.run(TestApplication.class, args);
        }
    }
    

    2.8.3 @ SpringBootApplication

    SpringBootApplication启动时会默认扫描主类当前包及子包,如果需要扫描主类当前包外的其他包就用@SpringBootApplication

    //指定扫描的包
    @SpringBootApplication(scanBasePackages = {"com.test"})
    

    2.9 注入Bean的三个注解

    @Autowired是spring自带的,@Inject是JSR330规范实现的,@Resource是JSR250规范实现的,需要导入不同的包

    @Autowired、@Inject用法基本一样,不同的是@Autowired有一个request属性

    @Autowired、@Inject是默认按照类型匹配的,@Resource是按照名称匹配的

    @Autowired如果需要按照名称匹配需要和@Qualifier一起使用,@Inject和@Name一起使用

    2.9.1 @Inject(javax.inject)

    根据类型进行自动装配的,默认需要配置与变量名一致。如果需要按名称进行装配,则需要配合@Named;
    @Inject可以作用在变量、setter方法、构造函数上

    2.9.2 @Autowired ( org.springframework下sping-beans)

    根据类型进行自动装配的,名称不一样也没事,如果需要按名称进行装配,则需要配合@Qualifier;

    @Autowired有个属性为required,可以配置为false,如果配置为false之后,当没有找到相应bean的时候,系统不会抛错;

    @Autowired可以作用在变量、setter方法、构造函数上。

    2.9.3 @Resource (jdk下rt.jar下的javax.annotation)

    根据名称进行自动装配的,默认需要配置与变量名一致,一般会指定一个name属性。

    @Resource可以作用在变量、setter方法上。

    3、在反射中使用示例

    /**
     * Annotation在反射函数中的使用示例
     */
    @Retention(RetentionPolicy.RUNTIME)
    @interface MyAnnotation {
        String[] value() default "unknown";
    }
    
    /**
     * Person类。它会使用MyAnnotation注解。
     */
    class Person {
        
        /**
         * empty()方法同时被 "@Deprecated" 和 "@MyAnnotation(value={"a","b"})"所标注 
         * (01) @Deprecated,意味着empty()方法,不再被建议使用
         * (02) @MyAnnotation, 意味着empty() 方法对应的MyAnnotation的value值是默认值"unknown"
         */
        @MyAnnotation
        @Deprecated
        public void empty(){
            System.out.println("\nempty");
        }
        
        /**
         * sombody() 被 @MyAnnotation(value={"girl","boy"}) 所标注,
         * @MyAnnotation(value={"girl","boy"}), 意味着MyAnnotation的value值是{"girl","boy"}
         */
        @MyAnnotation(value={"girl","boy"})
        public void somebody(String name, int age){
            System.out.println("\nsomebody: "+name+", "+age);
        }
    }
    
    public class AnnotationTest {
        public static void main(String[] args) throws Exception {
            // 新建Person
            Person person = new Person();
            // 获取Person的Class实例
            Class<Person> c = Person.class;
            // 获取 somebody() 方法的Method实例
            Method mSomebody = c.getMethod("somebody", new Class[]{String.class, int.class});
            // 执行该方法
            mSomebody.invoke(person, new Object[]{"lily", 18});
            iteratorAnnotations(mSomebody);
            
    
            // 获取 somebody() 方法的Method实例
            Method mEmpty = c.getMethod("empty", new Class[]{});
            // 执行该方法
            mEmpty.invoke(person, new Object[]{});        
            iteratorAnnotations(mEmpty);
        }
        
        public static void iteratorAnnotations(Method method) {
    
            // 判断 somebody() 方法是否包含MyAnnotation注解
            if(method.isAnnotationPresent(MyAnnotation.class)){
                // 获取该方法的MyAnnotation注解实例
                MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
                // 获取 myAnnotation的值,并打印出来
                String[] values = myAnnotation.value();
                for (String str:values)
                    System.out.printf(str+", ");
                System.out.println();
            }
            
            // 获取方法上的所有注解,并打印出来
            Annotation[] annotations = method.getAnnotations();
            for(Annotation annotation : annotations){
                System.out.println(annotation);
            }
        }
    }
    

    运行结果:

    somebody: lily, 18
    girl, boy, 
    @cn.bcsoft.annotation.MyAnnotation(value=[girl, boy])
    
    empty
    unknown, 
    @cn.bcsoft.annotation.MyAnnotation(value=[unknown])
    @java.lang.Deprecated()
    

    参考文档:

    相关文章

      网友评论

        本文标题:Java注解(Annotation)中-示例

        本文链接:https://www.haomeiwen.com/subject/xnovyktx.html