Spring应用于组件注册的注解

在将Spring框架应用于项目开发中时,繁多的xml配置文件会使项目的维护升级变得困难,特别是项目很大时,有时候会花掉大量的时间去定位相应的组件配置。为了解决这个问题,引入Spring框架中的强大注解变得很重要,同时,注解的学习更是为后期学习Spring Boot做好了铺垫。

@Configuration

@Configuration注解用于定义配置类,并用于构建bean定义,初始化Spring容器,被标注的类类似于Spring的xml配置文件中的beans标签。

@Bean

给容器注册一个Bean;类型为方法返回值类型,id不指定时默认使用方法名作为id。

@ComponentScan

配置自动扫描相应的包。会自动扫描包路径下面的所有@Controller、@Service、@Repository、@Component 的类。包含的属性如下:

  • value:指定扫描的包路径。接收String数组。
  • @Filter:声明扫描包的过滤规则,可以按注解、类型、正则表达式等进行过滤。

@ComponentScans

如果是JDK8以上可以声明多个@ComponentScan进行配置,也可以在@ComponentScans中配置多个@ComponentScan。

//配置类==配置文件
@Configuration //告诉spring这是一个配置文件
@ComponentScan(value="com.jt",/*excludeFilters*/ includeFilters = {
        @Filter(type=FilterType.ANNOTATION,classes={Controller.class,Service.class})},useDefaultFilters=false)//配置自动扫描相应的包
/*@ComponentScans(value = {
        @ComponentScan(value="com.jt",excludeFilters  = {
                @Filter(type=FilterType.ANNOTATION,classes={Controller.class,Service.class})})
})*/
/**@ComponentScan vaue:指定要扫描的包
 *excludeFilters = Filter[],指定扫描的时候按照什么规则排除哪些组件。
 *includeFilters = Filter[],指定扫描的时候只包含哪些组件。生效的前提是让useDefaultFilters
 *FilterType.ANNOTATION 按照注解
 *FilterType.ASSIGNABLE_TYPE 按照给定的类型
 *FilterType.ASPECTJ 使用ASPECTJ表达式
 *FilterType.REGEX 使用正则表达式
 *FilterType.CUSTOM 使用自定义规则(需要实现TypeFilter接口)
 * 
 */
public class MainConfig {

    //给容器注册一个Bean;类型为返回值类型,id不指定时默认使用方法名作为id
    @Bean("person1")
    public Person person(){
        return new Person("lishi",20);
    }
    
}

@Scope

控制Bean的作用范围。

@Lazy

懒加载。

   /**默认是单实例的
     * prototype:多实例:ioc容器启动时并不会去调用方法创建对象,
     *                 而是每次获取的时候才调用方法去创建对象。
     * singleton:单实例(默认值):ioc容器启动时会调用方法创建对象并放入容器中。
     *                                                  以后每次获取是直接从容器(map.get())中获取。
     * request:同一次请求创建一个实例
     * session:同一个session创建一个实例
     * 
     * 
     * 懒加载:对于单实例的Bean,默认容器启动的时候创建对象;
     *       懒加载就是容器启动的时候不创建对象,而是第一次获取(map.get())对象时才初始化对象。
     * */
    @Scope("prototype")
    @Lazy
    @Bean("person")
    public Person person(){
        System.out.println("获取Person....");
        return new Person("张三",25);
    }

@Conditional(条件注解)

标注在方法上时,按照一定的条件进行动态转配,满足条件才给容器中注册Bean。标注在配置类上时,满足当前条件,这个类配置中的所有Bean才能生效。其中这个条件类必须实现Condition接口。

    /**
     * @Conditional({Condition}):按照一定的条件进行动态转配,满足条件才给容器中注册Bean
     * 
     * 如果系统是Windows,给容器中注册bill
     * 如果系统是Linux,给容器中注册Linus
     * 
     * */
    @Conditional({WindowsCondition.class})
    @Bean("bill")
    public Person person01(){
        return new Person("Bill Gates",60);
    }
    
    @Conditional({LinuxCondition.class})
    @Bean("linus")
    public Person person02(){
        return new Person("linus",40);
    }
//判断对象是否是linux
public class LinuxCondition implements Condition{

