美文网首页JAVAJava基础
Java原生注解和Spring注解的说明

Java原生注解和Spring注解的说明

作者: 花神子 | 来源:发表于2019-09-16 11:25 被阅读0次

    注解

    • java 原生注解
    • Spring 中的注解

    一 Java原生注解

    Java注解是在JDK1.5以后引入的新特性!

    • 有利于代码的解藕、整洁,提升开发的效率!通俗来讲,注解就是标签,标签的内容可以变动!

    • 注解也是java中的一种数据类型!注解的创建和接口的创建很类似!使用@Interface修饰!

    • JDK本身自带的几种原生注解!也就是我们常说的元注解,原生注解是用于修饰自定义注解!JVM规范规定自定义注解必须使用些原生注解修饰,否则不能正常使用。

    目前为止JDK自带的原生注解有6个:@Retention , @Target , @Inherited , @Documented , @Repeatable , @Native
    其中,@Native、@Repeabable是在JDK1.8之后推出的元注解!

    注解1 @Retention

    @Retention表示注解保留周期,用于提示注解被保留多长时间,

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Retention {
        /**
         * Returns the retention policy.
         * @return the retention policy
         */
        RetentionPolicy value();
    }
    

    有三种取值:

    • RetentionPolicy.SOURCE:保留在源码级别,被编译器抛弃(常见的@Override注解就是此类);
    • RetentionPolicy.CLASS:被编译器保留在编译后的类文件级别,但是被虚拟机丢弃;
    • RetentionPolicy.RUNTIME:保留至运行时,可以被反射读取。
    public enum RetentionPolicy {
        /**
         * Annotations are to be discarded by the compiler.
         */
        SOURCE,
    
        /**
         * Annotations are to be recorded in the class file by the compiler
         * but need not be retained by the VM at run time.  This is the default
         * behavior.
         */
        CLASS,
    
        /**
         * Annotations are to be recorded in the class file by the compiler and
         * retained by the VM at run time, so they may be read reflectively.
         *
         * @see java.lang.reflect.AnnotatedElement
         */
        RUNTIME
    }
    
    

    注解2 @Target

    @Target: 表示注解可以使用在什么地方

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Target {
        /**
         * Returns an array of the kinds of elements an annotation type
         * can be applied to.
         * @return an array of the kinds of elements an annotation type
         * can be applied to
         */
        ElementType[] value();
    }
    

    常见的取值有:

    • ElementType.TYPE : 表示该注解可以被使用在 【类, 接口,注解,enum】上面
    • ElementType.FIELD : 表示该注解可以被使用在 【属性域】上面
    • ElementType.METHOD : 表示该注解可以被使用在 【方法】上面
    • ElementType.PARAMETER : 表示该注解可以被使用在 【参数】上面
    • ElementType.CONSTRUCTOR : 表示该注解可以被使用在 【构造函数】上面
    • E lementType.LOCAL_VARIABLE* : 表示该注解可以被使用在 【局部变量】上面
    • ElementType.ANNOTATION_TYPE : 表示该注解可以被使用在 【 注解类型】上面
    • ElementType.PACKAGE : 表示该注解可以被使用在 【包】上面
    • ElementType.TYPE_PARAMETER : 表示该注解可以被使用在 【输入参数】上面
    • ElementType.TYPE_USE :
    public enum ElementType {
        /** Class, interface (including annotation type), or enum declaration */
        TYPE,
    
        /** Field declaration (includes enum constants) */
        FIELD,
    
        /** Method declaration */
        METHOD,
    
        /** Formal parameter declaration */
        PARAMETER,
    
        /** Constructor declaration */
        CONSTRUCTOR,
    
        /** Local variable declaration */
        LOCAL_VARIABLE,
    
        /** Annotation type declaration */
        ANNOTATION_TYPE,
    
        /** Package declaration */
        PACKAGE,
    
        /**
         * Type parameter declaration
         *
         * @since 1.8
         */
        TYPE_PARAMETER,
    
        /**
         * Use of a type
         *
         * @since 1.8
         */
        TYPE_USE
    }
    

    注解3 @Documented

    注解写入文档 表示注解是否能被 javadoc 处理并保留在文档中。

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

    注解4 @Inherited

    子类继承父类的注解(子类没有任何注解修饰)

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

    注解5 @Repeatable

    @Repeatable : 表示注解的属性可以重复!同一种注解多次使用。可以用来表示某个对象存在多个身份。@Repeatable通俗来讲,就是注解容器!

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Repeatable {
        /**
         * Indicates the <em>containing annotation type</em> for the
         * repeatable annotation type.
         * @return the containing annotation type
         */
        Class<? extends Annotation> value();
    }
    

    JDK提供的其他注解

    @Deprecated:用于标志过时的类、方法和成员变量
    @Override:用于修饰重写的方法
    @SuppressWarnings:用于忽略@Deprecated标志过的警告
    @SafeVarargs:参数安全类型注解,用于提示用户参数安全(JDK1.7)
    @FunctionalInterface:函数式接口注解,用于定义函数式接口(JDK1.8)
    
    

    范例

    @Override的作用是,提示编译器,使用了@Override注解的方法必须override父类或者java.lang.Object中的一个同名方法。
    表示 @Override 只能使用在方法上,保留在源码级别,被编译器处理,然后抛弃掉。

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.SOURCE)
    public @interface Override {
    }
    

    二 Spring中的注解

    注解1 @Autowired

    Spring开发者对@Autowired注解必定是非常了解,其实就是 autowire=byType 就是根据类型的自动注入依赖(基于注解的依赖注入),可以被使用再属性域,方法,构造函数上。

    @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Autowired {
        boolean required() default true;
    }
    

    注解2 @Qualifier

    @Qualifier 就是 autowire=byName, 当@Autowired注解判断多个bean类型相同时,就需要使用 @Qualifier("xxBean") 来指定依赖的bean的id:

    @Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    @Documented
    public @interface Qualifier {
        String value() default "";
    }
    

    注解3 @Resource

    @Resource 属于JSR250标准,它并不是Spring提供的注解,但是Spring对它提供了支持。

    • @Resource的作用相当于@Autowired,只不过@Autowired按byType自动注入,而@Resource默认按 byName自动注入。
    • @Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略。
    • 用于属性域和方法上。使用方式:@Resource(name="xxBean"). 不带参数的 @Resource默认值类名首字母小写。
    @Target({TYPE, FIELD, METHOD})
    @Retention(RUNTIME)
    public @interface Resource {
    
      String name() default "";
      
      String lookup() default "";
      
      Class<?> type() default java.lang.Object.class;  
    
      enum AuthenticationType {
        CONTAINER,
        APPLICATION 
      }
      AuthenticationType authenticationType() default AuthenticationType.CONTAINER;
    
      boolean shareable() default true;
    }
    

    @Resource装配顺序:

    • 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
    • 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
    • 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
    • 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配;

    注解4 @Component @Repository, @Service, @Controller

    @Component 是spring注解,注解后可以被spring框架所扫描并注入到spring容器来进行管理

    @Controller, @Service, @Repository, 这几个注解不同于上面的注解,上面的注解都是将被依赖的bean注入进入,而这几个注解的作用都是生产bean, 这些注解都是注解在类上,将类注解成spring的bean工厂中一个一个的bean。@Controller, @Service, @Repository基本就是语义更加细化的@Component

    • @Component 是通用注解,其他三个注解是这个注解的拓展,并且具有了特定的功能
    • @Repository 注解在持久层中,具有将数据库操作抛出的原生异常翻译转化为spring的持久层异常的功能。注解类作为DAO对象(数据访问对象,Data Access Objects),这些类可以直接对数据库进行操作 有这些分层操作的话,代码之间就实现了松耦合,代码之间的调用也清晰明朗,便于项目的管理;
    • @Controller 层是spring-mvc的注解,bean会被spring-mvc框架所使用。具有将请求进行转发,重定向的功能。不能被其他注解所互换的。@Controller注解类进行前端请求的处理,转发,重定向。包括调用Service层的方法 @Service注解类处理业务逻辑。
    • @Service 层是业务逻辑层注解,这个注解只是标注该类处于业务逻辑层。
      用这些注解对应用进行分层之后,就能将请求处理,义务逻辑处理,数据库操作处理分离出来,为代码解耦,也方便了以后项目的维护和开发.

    注解5 # @RequestParam @RequestBody @PathVariable

    用于参数绑定的注解

    • @PathVariable : 处理requet uri 部分(这里指uri template中variable,不含queryString部分)。当使用@RequestMapping URI template 样式映射时, 即 someUrl/{paramId}, 这时的paramId可通过 @Pathvariable注解绑定它传过来的值到方法的参数上。
    • @RequestHeader@CookieValue : @RequestHeader 注解,可以把Request请求header部分的值绑定到方法的参数上。

    范例

    @RestController
    @RequestMapping("/head")
    public class DemoController {
    
        @RequestMapping("/info")
        public String headInfo(@RequestHeader("Accept-Encoding") String encoding ,@RequestHeader("Keep-Alive")long keepAlive) {
            return encoding + " : " + keepAlive;
        }
    }
    

    @RequestParam

    • 常用来处理简单类型的绑定,通过Request.getParameter() 获取的String可直接转换为简单类型的情况( String--> 简单类型的转换操作由ConversionService配置的转换器来完成);因为使用request.getParameter()方式获取参数,所以可以处理get 方式中queryString的值,也可以处理post方式中 body data的值;
    • 用来处理Content-Type: 为 application/x-www-form-urlencoded编码的内容,提交方式GET、POST;
    • 该注解有两个属性: value、required; value用来指定要传入值的id名称,required用来指示参数是否必须绑定;

    @RequestBody
    该注解常用来处理Content-Type: 不是application/x-www-form-urlencoded编码的内容,例如application/json, application/xml等;

    它是通过使用HandlerAdapter 配置的HttpMessageConverters来解析post data body,然后绑定到相应的bean上的。

    注解6 @PostConstruct 和 @PreDestroy

    @PostConstruct 和 @PreDestroy 不是用于依赖注入,而是bean 的生命周期。类似于 init-method(InitializeingBean) destory-method(DisposableBean).
    Spring 容器中的 Bean 是有生命周期的,Spring 允许在 Bean 在初始化完成后以及 Bean销毁前执行特定的操作,您既可以通过实现 InitializingBean/DisposableBean 接口来定制初始化之后 /销毁之前的操作方法,也可以通过 <bean> 元素的 init-method/destroy-method 属性指定初始化之后 /销毁之前调用的操作方法
    容器初始化 bean 和销毁前所做的操作定义方式有三种:
    第一种:通过@PostConstruct 和 @PreDestroy 方法 实现初始化后和销毁bean之前进行的操作
    第二种是:通过 在xml中定义init-method 和 destory-method方法
    第三种是: 通过bean实现InitializingBean和 DisposableBean接口

    范例

    public class Boss {
        @Resource
        private Car car;
    
        @Resource(name = "office")
        private Office office;
    
        @PostConstruct
        public void postConstruct1(){
            System.out.println("postConstruct1");
        }
    
        @PreDestroy
        public void preDestroy1(){
            System.out.println("preDestroy1"); 
        }
    }
    
    public class AnnoIoCTest {
    
        public static void main(String[] args) {
            String[] locations = {"beans.xml"};
            ClassPathXmlApplicationContext ctx = 
                new ClassPathXmlApplicationContext(locations);
            Boss boss = (Boss) ctx.getBean("boss");
            System.out.println(boss);
            ctx.destroy();// 关闭 Spring 容器,以触发 Bean 销毁方法的执行
        }
    }
    

    最后说明下Spring对注解的处理

    三 spring中注解的处理

    spring中注解的处理基本都是通过实现接口 BeanPostProcessor 来进行的:

    public interface BeanPostProcessor {
        @Nullable default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
             return bean; 
         }    
        @Nullable
        default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            return bean;
        }
        
    }
    

    相关的处理类有:

    AutowiredAnnotationBeanPostProcessor,
    CommonAnnotationBeanPostProcessor,
    PersistenceAnnotationBeanPostProcessor,
    RequiredAnnotationBeanPostProcessor
    ...
    
    • 这些处理类,可以通过 context:annotation-config/ 配置隐式的配置进spring容器。这些都是依赖注入的处理,还有生产bean的注解(@Component, @Controller, @Service, @Repository)的处理:

    • 这些都是通过指定扫描的基包路径来进行的<context:component-scan base-package="..." />,将他们扫描进spring的bean容器。

    • 注意context:component-scan也会默认将 AutowiredAnnotationBeanPostProcessor,CommonAnnotationBeanPostProcessor 配置进来。所以context:annotation-config/是可以省略的。另外context:component-scan也可以扫描@Aspect风格的AOP注解,但是需要在配置文件中加入 aop:aspectj-autoproxy/ 进行配合。

    相关文章

      网友评论

        本文标题:Java原生注解和Spring注解的说明

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