SpringBean应用之Bean的注册

一、包扫描@ComponentScan

@ComponentScan只会扫描有以下四种注解中某一注解的类,并管理他们把他们加载到上下文中
@Component:基本注解,标识了一个受Spring管理的组件,实际上只会扫描@Component,只是其他3个都继承于他
@Repository:标识持久层组件
@Service:标识服务层(业务层)组件
@Controller:标识表现层组件

他们可以混用,因为Spring还没有聪明到能判断我们写的代码是那一层的,但最好那一层的注解,就用那一层,因为未来有可能有别的寓意
对于扫描到的组件,Spring有默认的命名策略:使用非限定类名,第一个字母小写(如UserService其默认id就是:userService)。也可以在注解中通过value属性值标识组件的名称

@ComponentScan的属性

//定义包路径
String[] value() default {}
String[] basePackages() default {}
//指定dean生成器,默认BeanNameGenerator
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
//处理与检测到的bean的scope范围,默认AnnotationScopeMetadataResolver
Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class
//是否为检测到的组件生成代理
ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;
//控制符合组件检测条件的类文件   默认是包扫描下的  **/*.class
String resourcePattern() default ClassPathScanningCandidateComponentProvider.DEFAULT_RESOURCE_PATTERN;
//是否对带有@Component @Repository @Service @Controller注解的类开启检测,默认是开启的
boolean useDefaultFilters() default true;
//扫描到的类是都开启懒加载 ,默认是不开启的
boolean lazyInit() default false
//包扫描过滤与包括设置
Filter[] includeFilters() default {}
Filter[] excludeFilters() default {}

Filter信息说明

FilterType.ANNOTATION//注解类型 默认
FilterType.ASSIGNABLE_TYPE//指定固定类
FilterType.ASPECTJ//ASPECTJ类型
FilterType.REGEX//正则表达式
FilterType.CUSTOM//自定义类型

说明excludeFilters是过滤规则,是在基础规则上的进一步排除,includeFilters是包括,他和基础规则设置冲突,
基础规则会覆盖他,所以当我要使用includeFilters时应该使用useDefaultFilters=false禁用基础规则或者不定义

案例

//只扫描hello包下标注注解@Controller的类
@ComponentScan(
  value ={"hello”},
  useDefaultFilters = false,
  includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Controller.class)}
  )

二、在组件中定义@Bean元数据

设置别名,如果未指定,则bean的名称是带注释的方法的名称。如果指定,则忽略方法名,一个bean可以设置多个别名

@Configuration
@EnableWebMvc
public class WebConfig{
    @Bean
    public Son son(){
        return new Son();
    }
}

如果一个类注册了多个bean,我可以使用@Qualifier点名要那个bean

三、@Import

说明:只能标注在类上,属性是 Class<?>[] value()

1、导入一个bean
@Import(Person.class)
@Configuration 
public class App{}
public class Person {
}

其别名是“包名.类名”

2、导入@Configuration注解的配置类
@Import({TestConfig.class)
@Configuration
public class AppConfig {
}
@Configuration
public class TestConfig {
    @Bean
    public Person person(){
        return new Person();
    }
}

注意:这时候person的别名不是“包名.类名”,是和普通的一样,而TestConfig的别名是“包名.类名”

  • 注意:如果主配置类AppConfig中如下
@Import({TestConfig.class)
@Configuration
public class AppConfig {
   @Bean
    public Person person(){
        return new Person();
    }
}

TestConfig中的person方法不会执行,而AppConfig中的会,除非AppConfig的没有
@Import({TestConfig.class)可以将配置类TestConfig中的bean全部导入到AppConfig中

延深:TestConfig可以不加@Configuration
因为@improt会将导入的class加上@component注解从而被spring容器管理,自然的class下@bean标注方法返回的实例也会被添加到spring容器中。但是@configuration和@component下的@bean是有点区别的。@configuration标注的类,其方法会被代理执行

3、导入ImportSelector的实现类

ImportSelector是Spring中导入外部配置的核心接口

public class MyImport implements ImportSelector { 
@Override 
public String[] selectImports(AnnotationMetadata importingClassMetadata) { 
        return new String[]{"cn.dao.Color"}; } 
}
@Configuration  
@Import(MyImport.class) 
public class CarFactory { }

导入的Color的别名是cn.dao.Color 别名是“包名.类名”,

4、导入DeferredImportSelector的实现类
public interface DeferredImportSelector extends ImportSelector {

	default Class<? extends Group> getImportGroup() {
		return null;
	}

	interface Group {

		void process(AnnotationMetadata metadata, DeferredImportSelector selector);

		Iterable<Entry> selectImports();
	}
5、导入ImportBeanDefinitionRegistrar的实现类
public class MyImport implements ImportBeanDefinitionRegistrar { 
     @Override  //importingClassMetadata包含@import标注类的信息
     public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { 
       boolean sign = registry.containsBeanDefinition("car”);
       if(!sign){ 
           registry.registerBeanDefinition("color", new RootBeanDefinition(Color.class)); 
      } 
}
@Configuration
@Import(MyImport.class) 
public class CarFactory {
}

四、@Conditional

@Conditional是Spring4新提供的注解,它的作用是按照一定的条件进行判断,满足条件给容器注册bean,他可以标注在类和方法上
@Conditional中必须存放Condition类型

  • Condition是个接口,需要实现matches方法,返回true则注入bean,false则不注入。
public interface Condition {
    boolean matches(ConditionContext var1, AnnotatedTypeMetadata var2);
}

使用场景,当有2个bean,我们想根据一定条件注册,那么可以有这个注解

public class TrueCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return true;
    }
}
public class FalseCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return false;
    }
}
@Configuration 
public class Appruner {
    @Conditional({FalseCondition.class})
    @Bean
    public Persion persion1(){
        return new Persion();
    }
    @Conditional({TrueCondition.class})
    @Bean
    public Persion persion2(){
        return new Persion();
    }
}

结论:
1、这种情况下只有别名是persion2会加载
2、如果@Conditional中有多个Condition实现类,只有当其全部为true时才会加载

五、FactoryBean

实现FactoryBean,然后把它注册到配置类中

public interface FactoryBean<T> {
    String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType”;

    //返回的bean对象
    @Nullable
    T getObject() throws Exception;


   //bean的类型
    @Nullable
    Class<?> getObjectType();


   //是否是单列模式。默认是单列模式
    default boolean isSingleton() {
        return true;
    }
}

案例

@Configuration
public class App{
    @Bean
    public Config config(){
        return new Config();
    }
}
public class Config  implements FactoryBean<Persion> {

    @Override
    public Persion getObject() throws Exception {
        return new Persion();
    }

    @Override
    public Class<?> getObjectType() {
        return Persion.class;
    }

    @Override
    public boolean isSingleton() {
        return false;
    }
}

测试

ApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(App.class);
System.out.println(annotationConfigApplicationContext.getBean("config").getClass());
//class hello.Persion
//如果我们想获取工厂对象,可以这样写
System.out.println(annotationConfigApplicationContext.getBean("&config").getClass());
//class hello.Config

思考;为什么要有FactoryBean,Persion类直接用@bean注册,不就行了吗,为什么非要多此一举多创建一个bean Config
答:FactoyBean主要是方便我们对附加bean的实例的注册。如果一个对象在实例化时要做很多事情,那么我们直接写在配置文件中就显得很臃肿,而FactoyBean就好像一个java的工具方法,我们直接调用就可以用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值