Spring温故而知新 - bean的装配(续)

按条件装配bean

就是当满足特定的条件时Spring容器才创建Bean,Spring中通过@Conditional注解来实现条件化配置bean

package com.sl.ioc;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AnimalConfig {

    @Bean("dog")
    @Conditional(DogCondition.class)
    public Dog DogInstance() {
        return new Dog();
    }

    @Bean("cat")
    @Conditional(CatCondition.class)
    public Cat CatInstance() {
        return new Cat();
    }

}

@Conditional和 :Condition接口的实现

public @interface Conditional {

    /**
     * All {@link Condition}s that must {@linkplain Condition#matches match}
     * in order for the component to be registered.
     */
    Class<? extends Condition>[] value();

}
public interface Condition {

    /**
     * Determine if the condition matches.
     * @param context the condition context
     * @param metadata metadata of the {@link org.springframework.core.type.AnnotationMetadata class}
     * or {@link org.springframework.core.type.MethodMetadata method} being checked
     * @return {@code true} if the condition matches and the component can be registered,
     * or {@code false} to veto the annotated component‘s registration
     */
    boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);

}

Conditional注解通过value传入一个类,实现Condition接口,通过实现Condition接口中matches方法决定是否需要装配Bean,如果满足条件需要创建bean则返回true,否则返回false

自己定义两个继承Condition接口的类:通过ConditionContext查找当前环境中是否存在dog或者cat属性,如果存在,则创建对应的bean对象,具体实现如下:

package com.sl.ioc;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class DogCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Environment environment = context.getEnvironment();
        boolean flag= environment.containsProperty("dog");
        return flag;
    }
}
package com.sl.ioc;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class CatCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {

        Environment environment = context.getEnvironment();

        boolean flag= environment.containsProperty("cat");

        return flag;

    }
}
package com.sl.ioc;
import org.springframework.stereotype.Component;
@Component
public interface Animal {

    void Say();

}

package com.sl.ioc;import org.springframework.stereotype.Component;

@Component
public class Cat implements Animal {
    @Override
    public void Say() {
        System.out.println("I am a cat");
    }
}

package com.sl.ioc;
import org.springframework.stereotype.Component;

@Component
public class Dat implements Animal {
    @Override
    public void Say() {
        System.out.println("I am a dog");
    }
}

测试代码:

public class TestClass {

    @Test
    public void TestGetDoInstance() {

        System.setProperty("dog","");
    ApplicationContext context = new AnnotationConfigApplicationContext(AnimalConfig.class);

        String[] beanNames = context.getBeanDefinitionNames();

        for(String bean : beanNames) {

                System.out.println(bean);

        }
    }
}

运行测试可以看到输出的beanname中会包含dog的bean:

自动装配的歧义处理

Spring自动装配时如果存在多个bean能够匹配的话,那么这种情况会阻碍Spring通过属性、构造函数或方法进行装配。针对这种情况,Spring提供了多种 可选方案来解决这个问题,可以选择一个bean作为首选的bean,或者使用限定符来确定唯一bean

1:使用首选Bean

Spring提供@Primary注解来设置首选Bean,当初选自动装配歧义时,会选择装配带有@Primary的bean

沿用上面的示例代码,尝试装载animal

@Component
public class AnimalInstance {

    @Autowired
    public Animal animal;

}

当Spring尝试注入animal实例时,由于Dog和Cat都继承自Animal,所以此处产生了歧义,下面通过使用@Primary指定首选bean

@Component
@Primary   //指定首选bean
public class Cat implements Animal {
    @Override
    public void Say() {
        System.out.println("I am a cat");
    }
}

同样也可以使用XML配置来实现:<bean>元素提供了primary属性来设置首选bean

<bean id="cat"  class="com.sl.ioc.Cat" primary ="true" >

测试代码:

public class TestClass {
    @Test
    public void TestGetDoInstance() {
        //应用上下文

        ApplicationContext context = new AnnotationConfigApplicationContext(AnimalConfig.class);

        AnimalInstance animalInstance = context.getBean(AnimalInstance.class);
        animalInstance.animal.Say();
    }
}

运行结果:

首选项只是标识一个优先选择装载的bean,如果配置了多个@Primary,那么将带来新的歧义,Spring依然无法完成自动装配,可以通过下面限定符来解决这个问题

2:使用限定符

Spring提供@Qualifier注解来指定想要注入的具体bean。例如上面的示例,如果指定注入dog:

package com.sl.ioc;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component
public class AnimalInstance {

    @Autowired
    @Qualifier("dog")
    public Animal animal;

}

解释一下:@Qualifier("dog")表示指定的bean具有”dog”限定符,spring中bean如果没有指定限定符,会使用默认限定符,即使用beanID作为限定符。所以上面是恰好使用了dog bean的ID作为了限定符。也可以写成如下方式:

@Component
@Qualifier("specialdog")    //为bean指定限定符
public class Dog implements Animal
{
    @Override
    public void Say() {
        System.out.println("I am a dog");
    }
}
@Component
public class AnimalInstance {

    @Autowired
    @Qualifier("specialdog")    //使用上面定义的限定符
    public Animal animal;
}

Bean的作用域

Spring容器在创建bean实例的同时,还允许指定bean实例的作用域,常见作用域有一下几种:

1:单例作用域(Singleton)

2:原型作用域(Prototype)

3:会话作用域(Session)

4:请求作用域(Request)

5:全局会话作用域(globalSession)

Singleton作用域

在整个应用中,Spring IOC容器为使用singleton模式的bean只创建一个实例,Spring将会缓存Bean实例,任何对该类型beand请求都会返回该实例。单例也是Spring默认的作用域。具体使用如下,通过XML配置

<bean id="beanid"  class="com.sl.ioc.xxx" scope="singleton" ></bean>

