讲解bean的装配
自动化装配
注解配置
当使用@Configutation注解的类,则声明该类为一个配置类,与配置类有关的注解还有:
- @ComponentScan
- @ComponentScans
它们都是用来指定包扫描路径的,使用方法如下:
@Configuration
@ComponentScan("wang.ismy.spring")
public class Config {}
装配Bean
@Component // 将当前类对象放入容器
public class Bean {...}
@Component这个注解修饰的类,如果类路径在容器的扫描路径中(兄弟包以及子包),则该类会被容器创建对象
与之作用相同的注解还有:
- @Controller
- @Service
- @Repository
这些注解只是语义不同,作用都是一样的。
使用Bean
要使用这个Bean,我们首先需要创建一个容器:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
然后,我们可以从中获取Pojo这个类型的对象:
context.getBean(Pojo.class)
不仅可以使用Bean的类型获取Bean,也可以使用Bean的名称获取:
context.getBean("pojo");
生命周期方法
有时候,我们需要Bean在创建后或者销毁前做一些事情:我们可以使用以下两个注解来实现:
//创建后执行
@PostConstruct
public void init(){ System.out.println("init"); }
//销毁前执行
@PreDestroy
public void destroy(){ System.out.println("destroy"); }
需要注意的是,这两个注解都不是Spring提供的,它是JAVA EE的标准,在使用的时候需要添加相关依赖
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
自动注入
Spring提供了一个最核心的功能就是依赖注入,也就说,Spring帮我们处理了各个对象之间的依赖关系,当一个对象创建时,Spring会找到这个对象所需要的依赖进行注入,我们只需要在要进行依赖注入的地方做一个标记即可,这个标记就是@Autowired
@Component
public class Bean {
private Bean1 bean1;
@Autowired
public Bean(Bean1 bean1) {
this.bean1 = bean1;
}
public void say(){
System.out.println("hi");
bean1.run();
}
}
这个注解不仅能加在构造函数上,也能放在成员变量、setter方法。
不过如果Bean只有一个构造函数,则可以省略这个注解。
JAVA代码注入
由于某些类来源于外部,我们无法修改其源码 所以可以使用java代码的方式创建后注入
@Configuration
public class Config {
@Bean
public Bean1 bean1(){return new Bean1();}
}
处理自动装配歧义性
在使用容器的时候,难免会遇到需要同类不同实例的对象,那么这时候又该怎么办?
解决方法有两个:
- 从生产方解决
- 从消费方解决
@Bean
@Primary // 标示首选bean
public Bean1 bean1(){
Bean1 bean1 = new Bean1();
bean1.setName("pro");
return bean1;
}
@Autowired
@Qualifier("bean1f") // 当有多个可选项时,将使用名为bean1f的bean
public void setBean1(Bean1 bean1){}
Bean的作用域
- singleton:单例,即在整个容器中只会有一个同类型对象
- prototype:每次获取都会创建实例
- session:每个会话一个bean(此处的会话指web容器的会话Session)
- request:每个请求一个bean(web容器的Request)
- global session:应用在Portlet环境.如果没有Portlet环境那么globalSession相当于session
条件装配
可能我们的Bean并不是每次都需要创建,那么则可以使用条件化装配
@Bean
@Conditional(MyConditional.class)
public Bean1 bean1(){
Bean1 bean1 = new Bean1();
bean1.setName("pro");
return bean1;
}
只要实现Condition接口,就可以控制Bean的创建与否
public class MyConditional implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return true;
}
}
运行时值注入
在运行时,我们可能需要外部配置文件的一些值,我们可以先通过配置类注入配置文件
@Configuration
@ComponentScan(basePackages = "wang.ismy.spring")
@PropertySource("classpath:config.properties")
public class Config { }
在Bean中,可以使用@Value注解注入值
@Component
public class Bean {
@Value("${name}")
String name;
}
SPEL
Spring Expression Language(Spring表达式),是一种类似于脚本语言的东西,我们可以通过在@Value中写一些字符串以此来达到语言级的能力:
@Value("#{T(System).currentTimeMillis()}") // 获取当前时间
long time;
导入配置
使用@Import可导入其他配置类
@Configuration
@Import({DevConfig.class,ProConfig.class})
public class MasterConfig { }
配置环境
在开发与测试或者生产环境,很多配置都是不一样的,如果需要频繁地改,那会是很麻烦的,我们可以为配置指定一个环境,在不同的场景启用不同的环境
@Configuration
@Profile(("dev")) // 开发环境配置
public class DevConfig {}
@Configuration
@Profile("pro") // 生产环境配置
public class ProConfig {}
我们需要一个主配置,导入所有的配置:
@Configuration
@Import({DevConfig.class,ProConfig.class})
public class MasterConfig { }
在使用注解上下文时,我们使用这个主配置为引导类
激活
方法有两种,一是设置环境变量,二是手动编码
System.setProperty("spring.profiles.active","dev"); // 通过设置环境变量
// 手动编码设置
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.getEnvironment().setActiveProfiles("dev");
context.register(MasterConfig.class);
context.refresh();