Spring注解之组件注册

Spring IOC(Inversion of Control ) 控制反转是一种思想,并不是 Spring 所特有的,而 DI 依赖注入是这种思想的具体实现方案。

@Configuration //配置类==配置文件
  • @Bean
    给容器中注册一个Bean;类型为返回值的类型,id默认是方法名,可通过该注解指定
@Bean
public Person person(){
    return new Person("zhangsan", 20);
}
@Bean("person01") // 指定id
public Person person(){
    return new Person("zhangsan", 20);
}
  • @ComponentScan
    加在配置类上,扫描指定包下所有类,默认加载标注了@Controller、@Service、@Repository、@Component
@ComponentScan("org.chm")

excludeFilters:指定扫描时按照什么规则排除哪些组件

@ComponentScan(value = "org.chm", excludeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class})
})
```java
includeFilters:指定扫描时只需要包含哪些组件,需要结合useDefaultFilters设置为false,静止默认加载规则
```java
@ComponentScan(value = "org.chm", includeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class})
}, useDefaultFilters = false)

Java 8 开始新增@Repeatable注解,允许同一个注解可以使用多次,如今Java 8 环境可在一个配置类上多次使用@ComponentScan注解,8 之前可以使用@ComponentScans。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
	...
}

过滤规则:

  1. FilterType.ANNOTATION:按照注解过滤
  2. ASSIGNABLE_TYPE:按照给定的类型过滤(包含子类)
  3. ASPECTJ:使用ASPECTJ表达式过滤
  4. REGEX:使用正则
  5. CUSTOM:按照自定义规则过滤
@ComponentScan(value = "org.chm", includeFilters = {
        @ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})
}, useDefaultFilters = false)
@Configuration
public class PersonConfig {
	...
}

public class MyTypeFilter implements TypeFilter {

    /**
     *
     * @param metadataReader:读取到的当前正在扫描的类的信息
     * @param metadataReaderFactory:可以获取到其他任何类信息
     */
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        metadataReader.getAnnotationMetadata();
        //获取当前类注解的信息
        metadataReader.getAnnotationMetadata();
        //获取当前类的类信息
        metadataReader.getClassMetadata();
        //获取当前类资源(类的路径)
        metadataReader.getResource();

        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        System.out.println("--> "+classMetadata.getClassName());
        return false;
    }
}

  • @Scope 控制作用域

    1. singleton 单实例(默认值):ioc容器在启动时调用方法创建对象放入ioc容器中,以后每次获取就是直接从容器中拿。
    2. prototype 多实例:ioc容器在启动时不会调用方法创建对象放入容器,每次获取(getBean)的时候才哈调用方法创建对象。
    3. request 同一次请求创建一个实例
    4. session 同一个session创建一个实例
  • @Lazy
    懒加载,针对单实例bean(默认在容器启动时创建),懒加载就是在容器启动时不创建对象,而是第一次使用(获取)Bean时创建对象,并初始化。

  • @Conditional SpringBoot中使用较多
    按条件给容器注册bean,可以放在类上或方法上使用,放在类上表示满足当前条件,这个类中配置的索引bean注册才能生效(统一管理)

public class LinuxCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Environment environment = context.getEnvironment();
        String name = environment.getProperty("os.name");
        if (name.contains("Linux"))
        {
            return true;
        }
        return false;
    }
}

public class WindowCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // 获取到ioc使用的beanfactory
        context.getBeanFactory();
        // 获取bean定义的注册类
        context.getRegistry();
        // 获取当前环境信息
        Environment environment = context.getEnvironment();
        String name = environment.getProperty("os.name");
        if (name.contains("Windows"))
        {
            return true;
        }
        return false;
    }
}

@Configuration //告诉Spring这是一个配置类,配置类==配置文件
@ComponentScan(value = "org.chm", includeFilters = {
        @ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})
}, useDefaultFilters = false)

public class PersonConfig {

    //给容器中注册一个Bean;类型为返回值的类型,id默认是方法名,可通过该注解指定
    @Bean
    public Person person(){
        return new Person("zhangsan", 20);
    }

    @Bean("bill")
    @Conditional({WindowCondition.class})
    public Person person01()
    {
        return new Person("Bill Gates", 62);
    }

    @Bean("linus")
    @Conditional({LinuxCondition.class})
    public Person person02()
    {
        return new Person("Linus", 48);
    }

}

给容器中注册组件的四种方式:
1)包扫描+组件标注注解(@Controller/@Service/@Repository/@Component)
2)@Bean:导入的第三方包里面的组件)
3)@Import 快速给容器导入一个组件

  • @Import(Color.class) 容器中会自动注册这个组件,id就是全类名。
  • @Import+ImportSelector(SpringBoot中使用较多)
  • @Import+ImportBeanDefinitionRegistrar 收到注册bean到容器中
// 自定义四逻辑返回需要导入的组件
public class MyImportSelector implements ImportSelector {
    // 返回值就是要导入到容器中的组件全类名
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"org.chm.bean.Red", "org.chm.bean.Yellow"};
    }
}

@Import({Blue.class, MyImportSelector.class})
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    /**
     * @param importingClassMetadata 当前类的注解信息
     * @param registry 调用BeanDefinitionRegistry.registerBeanDefinition方法手工注册到容器中
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        boolean definition = registry.containsBeanDefinition("org.chm.bean.Blue");
        boolean definition2 = registry.containsBeanDefinition("org.chm.bean.Yellow");
        if (definition && definition2)
        {
            registry.registerBeanDefinition("rainBow", new RootBeanDefinition(RainBow.class));
        }
    }
}

@Import({Blue.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})

4)使用Spring提供的FactoryBean(工厂Bean);

  • 默认获取到的是工厂bean调用getObject创建的对象
  • 要获取工厂Bean本身,我们需要给id前面加一个&符号
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() {
        return true;
    }
}

// 配置类中加入
@Bean
public ColorFactoryBean colorFactoryBean()
{
    return new ColorFactoryBean();
}

测试类

public class MainTest {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(PersonConfig.class);
//        Person person = context.getBean(Person.class);
//        System.out.println(person);
//        String[] names = context.getBeanNamesForType(Person.class);
//        Arrays.asList(names).forEach(System.out::println);

        String[] beanNames = context.getBeanDefinitionNames();
        Arrays.asList(beanNames).forEach(System.out::println);

        Object object = context.getBean("colorFactoryBean");
        System.out.println("类型:"+object.getClass().getName());
    }
}

本文基于尚硅谷Spring教学视频,在此感谢。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值