<bean>元素提供了scope属性来设置singleton作用域

对应的注解:

@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)

Prototype原型作用域

每次注入或者从Spring容器中获取时都创建一个新的bean实例:

<bean id="beanid"  class="com.sl.ioc.xxx" scope="prototype" ></bean>

<bean>元素提供了scope属性来设置singleton作用域

对应的注解:

@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)

Session会话作用域

在web应用中,针对每个会话,Spring容器根据bean定义创建的bean实例,只在当前会话Session中有效,XML配置如下:

<bean id="beanid"  class="com.sl.ioc.xxx" scope="session" ></bean>

针对某个HTTP Session,Spring容器会根据bean定义创建一个新的bean实例,该bean仅在当前HTTP Session内有效。所以可以根据需要放心的更改bean实例的内部状态,而不影响其他Http Session中bean实例。当HTTP Session最终被废弃的时候,在该HTTP Session作用域内的bean也会被销毁掉。

Request 请求作用域

<bean id="beanid"  class="com.sl.ioc.xxx" scope="globalSession" ></bean>

在web应用中,针对每次请求,Spring容器根据bean定义创建新的bean实例,只在当前请求内有效

<bean id="beanid"  class="com.sl.ioc.xxx" scope="request" ></bean>

该bean实例只在当前请求内有效,在请求处理完成之后bean也会被销毁掉

globalSession全局会话作用域

类似于session作用域,只是其用于portlet环境的web应用。如果在非portlet环境将视为session作用域。

原文地址:https://www.cnblogs.com/ashleyboy/p/9000436.html

时间: 2024-08-29 16:45:39

Spring温故而知新 - bean的装配(续)的相关文章

Spring 之Bean的装配

Spring Bean的装配分为3中: 1.隐式发现和自动装配 @Component:将一个Java类声明为Bean(组件类),等待Spring扫描发现. @ComponentScan:启用组件扫描将带有@Component的类实例化为Bean,一般用在配置类上,可指定扫描基础包,默认与配置类相同的包. @Configuration:声明一个Java类是配置类,它与@Component作用相当,只是更为直观,一般@Bean与其连用. <context:component-scan base-pa

Spring笔记2——Spring中Bean的装配

1.引言 Spring中,对象无需自己负责查找或创建与其关联的其他对象,而是由容器负责把需要相互协作的对象引用赋予各个对象.创建应用对象之间的协作关系的行为通常称为装配(Wiring),这也是依赖注入的本质. 2.声明Bean 配置Bean的方式主要有两种:基于XML文件的配置方式和基于Java注解的配置方式.传统的基于XML文件的配置方式在声明Bean时,Spring配置文件的根元素来源于Spring beans命名空间所定义的<beans>元素.除了beans命名空间外,Java自带了多种

&lt;Spring实战&gt;2:装配Bean

1 声明Bean 1.1 创建 Spring 配置 Spring 容器提供两种配置 Bean 的方式:xml 配置和基于注解配置. Spring 配置文件: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/

Spring实战3:装配bean的进阶知识

主要内容: Environments and profiles Conditional bean declaration 处理自动装配的歧义 bean的作用域 The Spring Expression Language 在装配bean—依赖注入的本质一文中,我们探讨了Spring的三种管理bean的方式:自动装配.基于JavaConfig.基于XML文件.这篇文字将探讨一些Spring中关于bean的管理的高级知识,这些技能你可能不会每天都用,但是非常重要. 3.1 Environments

Spring之IOC&amp;DI/装配Bean(一)

简介 今天学习Spring的第一天,无非也就是入门基础知识.主要了解IOC和DI部分,要熟练掌握哦~ Spring简介 1. Spring介绍 Spring是一个非常活跃的开源框架:它是一个基于Core来构架多层JavaEE系统的框架,它的主要目地是简化企业开发. Spring以一种非侵入式的方式来管理你的代码,Spring提倡"最少侵入",这也就意味着你可以适当的时候安装或卸载Spring 2. Spring框架的优势 ?方便解耦,简化开发 ?Spring就是一个大工厂,可以将所有对

Spring bean依赖注入、bean的装配及相关注解

依赖注入 Spring主要提供以下两种方法用于依赖注入 基于属性Setter方法注入 基于构造方法注入 Setter方法注入 例子: public class Communication { private Messaging messaging; /* * DI via Setter */ public void setMessaging(Messaging messaging){ this.messaging = messaging; } public void communicate(){

Spring 实战-第二章-装配Bean

Bean是Spring对象的声明(装配wiring),要使用Spring,必须先装配需要使用的对象,有3种装配的方式 自动化装配Bean 通过Java代码装配 通过XML装配 自动化装配Bean 自动化装配Bean很简单 1.声明接口 package soundsystem; public interface CompactDisc { void play(); } 2.添加注解 package soundsystem; import org.springframework.stereotype

Spring学习总结之装配bean

1.  XML中显式配置 规范,文件头: <?xml version="1.0" encoding="UTF-8"?>            <beans xmlns=http://www.springframework.org/schema/beans                     xmlns=http://www.w3.org/2001/XMLSchema-instance                     xsi:schema

Spring -- Bean自动装配&amp;Bean之间关系&amp;Bean的作用域

Bean的自动装配 Spring IOC 容器可以自动装配 Bean. 需要做的仅仅是在 的 autowire 属性里指定自动装配的模式 有以下几种自动装配的类型: byType(根据类型自动装配): 若 IOC 容器中有多个与目标 Bean 类型一致的 Bean. 在这种情况下, Spring 将无法判定哪个 Bean 最合适该属性, 所以不能执行自动装配. byName(根据名称自动装配): 必须将目标 Bean 的名称和属性名设置的完全相同. constructor(通过构造器自动装配):