Spring-bean的装配方式

529 阅读3分钟

这是我参与更文挑战的第21天,活动详情查看: 更文挑战

先看一下springbean实例化流程图: 77

接下来主要讲解上图中装配的部分

xml

<bean id="user"  class="com.mandy.bean.User"/>

容器加载xml

ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");

@ImportResource

@ImportResource("spring.xml")
public class AppConfig {
 
}

容器加载

ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

以上上述两种方式本质都xml的解析方式。

实现FactoryBean

public class MyFactroyBean  implements FactoryBean {
   @Override
   public Object getObject() throws Exception {
      return new User();
   }
 
   @Override
   public Class&lt;?&gt; getObjectType() {
      return User.class;
   }
}

原理是Spring中存在两个关于FactoryBean的Map factoryBeanObjectCache 通过getObject 获取bean allBeanNamesByType 通过getObjectType 获取bean

@Component+@ComponentScan

@ComponentScan默认扫描:@Component,@Repository,@Service,@Controller

@ComponentScan("com.mandy")
public class AppConfig {
}
 
//容器加载
 ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

@ComponentScan注解扩展用法 有三种过滤方式 注解,类型,自定义过滤规则 排除用法 excludeFilters

@ComponentScan(basePackages = "com.mandy",excludeFilters = {
    @ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Service.class}),
    @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value = {User.class})
})

包含用法 includeFilters

@ComponentScan(basePackages = "com.mandy",includeFilters = {
    @ComponentScan.Filter(type = FilterType.CUSTOM,value = {CustomTypeFilter.class})
},useDefaultFilters = false)

FilterType.CUSTOM在定义过滤规则

public class CustomTypeFilter implements TypeFilter {
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        if (classMetadata.getClassName().contains("Service")) {
            return true;
        }
        return false;
    }
}

@Bean+ @Configuration

@Configuration
public class AppConfig {
 
    @Bean
    public User user(){
        return new User();
    }
 
    @Bean
    public UserService userService(){
        // 调用其他@Bean方法
        return new UserService(user());
    }
}

@Configuration的作用:

1.表明当前类是一个配置类,是方法bean的源

2.将@Configuration配置的AppConfig的BeanDefinitioin属性赋值为full类型,保证AppConfig类型可以转变为cglib类型

3.将@Configuration配置的AppConfig由普通类型转变为cglib代理类型,最后会生成cglib代理对象,通过代理对象的方法拦截器,可以解决AppConfig内部方法bean之间发生依赖调用的时候从容器中去获取,避免了多例的出现。

使用场景

零xml配置,推荐使用,spring boot自动配置中大量使用@Bean xxxAutoConfiguration

@Import

@Import(value = MyImportBeanDefinitionRegistrar.class)
public class AppConfig {
}

ImportSelector

其主要作用是收集需要导入的配置类,如果该接口的实现类同时实现EnvironmentAware, BeanFactoryAware ,BeanClassLoaderAware或者ResourceLoaderAware,那么在调用其selectImports方法之前先调用上述接口中对应的方法,如果需要在所有的@Configuration处理完在导入时可以实现DeferredImportSelector接口。

//实现 ImportSelector接口
public class MyImportSelector implements ImportSelector {
   @Override
   public String[] selectImports(AnnotationMetadata importingClassMetadata) {
      return new String[]{Fox.class.getName()}; 
   }
}

ImportBeanDefinitionRegistrar

因为它含有BeanDefinitionRegistry注册器,所以利用它可以在Spring定义BeanDefinition,达到装配bean的作用

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
   @Override
   public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,BeanDefinitionRegistry registry) {
      //创建BeanDefinition
      RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Fox.class);
      // 注册到容器
      registry.registerBeanDefinition("fox",rootBeanDefinition);
   }
}

使用场景

中间件底层大量使用,和Spring集成的核心扩展技术

mybatis-spring.jar @MapperScan

spring boot @SpringBootApplication XXXAutoConfiguration

spring cloud @EnableEurekaServer @EnableCircuitBreaker @EnableFeignClients @EnableZuulProxy

@Conditional

@Conditional是Spring4新提供的注解,它的作用是按照一定的条件进行判断,满足条件给容器注册bean。

@Configuration
public class AppConfig {
  @Bean
  public Cat cat(){
     return new Cat();
  }
    
  @Bean
  @Conditional(value = MyConditional.class)
  public Fox fox(){
     return new Fox()
  }
}
 
public class MyConditional implements Condition {
   @Override
   public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
      if(context.getBeanFactory().containsBean("cat"))
         return true;
      return false;
   }
}

应用场景:

Spring boot 自动配置实现核心技术之一: 条件装配 ,Spring Boot进行了扩展

@ConditionalOnWebApplication:当前项目是 Web项目的条件下

@ConditionalOnBean:当容器里有指定 Bean 的条件下

@ConditionalOnMissingBean:当容器里没有指定 Bean 的情况下

@ConditionalOnClass:当类路径下有指定类的条件下

@ConditionalOnMissingClass:当类路径下没有指定类的条件下

@ConditionalOnProperty:指定的属性是否有指定的值