Spring注解-IOC(一)

基于xml配置文件的Spring运用:

  传统的Spring做法是使用xml文件来对bean进行注入或者是配置aop、事物,这么做有两个缺点:
  1、如果所有的内容都配置在xml文件中,那么.xml文件将会十分庞大;如果按需求分开.xml文件,那么.xml文件又会非常多。总之这将导致配置文件的可读性与可维护性变得很低。
  2、在开发中在.java文件和xml文件之间不断切换,是一件麻烦的事,同时这种思维上的不连贯也会降低开发的效率。

  //获取配置文件生成的IOC容器
  ApplicationContext applicationContext = 
      new ClassPathXmlApplicationContext("beans.xml");

  为了解决这两个问题,Spring引入了注解,通过"@XXX"的方式,让注解与Java Bean紧密结合,既大大减少了配置文件的体积,又增加了Java Bean的可读性与内聚性。

基于注解的Spring运用:

  @Configuration: 告诉Spring这是一个配置类,替代传统的xml配置文件,是配置类的最基本组件。在配置类中配合@Import、@Conditional、@Bean等等注解可以向容器中自定义的添加各类组件。

  //获取配置类生成的IOC容器
  ApplicationContext applicationContext = 
      new AnnotationConfigApplicationContext(MainConfig.class);

  @Import: 快速导入组件,包括配置类。
    1.Class : id默认是组件的全类名
    2.ImportSelector :返回需要导入的全类名数组
    3.ImportBeanDefinitionRegistrar :bean的定义注册器

  代码示例:
  1.定义三个将要被@Import导入的类

  public class Red extends Color{

  }
  /**
   * 自定义返回需要导入的组件
   */
  public class MySelector implements ImportSelector {
      //返回值就是要导入到容器中的组件全类名数组,
      //AnnotationMetadata:当前标注@Import注解的配置类的所有注解信息
      public String[] selectImports(AnnotationMetadata importingClassMetadata) {
          return new String[]{
              "com.atguigu.bean.ioc.Blue", "com.atguigu.bean.ioc.Yellow"
          };
      }
  }
    /**
     * 实现ImportBeanDefinitionRegistrar接口,使其拥有注册bean的功能
     * AnnotationMetadata:当前标注@Import注解的配置类的所有注解信息
     * BeanDefinitionRegistry:配置类对应的IOC容器注册器
     */
    public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            registry.registerBeanDefinition("yellow",new RootBeanDefinition(Yellow.class));
        }
    }
AnnotationMetadata:当前标注@Import注解的配置类的所有注解信息

BeanDefinitionRegistry :bean的定义注册器

  2.定义配置类

  @Configuration
  @Import({Red.class, MySelector.class, MyImportBeanDefinitionRegistrar.class})
  public class MainConfig {
 
  }

  3.测试

    @Test
    public void testScope(){
        ApplicationContext applicationContext = 
                 new AnnotationConfigApplicationContext(MainConfig.class);
        String[] beans = applicationContext.getBeanDefinitionNames();
        for (String bean : beans) {
            System.out.println(bean);
        }
    }

  @ImportResource: 向配置类中导入xml配置文件。

  @ComponentScan: 代替配置文件中的<context:component-scan base-package="com.atguigu"/>,定义扫描的路径从中找出标识了需要装配的类自动装配到IOC容器中。可以使用 includeFilters、excludeFilters 作为过滤规则。该注解是@Controller,@Service,@Repository,@Component注解使用的基础。

  @Bean:注入组件,默认的组件名为首字母小写的类的名称。代替配置文件中的<bean></bean>。@Bean标注的方法,IOC容器在创建对象的时候,参数直接从IOC容器中获取。

  @Scope:
    singleton:单实例,容器启动的时候直接创建单个对象放到IOC容器中。
    prototype:多实例,每次获取的时候才会创建对象。

  @Lazy:懒加载,针对单实例bean,容器启动不默认创建对象,第一次获取bean的时候才创建对象并初始化

  @Conditional:可标注在类上或者方法上,按照一定条件进行判断,满足条件给容器中注册bean,否则不对类或者方法做处理。此注解在Springboot的自动配置中有大量应用。

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
    /**
     * All {@link Condition}s that must {@linkplain Condition#matches match}
     * in order for the component to be registered.
     */
    Class<? extends Condition>[] value();
}

  从代码中可以看到,使用@Conditional 注解,需要传入一个Class数组,并且数组内元素需要实现Condition接口。
  如何运用呢?首先我们自定义两个Condition接口的实现类以及一个需要被按条件注入的bean组件。

  • 定义实现类
