zoukankan      html  css  js  c++  java
  • Bean的高级装配

    配置profile bean

    针对不同的环境需要配置不同的bean,Spring提供的解决方案是bean profile功能。首先将所有不同的bean定义到一个或多个profile中,然后根据激活的profile来决定创建哪个bean。

    @Profile注解指定bean属于哪一个profile,只有该profile激活时,该bean才能被创建。

    @Profile可以被用在类级别上,也可以用在方法级别上。

    @Configuration
    public class DataSourceConfig {

    @Profile("dev")
    public DataSource embeddedDataSource() {
    }

    @Profile("prod")
    public DataSource jndiDataSource() {
    }
    }

    可以将不同环境的bean定义在一个配置类中,使用@Profile("")指定其profile,表明只有在相应的profile激活时才会创建该bean。

    在XML配置文件中一样可以这样配置。

    没有声明在任一profile中的bean始终都会创建,与激活哪个profile没关系。

    激活profile

    Spring在确定激活那个profile时,依赖两个属性:spring.profiles.active和spring.profiles.default。

    如果设置了active属性,它的值就是来确定激活哪个profile

    如果没有设置active,Spring会查找default的值来确定激活哪个profile

    如果active和default都没设置,Spring只会创建没有定义profile的bean

    设置两个属性的方式:

    • 作为DispatcherServlet的初始化参数
    • 作为Wen应用的上下文参数
    • 作为JNDI条目
    • 作为环境变量
    • 作为JVM的系统属性
    • 集成测试类上,使用@ActiveProfiles设置

    系统优先使用spring.profiles.active的值。

    可以同时激活多个profile,用,隔开。

    条件化的bean

    @Conditional注解用来条件化配置bean,可以用到带@Bean的方法上,如果给定的条件结果为true,就会创建这个bean,否则忽略这个bean。

    @Bean
    @Conditional(MagicExistsCondition.class)
    public MagicBean magicBean() {
        return new MagicBean();
    }

    MagicExistsCondition这个类指明了条件,需要实现Condition接口。如果matches()返回true,bean会被创建,返回false,bean不会被创建。

    public class MagicExistsCondition implements Condition {
    
        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            Environment environment = context.getEnvironment();
            return environment.containsProperty("magicBean");
        }
    }

    Condition接口简单但功能强大,matches()方法的参数ConditionContext和AnnotatedTypeMetadata提供了很多的功能。

    @Profile在Spring4中进行了重构,使用了@Conditional和Condition接口。

    处理自动装配的歧义性

    只要一个bean匹配所需的结果时,自动装配才是有效的。如果不仅有一个bean能够匹配结果的话,这种歧义性会阻碍Spring自动装配属性、构造参数或方法参数。可以使用以下方法来解决这个问题。

    用首选标识bean

    使用@Primary注解将其中一个可选的bean设置为首选,可以和@Component组合使用,可以和@Bean组合使用,告诉Spring在遇到歧义性时要选择的bean。

    @Primary
    @Component
    public class IceCream implements Dessert {
    }
    @Primary
    @Bean
    public Dessert iceCream() {
        return new IceCream();
    }

    限定自动装配的bean

    Spring中的限定符能够在可选的bean上缩小范围,直到只有一个bean满足这些范围。@Qualifier注解是限定符的主要方式,可以与@Autowired和@Inject使用。

    以下是简单使用@Qualifier的例子,参数是想要注入bean的限定符,默认和bean id一致。

    @Qualifier("iceCream")
    public void setDessert(Dessert dessert) {
        this.dessert = dessert;
    }

    为了方便修改类名,可以自定义限定符,这样限定符和类名不耦合。

    @Component
    @Qualifier("cold")
    public class IceCream implements Dessert {
    }

    @Qualifier也可以和@Bean一起使用。

    @Bean
    @Qualifier("cold")
    public Dessert iceCream() {
        return new IceCream();
    }

    如果需要在一个bean上添加个限定符(@Qualifier),在Java8前的是不允许在单个条目上使用同一注解多次,这时需要自定义限定符注解,如下,然后再把这些注解添加到bean上,需要注入的方法或字段上。

    @Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Qualifier
    public @interface Cold {
    }

    bean的作用域

    默认情况下,Spring上下文中的Bean都是单例的。Spring定义了多种作用域。

    • 单例(singleton),整个应用中,只创建bean的一个实例
    • 原型(prototype),每次注入或者通过Spring上下文获取时,都会创建一个新的实例
    • 会话(session),在Web应用中,为每个会话创建一个bean实例
    • 请求(request),在Web应用中,为每个请求创建一个bean实例

    使用@Scope来声明

    @Component
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public class IceCream implements Dessert {
    }

    如下是创建会话或请求作用域bean的声明。proxyMode的作用是解决将会话或请求作用域的bean注入到单例bean中遇到的问题。遇到单例的bean实例,Spring注入的不是特定的ShoppingCart实例,而是一个代理,这个代理会暴露与ShoppingCart相同的接口,随后调用真正ShoppingCart的方法。proxyMode指定的就是为接口创建代理(ScopedProxyMode.INTERFACES)还是为类创建代理(ScopedProxyMode.TARGET_CLASS)。

    @Component
    @Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.INTERFACES)
    public class ShoppingCart {
    }

    运行时注入值

    Spring提供了两种运行时求值的方法:

    属性占位符(property placeholder)

    Spring表达式语言(SpEL)

    属性占位符

    Spring支持将属性定义到外部的属性文件中,然后在程序中引用。

    下面的代码首先声明了属性源,并通过Environment来检索属性。

    @Configuration
    @PropertySource("classpath:/com/soundsystem/app.properties")
    public class DemoConfig {
    
        @Autowired
        Environment environment;
    
        public BlankDisc blankDisc() {
            return new BlankDisc(environment.getProperty("disc.title"), environment.getProperty("disc.artist"));
        }
    }

    另一种方式是用占位符将值插入到bean中。占位符的形式是用${}包装属性名,使用@Value注解来插入。

    public BlankDisc(@Value("${disc.title}") String title, @Value("${disc.artist}") String artist) {
        this.title = title;
        this.artist = artist;
    }
  • 相关阅读:
    线程生命周期
    java集合源码分析几篇文章
    Java中的equals和hashCode方法详解
    java集合(一)
    volatile和synchronized实现内存可见性的区别
    动态代理的原理
    过滤器的使用
    pageBean的实体类
    FindUserByPageServlet
    用户信息系统_serviceImpl
  • 原文地址:https://www.cnblogs.com/minguo/p/10964263.html
Copyright © 2011-2022 走看看