spring注解

Posted 新火且试茶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring注解相关的知识,希望对你有一定的参考价值。

一、组件注册

1、@Configuration和@Bean

  • @Configuration:告诉spring这是一个配置类。配置类==配置文件,可使用注解在这个类中进行配置文件中的配置。
  • @Bean:给容器中注册一个Bean,类型为返回值类型,id默认使用方法名为id。可修改
  • 使用AnnotationConfigApplicationContext来从容器中读取bean。

2、@ComponentScan

与.xml配置文件中的扫描包相同。

1)、属性:

value:要扫描的包

excludeFilters=Filter[]:指定扫描的时候按照什么规则排除哪些组件

includeFilters=Filter[]:指定扫描的时候只需要那些组件。需要将默认过滤关闭useDefaultFilters = false才有用,否则全部都会被导入。

//将com.atguigu包及其子包下的有@Controller和@Service的组件添加到容器中,
@Configuration@ComponentScan(value = "com.atguigu" ,         includeFilters = {@Filter(type = FilterType.ANNOTATION,classes = {Controller.class,Service.class})},         useDefaultFilters = false)public class MainConfig {

@ComponentScan是可重复注释,可以扫描多个包,或者用@ComponentScans来配置多个@ComponentScan

2)、TypeFilter指定过滤规则

  • ANNOTATION 按照注释

  • ASSIGNABLE_TYPE 按照给定的类型

  • REGEX 正则表达式

  • CUSTOM 自定义规则。

自定义过滤规则

实现TypeFilter接口

public class MyTypeFilter implements TypeFilter {
    /**
    * metadataReader:读取当前正在扫描的类
    * metadataReaderFactory:可以获取到任何类的信息
    */
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
        throws IOException {
        //获取当前正在扫描类的注解信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        //获取当前正在扫描类的类信息
        ClassMetadata classMetadata = metadataReader.getClassMetadata();         //获取当前类资源
        Resource resource = metadataReader.getResource();
        if(classMetadata.getClassName().contains("er")) {//将类名带有er的扫描进容器
            return true;
        }
        return false;
    }
}

3、@Scope设置组件作用域

相当于bean标签中的scope属性

  • prototype:多实例。每次获取时才会调用方法,并且每一次获取都会调用一次
  • singleton:单实例的。(默认值):ioc容器启动时就会调用方法创建对象放到ioc容器中,以后每次获取就是直接从容器中拿
  • request:同一次请求创建一个实例
  • session:同一个session创建一个实例

4、@Lazy (bean懒加载)

只针对单例而言。

单例bean,默认在容器启动时创建对象

使用懒加载,在第一次获取时创建实例

5、@Conditional(按条件判断注册)

public @interface Conditional {
    /**
    * All {@link Condition Conditions} that must {@linkplain Condition#matches match}
    * in order for the component to be registered.
    */
    Class<? extends Condition>[] value();
}

参数类型为Class数组,可通过实现Condition接口的类来进行条件判断

满足当前条件,配置的bean才能生效。放在类上,可以对类中的组件统一设置

例:在linux环境下才注册一个bean

//作为条件要实现Condition接口
public class LinuxCondition implements Condition {
    /**
    * ConditionContext:判断条件能使用的上下文环境
    * AnnotatedTypeMetadata:注释信息
    */
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Environment environment = context.getEnvironment();
        String property = environment.getProperty("os.name");
        if(property.equals("Linux")) {
            return true;
        }
        return false;
    }
}

使用

@Conditional({LinuxCondition.class})
@Bean("linux")
public Person person3() {
    return new Person("linus",50);
}

6、@Import

1)、快速给容器中导入一个组件。

id默认为全类名。

@Import(要导入容器的组件)。容器就会自动注册这个组件,默认id为全类名。

2)、实现自定义逻辑返回需要的组件

1. importSelector:返回要导入组件的全类名数组。

创建一个实现了接口ImportSelector的类,实现方法selectImports方法,可以在内部书写自定义的逻辑,返回的数组要是全类名,并且不能为空指针,最低为空数组。

public class MyImportSelect implements ImportSelector{
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"com.atguigu.bean.Blue","com.atguigu.bean.Red"};
    }
}
@Import({Color.class,MyImportSelect.class})

在导入这个实现类时就会将自定义的组件({"com.atguigu.bean.Blue","com.atguigu.bean.Red"})导入容器中,而不是将实现类导入容器中。

2. ImportBeanDefinitionRegistrar接口

与ImportSelector功能相同,可以将要添加的组件注册到容器中

7、FactoryBean注册组件

工厂Bean获取的是调用getObject创建的对象

创建一个实现了FactoryBean接口的类

public class ColorFactoryBean implements FactoryBean<Color> {
    @Override
    public Color getObject() throws Exception {
        return new Color();
    }
    @Override
    public Class<?> getObjectType() {
        return Color.class;
    }
    @Override
    public boolean isSingleton() {
        // TODO Auto-generated method stub
        return FactoryBean.super.isSingleton();
    }
}
  • getObejct:返回一个对象,这个对象会添加到容器中

  • getObjectType:返回对象的类型

  • isSingleton:是否是单例

配置Bean

@Bean
public ColorFactoryBean colorFactoryBean() {
    return new ColorFactoryBean();
}

测试FactoryBean,结果为Color。若通过id获取bean时在id前加上&符,那么变回获取工厂本身,或者通过类型获取

