spring注解驱动开发(二):spring中的@Lazy、@Scope、@Conditional注解
上一篇讲了@Bean、@Configuration、@ComponentScan,通过这三个注解,我们可以完成基本的容积组件的注册,这篇是上一篇的深入,是对注入到容器中的bean做更一步的认识。包括bean的作用范围、加载时机以及在什么条件下祖册bean。
1. bean的作用范围,使用@Scope调整作用域
在spring中注入的实例默认是单实例:
* singleton:单实例,初始化容器会实例化bean,并将bean放入到容器中,等下次获取直接到容器中获得。
* prototype:多实例,初始化容器不会实例化bean,每次获得bean时候就会初始化bean,每次获得的bean会不同。
* request:同一次请求创建一个实例。
* session:同一次session同一个实例。
代码演示:
新建配置类代码,User对象和之前的User对象一致,指定姓名和年龄。
@Configuration public class MainConfig02 { /** * * @see ConfigurableBeanFactory#SCOPE_PROTOTYPE * * @see ConfigurableBeanFactory#SCOPE_SINGLETON 默认 * * @see org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST * * @see org.springframework.web.context.WebApplicationContext#SCOPE_SESSION * @return * String SCOPE_SINGLETON = "singleton"; * String SCOPE_PROTOTYPE = "prototype"; * request:同一次请求创建一个bean * session:同一次会话创建一个bean * */ @Bean @Scope("prototype") public User user(){
System.out.println("创建user------"); return new User("zhangsan",12); } }
新建测试类
@Test public void testScope() { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig02.class); User u1 = (User)applicationContext.getBean("user");//1 User u2 = (User)applicationContext.getBean("user");//2 System.out.println(u1==u2);//3 }
输出的结果是false,当吧@Scope中的参数修改为single是返回为true.
2. @Scope小结
1)看出@Scope可以控制bean的作用域,single表示容器启动到关闭期间只会生成一个bean而scope表示每一次请求会产生不同的bean。
2)注释特使类中的1、2、3行,在@Scope("single")时,控制台会打印创建user,在@Scope("Scope")时,并不会打印创建user,打开测试类1处注释,这时候说明单实例bean是在容器创建的时候创建好对象并放入到IOC容器,多实例bean要在使用bean的时候才会创建对象。
3. @Lazy延迟加载
容器创建的时候全部初始化单实例bean会拉长项目启动时间,单实例bean如果在容器创建没有用到,在初始化不让其实例化:
@Lazy,单实例在容器初始化的时候创建对象,懒加载是容器初始化时候不创建对象,等到使用该bean的时候再创建对象。
在单实例bean上使用@Lazy,可以使单实例bean在容器创建的时候不被初始化,只有在使用bean实例化。
可以在单实实例user上加上@Lazy注解,注释测试中getBean()方法,初始化容器不会打印 创建user。在getBean执行的时候,打印这句话,说明bean延迟初始化。
4. @Conditional 条件注入bean
@Conditional 满足一定条件将bean注册到容器中。在springboot大量使用,例如注解ConditionalOnMissingBean。
@Conditional参数是实现Condition接口得类,如果想使用@Conditional,需要自定义类并实现Condition接口。
代码示例。
新建条件类实现Condition接口
public class LinuxCondition implements Condition { /** * * @param context 上下文环境,可作为判断条件 * @param metadata 注释信息 * @return */ @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { //获得当前IOC使用的bean工厂 context.getBeanFactory(); //获得类加载器 context.getClassLoader(); //获取当前环境信息 Environment environment = context.getEnvironment(); //获取bean的注册类,可以注册、移除bean BeanDefinitionRegistry registry = context.getRegistry(); // registry.containsBeanDefinition(""); 判断容器中包含bean String property = environment.getProperty("os.name"); if(property.contains("linux")) return true; return false; } }
public class WindowsCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { //获取当前环境信息 Environment environment = context.getEnvironment(); String property = environment.getProperty("os.name"); if(property.contains("Windows")) return true; return false; } }
测试类新增测试方法,根据os.name的值来选择需要注册的组件。
@Test public void testCondition(){ ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig02.class); String property = applicationContext.getEnvironment().getProperty("os.name"); System.out.println(property); Map<String, User> beansOfType = applicationContext.getBeansOfType(User.class); System.out.println(beansOfType); }
@Conditional 放在方法上,表示当前bean按照条件判断
@Conditional 放在类上,表示当前类中的所有方法生成的bean按照条件判断,是对类的统一设置
可以设置虚拟机启动参数-Dos.name=linux,来指定运行环境。

浙公网安备 33010602011771号