前一章节主要介绍了基础的配置注解以及包扫描注解。本章将继续介绍
- 作用域
- 懒加载
- 条件注入












我是分隔符 













一、作用域
bean的作用域有以下几类:
- singleton:单例作用域,从spring容器创建到最后的销毁,每一个bean只有一个对应的bean对象在容器当中。
- prototype:原型作用域,每一次使用时,都重新创建一个新的bean对象进行使用。
- request:在一次request请求当中,每一个bean只有一个对应的bean对象被创建。专用于web作用域上下文。
- session:在同一个session中,每一个bean只有一个对应的bean对象被创建。专用于web作用域上下文。
- globalSession:类似于标准的HTTP Session作用域,不过它仅仅在基于portlet的web应用中才有意义。专用于web作用域上下文。
本次主要以前两种作用域举例
基础模型:
public class Book {
private int id;
private String name;
public Book(int id) {
this.id = id;
}
public Book(int id, String name) {
System.out.println("book bean created。。");
this.id = id;
this.name = name;
}
//此处忽略n行 setter、getter
}举例用到的测试类
public class TestBean {
public static void main(String[] args) {
//通过注解的方式获取对应的bean
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
Book book1 = applicationContext.getBean(Book.class);
Book book2 = applicationContext.getBean(Book.class);
System.out.println(book1 == book2);
}
}1. singleton作用域
单例是bean的默认作用域,在没有特别声明的情况下,就是以单例作用域进行的。
//配置类==配置文件
@Configuration //告诉spring这是一个配置类
public class SpringConfig {
//单例为默认作用域,Scope注解可加可不加
//@Scope("singleton")
@Bean
public Book book() {
return new Book(1, "123");
}
}运行测试类,得出结果:
book bean created。。
true
可以发现当容器启动后,不管我们获取几次book对象,只创建一次book对象,并且需要再次获取时,使用之前已创建的对象。
我们再做个实验:
public class TestBean {
public static void main(String[] args) {
//通过注解的方式获取对应的bean
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
}
}单纯的只是去创建对应的配置类对象,再次运行测试类:
book bean created。。
在配置类中定义的对象也被创建了,也就是说在单例模式下,bean对象的创建和实例化默认是在容器创建完之后就进行的。
2. prototype作用域
在bean上加上注解@Scope并且作用域prototype:
//配置类==配置文件
@Configuration //告诉spring这是一个配置类
public class SpringConfig {
@scope("prototype")
@Bean
public Book book() {
return new Book(1, "123");
}
}再次运行TestBean测试类,得出结果:
book bean created。。
book bean created。。
false
可以发现在获取两次book对象时,都重新创建了一个新的book对象。
让我们再去进行一次之前的小实验,单纯的只是实例化一个配置类:
public class TestBean {
public static void main(String[] args) {
//通过注解的方式获取对应的bean
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
}
}不出意外的发现
,它的结果什么都没有打印,命令行中只有如下内容:
Process finished with exit code 0也就是说在prototype作用域下,容器启动后,该对象并不会被创建,而是在使用时才会进行创建。
二、懒加载
懒加载,顾名思义就是很懒的加载方式-能多迟就多迟,使用的时候才加载。
以前面讲的Book bean对象为例,作用域使用默认的单例模式(不过懒加载@Lazy也只适用于单例作用域):
//配置类==配置文件
@Configuration //告诉spring这是一个配置类
public class SpringConfig {
/**
* lazy 懒加载:只适用于单例,在容器创建的时候不创建bean,在第一次使用的时候在创建
* @return
*/
@Lazy
@Bean
public Book book() {
return new Book(1, "123");
}
}再次运行测试类:
public class TestBean {
public static void main(String[] args) {
//通过注解的方式获取对应的bean
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
Book book1 = applicationContext.getBean(Book.class);
Book book2 = applicationContext.getBean(Book.class);
System.out.println(book1 == book2);
}
}结果为:
book bean created。。
true
和之前的单例一样,只会创建一个book对象
那么此时这个book对象的实例化是什么时候进行的呢?
我们将上述结果结合下述实验进行研究:
public class TestBean {
public static void main(String[] args) {
//通过注解的方式获取对应的bean
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
}
}此时我们只是单纯的实例化对应的配置类,再次启动测试类,可以发现输出结果和之前的单例作用域的实验不同,book bean created不见了,只输出了:
Process finished with exit code 0也就是说,在单例作用域中如果使用了懒加载,那么bean的实例化是在第一次使用对应bean时进行的,之后遵循单例规则,再次使用时,会使用之前已经实例化好后的对象。
三、条件注入
针对spring的bean对象注入,还可以根据自定义的条件进行判断是否进行注入,对应的注解为Conditional,其定义如下:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
Class<? extends Condition>[] value();
}即可以通过实现Condition接口来自定义bean的过滤条件。
举栗
正式开始:
针对Person类:
public class Person {
private int age;
private String name;
public Person() {
}
public Person(int age, String name) {
this.age = age;
this.name = name;
}
//此处忽略n行 setter、getter
@Override
public String toString() {
return "Person{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}我们需要根据代码的运行环境为Windows系统还是Linux系统来实例化不同的person bean对象。则我们可以定义两个条件:
/**
* spring Windows环境条件过滤器,返回true时才注册对应的bean
*/
public class WindowsCondition implements Condition {
/**
*
* @param conditionContext 条件能使用的上下文
* @param annotatedTypeMetadata 注释信息
* @return
*/
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
//能获取到IOC使用的bean工厂
//ConfigurableBeanFactory beanFactory = conditionContext.getBeanFactory();
//能获取到类加载器
//ClassLoader ca = conditionContext.getClassLoader();
//获取到bean定义的注册类
//BeanDefinitionRegistry definitionRegistry = conditionContext.getRegistry();
//能获取到当前环境
Environment environment = conditionContext.getEnvironment();
String name = environment.getProperty("os.name");
if (name.contains("Window")) {
//当系统名称包含Window时才说明匹配
return true;
}
return false;
}
}/**
* spring linux环境条件过滤器,返回true时才注册对应的bean
*/
public class LinuxCondition implements Condition {
/**
*
* @param conditionContext 条件能使用的上下文
* @param annotatedTypeMetadata 注释信息
* @return
*/
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
//能获取到IOC使用的bean工厂
//ConfigurableBeanFactory beanFactory = conditionContext.getBeanFactory();
//能获取到类加载器
//ClassLoader ca = conditionContext.getClassLoader();
//获取到bean定义的注册类
//BeanDefinitionRegistry definitionRegistry = conditionContext.getRegistry();
//能获取到当前环境
Environment environment = conditionContext.getEnvironment();
String name = environment.getProperty("os.name");
if (name.contains("Linux")) {
//当系统名称包含Linux时才说明匹配
return true;
}
return false;
}
}在配置类中配置对应bean时,加入对应注入条件:
//配置类==配置文件
@Configuration //告诉spring这是一个配置类
public class SpringConfig {
@Conditional(WindowsCondition.class)
@Bean("bill")
public Person person02() {
return new Person(68, "bill");
}
@Conditional(LinuxCondition.class)
@Bean("linus")
public Person person03() {
return new Person(48, "linus");
}
}Windows环境运行对应测试类:
public class TestBean {
public static void main(String[] args) {
//通过注解的方式获取对应的bean
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
String[] beanNames = applicationContext.getBeanDefinitionNames();
for (String name : beanNames) {
System.out.println(name);
}
}
}运行结果:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
springConfig
bill
可以发现在Windows环境下,只有实例化了内容为bill的person对象。
另外@Conditional注解也可以直接使用在配置类上,表明配置类中的所有bean只在某个条件下注入。