@Test
public void testFactoryBean() {
    Object bean = ioc.getBean("colorFactoryBean");
    System.out.println(bean.getClass());
}//获取到Color

@Test
public void testFactoryBean() {
    Object bean = ioc.getBean("&colorFactoryBean");
    System.out.println(bean.getClass());
}//获取到ColorFactoryBean

二、生命周期(指定初始化和销毁方法)

1、@Bean指定初始化和销毁方法

默认由容器来管理bean的声明周期。但我们可以自定义初始化和销毁方法,容器在bean进行到当前生命周期的时候来调用我们自定义的初始化和销毁方法。

  1. 指定初始化和销毁方法。像bean标签里的init-method和destroy-method方法。
  2. 在Bean注解中对应有initMethod方法和destroyMethod方法
  3. 初始化:对象创建完成并且属性赋值完毕。销毁:容器关闭。
  4. 多实例:容器不会管理这个bean。不会调用其销毁方法

2、InitializingBean和DisposableBean接口

通过让bean实现InitializingBean和DisposableBean接口同样可以指定初始化和销毁方法

3、@PostConstruct和@PreDestroy

通过@PostConstruct和@PreDestroy可以实现同样效果。将两个注释分别标注在bean方法的初始化、销毁方法。

  • @PostConstruct:在创建bean并为属性赋值后调用该注解标注的方法

  • @PreDestroy:在容器关闭之前调用该注解标注的方法

4、BeanPostProcessor

bean的后置处理器

在bean初始化前后进行一些处理工作:

  • postProcessorBeforeInitialization:在初始化之前工作

  • postProcessAfterInitializeation:在初始化之后工作

三、属性赋值

1、@Value

  1. 基本数值
  2. 可以写SpEL,#{}取出
  3. 可以写${},取出配置文件中的值

2、@PropertySource

加载外部配置文件,与xml中的加载外部属性文件功能相同

四、自动装配

自动装配:spring利用依赖注入(DI),完成对IOC容器中各个组件的依赖关系赋值。

1、Autowired(Spring定义的)

自动注入。

  • 默认优先按照类型从容器中找对应的组件
  • 如果找到多个相同类型的组件,在将属性的名称作为id到容器中查找
  • @Qualifier(),使用@Qualifier指定要装配的组件id,而不是使用属性
  • 默认一定要将属性赋值好,没有就会报错。可以使用属性required,来指定是否必须要被装配
  • @Primary,让spring进行自动装配的时候,在未指定装配的情况下,默认使用此注解标注的bean作为装配的首选项。若使用了@Qualifier,那么便使用@Qualifier指定的bean的名字

2、@Resource和@Inject(java规范)

  • @Resource:可以和@Autowired一样实现自动装配功能,默认使用属性的名称装配。不能支持@Primary和requred功能
  • @Inject:需要导入javax.inject的包,和@Autowired的功能一样。但是没有required=false的功能。

3、方法、构造器位置的自动装配

1.标注在方法上

spring容器创建当前对象,就会调用方法,完成赋值

方法使用的参数,自定义类型的值从ioc容器获取。

默认加载ioc容器中的组件,容器启动会自动调用无参构造器创建对象,再进行初始化等操作

2.标注在构造方法上

如果组件只有一个有参构造器,这个有参构造器的@Autowired可以省略,参数位置的组件还是可以自动从容器中获取

3.标注在参数上

4.@Bean标注的方法创建对象的时候,方法参数的值从容器中获取。默认不写@Autowired

5.都是从ioc容器中获取参数的值

4.、自定义组件注入底层组件

自定义组件想要使用spring容器底层的一些组件(ApplicationContext、BeanFactory)

自定义组件实现xxxAware:在创建对象的时候,会调用接口规定的方法注入相关组件。

5、@Profile环境搭建

Profile:Spring为我们提供的可以根据当前环境,动态的激活和切换一些列组件的功能

  1. 加了环境标识的bean,只有这个环境被激活的时候才能够注册到容器中,默认是default环境
  2. 写在配置类上,只有是指定的环境的时候,整个配置类里面的所有配置才能开始生效
  3. 没有标注环境的bean,在所有的环境下都被加载

开发环境,测试环境,生产环境

@Porfile根据环境注册bean

1.使用命令行动态参数:在虚拟机参数位置加载-Dspring.profiles.actice=test切换到测试环境

2.使用代码的方式激活某些环境

@Test
public void test01() {

    //1.创建一个无参的ApplicationContext
    AnnotationConfigApplicationContext ioc = new AnnotationConfigApplicationContext();

    //2.设置需要激活的环境
    ioc.getEnvironment().setActiveProfiles("test","prod");

    //3.注册主配置类
    ioc.register(MainConfigOfProfile.class);

    //4.启动刷新容器
    ioc.refresh();

    String[] beanDefinitionNames = ioc.getBeanDefinitionNames();

    for (String name : beanDefinitionNames) {

        System.out.println(name);

    }
}

以上是关于spring注解的主要内容,如果未能解决你的问题,请参考以下文章

使用Java代码和注解完成Spring配置

Spring Boot实战笔记-- Spring高级话题(组合注解与元注解)

如何获取spring 注解的bean

SRPING02_配置数据源原始注解开发新注解开发集成Junit代码实现

spring 在哪里可以找到注解的实现代码

Spring组合注解与元注解