共计 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 没有打印出来。