public class WindowCondition implements Condition {
    /**
     * ConditionContext: 上下文环境,包含容器的环境信息、注册器、资源加载器
     * AnnotatedTypeMetadata: 当前标注了@Condition注解的注释信息
     */
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {

        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        ClassLoader classLoader = context.getClassLoader();
        Environment environment = context.getEnvironment();
        BeanDefinitionRegistry registry = context.getRegistry();
        ResourceLoader resourceLoader = context.getResourceLoader();
        System.out.println(beanFactory);
        System.out.println(classLoader);
        System.out.println(environment);
        System.out.println(registry);
        System.out.println(resourceLoader);
        //判断是否window系统
        if (environment.getProperty("os").contains("Window")){
            return true;
        }
        return false;
    }
}
public class LinuxCondition implements Condition {

    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Environment environment = context.getEnvironment();
        String os = environment.getProperty("os");
        if (os.contains("linux")){
            return true;
        }
        return false;
    }
}
  • 定义将被按条件注册的实体bean
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Dept {
    private Integer deptNo;
    private String deptName;
}
  • 然后在配置类运用它。
@Configuration
@Import({Color.class, Red.class, MySelector.class, MyImportBeanDefinitionRegistrar.class})
@Conditional(WindowCondition.class)  //如果不满足条件,则配置类失效
@ComponentScan(value = "com.atguigu.ioc"
    ,includeFilters ={@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class,Repository.class})}
    ,useDefaultFilters = false)
public class MainConfig {

    /**
     * @Scope:单实例:容器启动的时候直接创建单个对象放到IOC容器中。多实例:每次获取的时候才会创建对象。
     * @Bean:给容器注册一个bean,类型为返回值类型,id默认是方法名,默认单例的。
     * @Lazy:懒加载,针对单实例bean,容器启动不默认创建对象,第一次获取bean的时候才创建对象并初始化
     */
    @Bean
    @Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
    @Lazy
    public Person person(){
        return new Person("李四",30,"设计师");
    }

    /**
     * @Conditional: 按照一定条件进行判断,满足条件给容器中注册bean
     */

    @Bean("window")
    public Dept dept01(){
        return new Dept(1001,"设计部");
    }

    @Bean("linux")  //@Bean标注的方法,IOC容器在创建对象的时候,参数直接从IOC容器中获取
    @Conditional(LinuxCondition.class)
    public Dept dept02(){
        return new Dept(1002,"开发部");
    }
}

  @PropertySource:加载指定配置文件。一般和@Value配合使用为IOC容器中的bean组件属性赋值。@PropertySource相当于在xml文件中配置:<context:property-placeholder location="classpath:score.properties"/>;@Value相当于<property name="name" value="${name}"/>

  • 在类路径下定义一个配置文件,score.properties
score.stuId=20100514
score.score=98
  • 在组件中,定义Score组件
@Data
@NoArgsConstructor
@AllArgsConstructor
@PropertySource("classpath:score.properties")  //加载配置文件
public class Score {

    @Value("${score.stuId}")    //通过el表达式为组件赋值
    private Integer stuId;

    @Value("${score.score}")
    private Integer score;
}
  • 定义配置文件,注入Score组件
@Configuration
@Import(Score.class)
public class MainConfigOfPropertyValue {

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

推荐阅读更多精彩内容