spring学习之bean的定义

4次阅读

共计 2903 个字符,预计需要花费 8 分钟才能阅读完成。

除了 @Bean 定义 bean 以外,spring 还提供了其他的定义形式。

@Component、@Repository、@Service、@Controller 和 @Configuration

@Component 是 spring 定义 bean 的通用注解,@Repository、@Service 和 @Controller 等注解,都是继承 @Component。
@Repository 用于持久层,@Service 用于服务层,@Controller 用于控制层。
如果仅仅只是为了定义 bean,随便用哪个都可以,但是为了的区分用于哪个场景,以及未来 spring 的扩展,还是用对应场景的注解。
@Configuration 主要场景是当作配置文件,引入 bean,比如之前的测试代码,都是用 @Configuration 来做配置文件。
默认是第一个小写的 class 名,如果想自定义,可以在括号后面定义自己想要的名称,比如@Service("abc")
MyConfig,ComponentScan 注解后面讲,就是扫描包的路径。

@Configuration
@ComponentScan(value="com.learn.annotation")
public class MyConfig {}

MyComponent

@Component
public class MyComponent {}

其他注解雷同,这边不做重复。
测试代码:

@Test
public void test(){ApplicationContext app =  new AnnotationConfigApplicationContext(MyConfig.class);
    System.out.println(app.getBean("myConfig"));
    System.out.println(app.getBean("myDao"));
    System.out.println(app.getBean("myComponent"));
    System.out.println(app.getBean("myService"));
    System.out.println(app.getBean("myController"));
}

运行结果:

@import

在 XML 配置文件中,用的是 <import> 标签,在注解中,用 @import 注解。可以 import 普通 bean,也可以引入配置 bean。
这种方法简化了容器实例化,因为只需要处理一个类,而不需要在构造期间记住大量的 @Configuration 类。
MyConfig

@Configuration
@Import({MyComponent.class,MyService.class,MyDao.class,MyController.class})
public class MyConfig {}

测试方法:

@Test
public void test(){ApplicationContext app =  new AnnotationConfigApplicationContext(MyConfig.class);
    String[] names = app.getBeanDefinitionNames();
    for (String name : names) {System.out.println(name);
    }
}

运行结果:

虽然 AnnotationConfigApplicationContext 只引入了 MyConfig.class,但是 MyConfig 中 import 了多个类,所以都打印了出来。与 @Bean 不同的是,bean 的 id 是全类名。

ImportSelector

除了 @import 注解,也可以通过实现 ImportSelector 接口来引入类。
MyConfig

@Configuration
@Import(MyImportSelector.class)
public class MyConfig {}

MyImportSelector

public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {return new String[]{"com.learn.annotation.MyComponent","com.learn.annotation.MyService"};
    }
}
@Test
public void test(){ApplicationContext app =  new AnnotationConfigApplicationContext(MyConfig.class);
    String[] names = app.getBeanDefinitionNames();
    for (String name : names) {System.out.println(name);
    }
}

运行结果如下:

注意的是,MyImportSelector 并没有在容器中。

@Conditional

当我们根据不同的场景,比如是否实例化一个 bean、根据不同环境变量实例化某些不同参数的 bean 等,我们可以用 @Conditional 这个注解。
下面模拟一个简单的例子,如果 bean 的名称是 one 就实例化,除非不实例化。
MyConditional

public class MyConditional implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {StandardMethodMetadata standardMethodMetadata = ((StandardMethodMetadata) annotatedTypeMetadata);
        return standardMethodMetadata.getMethodName().equals("one");
    }
}

MyConfig

@Configuration
public class MyConfig {@Bean()
    @Conditional(MyConditional.class)
    public One one(){return new One();
    }

    @Bean()
    @Conditional(MyConditional.class)
    public Two two(){return new Two();
    }
}

测试代码

@Test
public void test(){ApplicationContext app =  new AnnotationConfigApplicationContext(MyConfig.class);
    String[] names = app.getBeanDefinitionNames();
    for (String name : names) {System.out.println(name);
    }
}

运行结果如下:

可以看出,two 这个 bean 没有打印出来。

正文完
 0