zoukankan      html  css  js  c++  java
  • 后端——框架——容器框架——spring_core——注解

      注解分为三类,容器相关,bean相关,null相关。

    1、容器

    采用注解方式配置IOC容器,有三种方式

    纯注解形式,提供至少一个配置类(@Configuration标注的类)

    纯注解形式,提供至少一个Bean(@Component等标注的类)

    混合方式,提供配置类,使用@ImportResource引入Spring的配置文件。

    1.1   创建

    容器创建,实质是创建applicationContext对象,使用注解时,创建的对象为AnnotationConfigApplicationContext对象,它的创建方式有以下几种。

    单个配置类:创建AnnotationConfig对象,参数为XXApp.class

    public ApplicationContext singleConfig() {
    	ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
    	return ac;
    }
    

      多个配置类:有三种方式,第一种使用@Import注解,第二种方式多个XXApp.class参数,第三种方式调用register方法。

    // 方式一
    @Configuration
    @Import({AppConfig1.class,AppConfig2.class})
    public class AppConfig {}
    // 方式二
    ApplicationContext ac = new  AnnotationConfigApplicationContext(AppConfig.class,AppConfig2.class);
    //  方式三,此时必须是AnnotationConfigApplicationContext对象,
    //  ApplicationContext接口中无这些方法
    ac.register(AppConfig1.class);
    ac.register(AppConfig.class);
    

      纯注解形式:多个Component与Configuration注解相同,只不过IOC容器中只存在初始化时传入的几个Bean。

      混合方式:使用@ImportResource注解

    @Configuration
    @ImportResource({"classpath:spring/application.xml"})
    public class AppConfig {}
    

    1.2     扫描

    1.2.1    路径

    指定扫描路径的方式有两种

    使用@ComponentScan注解,通过设置basePackages指定bean所在包的名称,多个包名时使用逗号分隔,包名可以是正则表达,SpringEL表达式。

    调用context.scan方法,参数为包名。使用频率很低。

    1.2.2  过滤条件

    1.2.2.1     概念

    添加过滤条件有两个含义,第一类是给配置类上添加过滤条件,第二类是给具体的某个bean上添加过滤条件。

    第一类是给@Component-scan设置include-filter和exclude-filter属性,它们的值可以是以下五类:

    1. Annotation:根据类上的注解进行过滤,默认值
    2. Assignable:根据类的class或类名进行过滤
    3. Aspectj:根据AspectJ的类型表达式对类名进行过滤
    4. Regex:根据正则表达式对类型进行过滤
    5. Custom:根据TypeFilter的实现类进行过滤。

      第二类是给具体的bean上添加过滤条件,当满足条件时注入bean,不满足时跳过。

      它是给具体的bean上添加@Conditional注解,并设置value属性,每一个value属性的值都是Condition接口的实现类。Condition接口只有一个方法matches,当满足条件时,该方法返回true,不满足条件时,返回false。

      要添加自定义过滤条件,至少需要两个步骤

    1. 第一步,编写XXConditionImpl,实现Condition接口,
    2. 第二步,在类上添加@Conditional注解,并设置value的值为XXConditionImpl.class

    springBoot中存在大量该注解,@Conditional和Condition都有自己的类结构。例如@ConditionalOnClass表示某个类是否在IOC容器中,当存在时满足条件,不存在时不满足条件。

    想要深入了解,可以查看DataSourceAutoConfig的源码。

    1.2.2.2     componentScan

    描述

    它用于指定容器注入bean时的一些配置。

    属性

    basePackage

    说明:指定扫描包的根路径,存在多个时,使用逗号分隔

    类型:字符串,包名或者包名的正则表达式

    是否必填:否,不指定时默认为classpath

    属性

    Include-filter

    说明:添加包含的过滤条件,过滤条件有五种类型,

    1. Annotation:根据类上的注解进行过滤,默认值
    2. Assignable:根据类或者类名进行过滤
    3. Aspectj:根据AspectJ的类型表达式对类名进行过滤
    4. Regex:根据正则表达式对类型进行过滤
    5. Custom:根据TypeFilter的实现类进行过滤。

    类型:不同类型对应不同的数值类型

    是否必填:否,不指定时无过滤器

    属性

    enclude-filter

    说明:添加排除的过滤条件,过滤条件有五种类型,

    1. Annotation:根据类上的注解进行过滤,默认值
    2. Assignable:根据类或者类名进行过滤
    3. Aspectj:根据AspectJ的类型表达式对类名进行过滤
    4. Regex:根据正则表达式对类型进行过滤
    5. Custom:根据TypeFilter的实现类进行过滤。

    类型:不同类型对应不同的数值类型

    是否必填:否,不指定时无过滤器

    属性

    lazyInit

    说明:指定bean加载时是否延迟加载

    类型:布尔值

    是否必填:否,默认值为false。

    属性

    nameGenerator

    说明:指定bean注入时,名称的生成

    类型:NameGenerator的实现类

    是否必填:否。

    位置

    配置类上


    1.2.3   添加索引

    添加索引是指在注入bean时,给bean添加索引,在获取bean时会变快,提高性能。

    添加索引的步骤有两步:

    1. 添加spring-context-indexer依赖。
    2. 在IOC容器中注入CandidateComponentsIndexer类。

    如果想禁用此功能,又不想移除依赖,可以设置spring.index.ignore属性值为true。

    1.2.4      profile

    Profile本质也是一种过滤条件,过滤条件是基于”环境”的,例如生产环境,测试环境。

    使用@Profile注解的步骤有以下两步:

    第一步:在bean上添加@profile注解,当激活的环境与设置的环境相等时,注入bean。方式有以下三种

    1. 在类上添加,在方法上添加,类上标注有@Component等,方法上有@Bean。
    2. 创建@Profile的元注解,在类上,方法上添加元注解。例如创建@Production注解
    3. 在配置文件中,给beans标签设置profile属性,相当于全局;或给单个bean标签设置profile属性。

    第二步:激活profile。方式有四种

    1. 设置spring.profiles.active属性。Java argument形式,配置文件形式等等
    2. 调用context.getEnvironment().setActiveProfiles方法,参数为激活的环境。
    3. 指定默认的profile。
    4. 如果存在spring-test依赖,在配置类上添加@ActiveProfiles

    设置默认profile的方式也有三种。

    1. 在配置类上添加@Profile注解
    2. 调用context.getEnvironment().setDefaultProfiles方法
    3. 设置spring.profiles.default属性。

    Profile的值可以是单个环境,多个环境,或者是环境的逻辑表达式。

    单个环境,@Profile(“envName”);

    多个环境,@Profile({“envName1”,”envName2”}),它们是逻辑或关系,只要其中一个环境激活即加载。

    逻辑表达式,与(&),或(|),非(!)。例如@Profile(“!envName”)。

    2、bean

      bean的注解分为三类,注入bean。获取bean。配置bean,例如属性,作用域,生命周期等。

    2.1     注入

    当存在配置文件,且没有配置类时(@Application标注的类),注解生效需要配置context:annotation-config,也可以配置context:component-scan,它基于annotation-config的基础上添加base-package,include,exclude等属性,用于添加扫描包的条件。

    当存在配置类时,需要在其上添加ComponentScan注解,配置base-package,include,exclude属性。含义与context:component-scan标签相同。

    当注解存在name属性时,容器会将name属性值作为bean的名称,当不存在name属性时,会将类名的首字母小写,作为bean的名称,需要特别注意的是类名不是类全名,当不同包下存在相同类名时,会存在同名的bean。

    Spring支持自定义bean名称的生成策略,两个步骤,第一步编写MyNameGenerator实现NameGenerator接口,第二步设置该类为Component-scan注解的name-generator属性值。

    2.1.1  configuration

    描述

    它用于创建AnnoationConfigApplicationContext,它属于配置类。地位等价于applicationContext.xml

    位置

    类上

      2.1.2  component

    描述

    它代表一个bean,当IOC容器扫描包时,会把标有该注解的类添加到容器中

    位置

    类上

      2.1.3  repository

    描述

    它是Component注解的元注解,功能与Component相等,含义缩小,只表示MVC层中的Model层,即DAO数据层

    位置

    类上

    2.1.4  service

    描述

    它是Component注解的元注解,功能与Component相等,含义缩小,只表示服务层

    位置

    类上

    2.1.5   controller

    描述

    它是Component注解的元注解,功能与Component相等,含义缩小,只表示控制器层

    位置

    类上

    2.1.6   restController

    描述

    它是Controller与ResponseBody的组合注解,表示它是一个Controller,并且响应类型为数据流。

    位置

    类上

      2.1.7   bean

    描述

    它代表一个bean,标注在方法上,将该方法的返回值注入到IOC容器中。

    属性

    name:

    说明:指定bean的名称,默认值为方法的名称,当指定多个name值时,本质是在设置bean的别名。

    类型:字符串,

    是否必填:否

    属性

    Init-method:

    说明:对应bean标签的init-method属性。

    类型:字符串,方法名称

    是否必填:否,默认值为init,

    属性

    destory-method:

    说明:对应bean标签的destory-method属性。

    类型:字符串,方法名称

    是否必填:否,默认值为close,shutdown

    位置

    方法上(居多),注解上

      定义在@Configuration下的@Bean会通过CGLIB方式调用方法,并获取相关的原信息,所以方法不能使用private,final修饰。定义在@Component下的@Bean不会。

    2.2    获取

    2.2.1   required

    描述

    在设置bean属性时,Required注解表示该属性为必备属性,如果在创建Bean时,没有对应的属性值,会抛出异常。构造器依赖也会起到同样的效果。

    位置

    属性上,或者属性的set方法上

       示例如下:

    public class User {
    	// 用户的名称,必填属性
    	@Required
    	private String name;
    }
    

    2.2.2   autoWired

    描述

    它对应bean标签的autowire属性,在注入bean的依赖时,从IOC容器中获取,获取方式有四种NONE,byName,byType,constructor。默认的方式为byName,如果查找不到,根据byType方式。

    当属性为容器类型时,数组或集合时,会把找到的所有依赖都放入容器中

    属性

    required:

    说明:当注入beanA的依赖beanB时,用于指定该依赖是否是必须的,当为true时,为必须的,此时容器中没有依赖的beanB,则beanA创建失败,并报错。

    类型:布尔值,true或者false

    是否必填:否,默认值为true

    位置

    依赖的任何地方,属性上,构造器参数,方法参数

      示例如下:

    public class User {
    // 自动注入Address类,当IOC容器中没有Address时,User创建失败并报错
    	@Autowired(required=true)
    	private Address homeAddress;
    }
    

    2.2.3   order

    描述

    当beanA依赖beanB的容器时,IOC容器在查找beanB时,如果beanB有多个,Order注解用来决定在容器中的顺序

    位置

    类上

      示例如下:

    public class User {
    //  IOC中存在多个Address时,IOC会根据Order注解决定Address在List<Address>
    //  的顺序
    	@Autowired(required=true)
    	private List<Address> homeAddress;
    }
    //  Address类
    @Order(value=1)
    public class Address {
    }
    

      它一般发生在根据byName无法找到依赖时,根据byType查找时,存在多个相同的类名,例如上例中不存在id为homeAddress的bean,存在多个Address类,com.test.Address,com.bean.Address。 

    2.2.4   primary

    描述

    当beanA依赖beanB的容器时,IOC容器在查找beanB时,如果beanB有多个,Primary用来指定优先使用该bean。 对应bean标签的primary属性

    位置

    注入bean时的任何地方,方法,类上

      示例如下:  

    public class User {
    //  IOC中存在多个Address时,IOC会根据Order注解决定Address在List<Address>
    //  的顺序
    	@Autowired(required=true)
    	private Address homeAddress;
    }
    //  Address类
    @Component
    @Primary
    public class Address {
    }
    

      与Order不同的是,beanA依赖beanB,它们之间的关系是1:1,而IOC容器中存在多个beanB,此时由于无法决定使用哪个beanB,导致beanA创建失败,primary用于决定优先选中哪个beanB。如果beanB只存在一个时,该注解无意义。

    2.2.5   qualifier

    描述

    当beanA依赖beanB,并且在容器中存在多个beanB时,Qualifiler注解用于为beanB分类。

    位置

    注入beanB时用来为beanB归类,获取时qualifier作为过滤条件,查找合适的beanB。

      分类的方式有三种,

    1. 第一种,设置qualifier的value属性
      1. 注入Address类
    <!-- 家庭住址 -->
    <bean class="com.bean.Address">
    	<qualifier value="homeAddress" />
    </bean>
    <!-- 公司住址 -->
    <bean class="com.bean.Address">
    	<qualifier value="companyAddress" />
    </bean>
    

          2.获取Address 

    public class User {
    	// 用户的家庭地址
    	@Autowired
    	@Qualifier("homeAddress")
    	private Address homeAddress;
    	// 用户的工作地址
    	@Autowired
    	@Qualifier("companyAddress")
    	private Address companyAddress;
    }
    

      此时Qualifier注解的作用与bean的ID差不多,还不如指定id属性,并且使用byName的方式获取。

      2.第二种,继承Qualifier

        1.编写@HomeAddress,@CompanyAddress注解

    /**
     * 
      * @Title: HomeAddress.java  
      * @Package com.annotation  
      * @Description: HomeAddress注解
      * @version V1.0
     */
    @Target({ElementType.FIELD,ElementType.PARAMETER})
    @Retention(RetentionPolicy.RUNTIME)
    @Qualifier
    public @interface HomeAddress {
    	// 居住地址
    	String value();
    }
    

        2. 注入Address类,配置qualifier子标签,可以看到子类相当于二级分类。

    <bean class="com.bean.Address">
    	<qualifier type="com.annotation.HomeAddress"  value="homeTown" />
    </bean>
    <bean class="com.bean.Address">
    	<qualifier type="com.annotation.CompanyAddress" value="working" />
    </bean>
    

        3.获取Address类

    public class User {
    	// 用户的家庭地址
    	@Autowired
    	@HomeAddress("homeTown")
    	private Address homeAddress;
    	// 用户的工作地址
    	@Autowired
    	@CompanyAddress("working")
    	private Address companyAddress;
    }
    

      此示例中,子类相当于二级目录,其中的value属性相当于过滤条件,如果value不是homeTown和working,则找不到Address类。homeAddress和companyAddress为null值

      3.第三种,继承Qualifier,添加更多的属性值作为过滤条件,例如在上述示例中只有value作为过滤条件,可以在注解中添加其他属性。

      它与第二种方式基本相同,在第二步时,注入Address类时,多个属性的格式为:

    <bean class="com.bean.Address">
    	<qualifier type="com.annotation.HomeAddress">
    		<attribute key="field1" value="value1"/>
    		<attribute key="field2" value="value2"/>
    	</qualifier>
    </bean>
    

      当beanA依赖beanB,并且存在多个beanB时,该注解为beanB分类,支持一级分类和二级分类。

      当容器中只存在一个beanB时,该注解无任何意义

      当只需要一级分类时,完全可以由bean的ID,name,alias等属性代替。

      当需要二级分类时,可以使用该注解。

      在实际的项目中,基本不会存在二级分类的情形,所以该注解的使用频率很低。

    2.2.6   resource(Java_based)

    描述

    当beanA依赖beanB时,Resource注解用于在IOC容器中查找beanB。方式通常是byName,当不指定name属性时,name的属性值为类名首字母小写。

    属性

    name:

    说明:根据name在IOC中查找beanB,它对应beanB的ID,name,alias中的任意一个。

    类型:字符串

    是否必填:否,默认值为类名首字母小写

    位置

    属性上,属性的set方法上

           示例如下:

      第一步,注入Address

    <bean id="address" class="com.bean.Address"/>
    

      第二步,获取

    public class User {
    	// 用户的工作地址,可以不指定,默认值也是address
    	@Resource(name="address")
    	private Address companyAddress;
    }
    

    2.2.7   inject(Java_based) 

      等价于@Autowired

      2.2.8   named 

      当不指定value属性值时,等价于@Component,当指定value值时,等价于@Qualifier(“value”)。

    2.3     配置

      2.3.1   description

    描述

    Bean的一段描述文字

    位置

    方法上,与@Bean一起使用

      2.3.2   value

    描述

    用于获取Properties的值,并且把该值赋给对象的属性

    属性

    key:

    说明:IOC容器中变量的key值,它可以从JVM变量,操作系统变量,配置文件等等获取。

    类型:springEL表达式

    是否必填:是

    位置

    属性上

      2.3.3   lazyInit

    描述

    用于定义bean是否延迟加载

    属性

    value:

    说明:true时延迟加载,false时随容器的创建加载。

    类型:布尔值

    是否必填:否,默认值为false

    位置

    方法上,与@Bean一起使用

    2.3.4  scope

    描述

    用于指定bean的作用域,

    属性

    value:

    说明:bean作用域的值,五个值中的任意一个。

    类型:枚举值,singleton,prototype,request,session,application

    是否必填:否

    位置

    方法上,与@Bean一起使用

    2.3.5   requestScope

      等价于@Scope(“request”)

      2.3.6   sessionScope

      等价于@Scope(“session”)

      2.3.7   servletContextScope

      等价于@Scope(“application”)

      2.3.8   postConstruct(Java_based)

    参考bean的生命周期,它添加在方法上,触发时机在构造器之后,init方法之前。

    2.3.9   preDestory(Java_based)

    参考bean的生命周期,它添加在方法上,触发时机在bean的销毁阶段,destory方法之前。

    3、null相关

    3.1     注解

    原著中介绍了4个注解。

    @NonNull:用于添加对象属性,方法参数,方法返回值不为NULL的约束条件。

    // 对象属性上
    @NonNull
    private String userName;
    // 方法参数上
    public static void testLiteralExp(@NonNull String str) {}
    // 方法返回值上
    public @NonNull String test(){}
    

      @Nullable:与@NonNull作用刚好相反,属性,方法参数,返回值可以为NULL

    @NonNullApi:当前包下面的所有方法参数和返回值都不可以为NULL,可以被@Nullable覆盖。

    @org.springframework.lang.NonNullApi
    package learn.test;
    

      @NonNullField:当前包下面的对象的所有字段都不可以为NULL,可以被@Nullable覆盖。

    3.2  IDE

    当字段,方法参数,方法返回值添加上这些注解时,IDE会有相应的提示。本文以Eclipse为例演示具体的步骤

      第一步:打开Window---->preferences----->Java------>Complier---->Error/Warnings

      找到Null analysis,展开,点击enable annotation-based null analysis。

      

       第二步,在下面的use default annotation for null specifications把对勾去掉,点击configure,配置如下图,

      

       第三步,点击Apply,重新编译即可看到效果。

        

    3.3   JSR305

    JSR305中也有相同功能的注解,而且还有很多其他的注解,使用这些注解首先必须引入jsr305的jar包

    <!-- https://mvnrepository.com/artifact/com.google.code.findbugs/jsr305 -->
    <dependency>
        <groupId>com.google.code.findbugs</groupId>
        <artifactId>jsr305</artifactId>
        <version>3.0.2</version>
    </dependency>
    

      编写代码时,再次使用NonNull注解时,会发现有javax.annotation.NonNull。

    import javax.annotation.Nonnull;
    

      要使编译器提示,需要重新配置第二步,将注解修改为javax.annotation.NonNull等注解

  • 相关阅读:
    day10 测试2
    算法题
    day10 自动化测试
    day09 测试
    进行试验,对比
    多层网络的SIR实现
    day08 商城项目
    day07 cookie session 模板
    day06 模型类
    纸上谈兵:图(graph)
  • 原文地址:https://www.cnblogs.com/rain144576/p/14758732.html
Copyright © 2011-2022 走看看