    /**
     * ConditionContext:判断条件能使用的上下文(环境)
     * AnnotatedTypeMetadata:标注了@Conditional的注释信息
     * */
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        //判断是否Linux系统
        //常用方法
        //1、能获得IOC使用的BeanFactory
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        //2、能获取到类加载器
        ClassLoader classLoader = context.getClassLoader();
        //3、获取当前环境信息
        Environment environment = context.getEnvironment();
        //4、获取到Bean定义的注册类
        BeanDefinitionRegistry registry = context.getRegistry();
        //判断容器中Bean的注册情况,也可以给容器注册Bean
        boolean difinition = registry.containsBeanDefinition("person");
        String property = environment.getProperty("os.name");
        if(property.contains("linux")){
            return true;
        }
        return false;
    }

}
//判断系统是否是windows
public class WindowsCondition implements Condition{

    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // 判断是否Windows
        Environment environment = context.getEnvironment();
        String property = environment.getProperty("os.name");
        if(property.contains("Windows")){
            return true;
        }
        return false;
    }

}
@Import

快速给容器中注册组件。id默认是全类名。

@Import({Color.class})//@Import导入组件,id默认是组件的全类名
public class MainConfig2 {
    //...
}
  • ImportSelector:如果某个类实现了ImportSelector接口,通过重写接口中的方法selectImports,可以将需要注册的类的全类名返回给@Import注解,并实现批量注册。
@Import({MyImportSelector.class})//@Import导入组件,id默认是组件的全类名
public class MainConfig2 {
    //.....
}
//自定义逻辑返回需要导入的组件
public class MyImportSelector implements ImportSelector{

    //返回值就是要注册到容器中的组件
    //AnnotationMetadata:当前标注@Import注解的类的所有注解信息
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        // TODO Auto-generated method stub
        //可以返回空数组,但是不能是null,否则会包空指针异常。
        return new String[]{"com.jt.bean.Color","com.jt.bean.Red"};
    }

}
  • ImportBeanDefinitionRegistrar:手动注册Bean到容器中。
@Import({MyImportSelector.class,MyImportBeanDefinitionRegistrar.class})//@Import导入组件,id默认是组件的全类名
public class MainConfig2 {
    //...
}
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    /**
     * AnnotationMetadata:当前类的注解信息
     * BeanDefinitionRegistry:BeanDefinition注册类;
     *                           把所有需要添加到容器中的Bean,调用
     *                        BeanDefinitionRegistry.registerBeanDefinition手工注册进容器
     * */
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        //定义注册Bean的条件
        boolean difinition = registry.containsBeanDefinition("com.jt.bean.Red");
        if(difinition){
            //指定Bean的定义信息(Bean的类型,Bean的作用域...)
            RootBeanDefinition paramBeanDefinition = new RootBeanDefinition(RainBow.class);
            //注册一个bean,指定bean的别名
            registry.registerBeanDefinition("com.jt.bean.RainBow", paramBeanDefinition);
        }
    }

}

使用FactoryBean注册组件

Spring提供了一个org.Springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化bean的逻辑。

@Bean
public ColorFactoryBean colorFactoryBean(){
    return new ColorFactoryBean();
}
//创建一个Spring定义的FactoryBean
public class ColorFactoryBean implements FactoryBean<Color>{

//返回一个Color对象,这个对象会注册到容器中
public Color getObject() throws Exception {
    // TODO Auto-generated method stub
    System.out.println("ColorFactoryBean...getObject()...");
    return new Color();
}

public Class<?> getObjectType() {
    // TODO Auto-generated method stub
    return Color.class;
}

//是否单实例
//true:这个bean是单实例,在容器中保存一份
//false:多实例,每次获取都会创建一个新的bean
public boolean isSingleton() {
    // TODO Auto-generated method stub
    return true;
}

}
@Test
public void testImport(){
    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
    printBeans(applicationContext);
    //工厂Bean获取到的是调用getObject()创建的对象
    Object object = applicationContext.getBean("colorFactoryBean");
    Object object2 = applicationContext.getBean("colorFactoryBean");
    System.out.println(object);
    System.out.println(object == object2);
    
    //获取colorFactoryBean本身
    Object object3 = applicationContext.getBean("&colorFactoryBean");
    System.out.println(object3);
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,198评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,663评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,985评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,673评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,994评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,399评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,717评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,407评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,112评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,371评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,891评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,255评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,881评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,010评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,764评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,412评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,299评论 2 260

推荐阅读更多精彩内容