zoukankan      html  css  js  c++  java
  • 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作用域。

     

     

  • 相关阅读:
    为《理解C#中的System.In32和int:并非鸡和鸡蛋 》做个续
    Windows C++代码heap分析详解
    Windows 内存分析之路 How to use Resource Monitor
    给C++初学者的50个忠告(好文转载)
    The 32bit generalpurpose registers EAX, EBX, ECX, EDX, ESI, EDI, EBP, and ESP
    Exceptional C++ 精华代码—实现异常安全的Stack
    Windows开发的内功和招式
    Windows代码heap内存分析实战
    十分钟让你对C++ Traits大彻大悟
    使用Windows API PostThreadMessage进行线程间消息通信
  • 原文地址:https://www.cnblogs.com/ashleyboy/p/9000436.html
Copyright © 2011-2022 走看看