• 三、spring中高级装配(1)


      大概看了一下第三章的内容,我从项目中仔细寻找,始终没有发现哪里有这种配置,但是看完觉得spring还有这么牛B的功能啊,spring的厉害之处,这种设计程序的思想,很让我感慨。。。

    一、环境与profile

    (1)配置profile bean

    面对这样的需求:想出一种方法来配置DataSource,使其在每种环境下都会选择最为合适的配置,你会如何做呢?看看spring所提供的解决方案。spring中引入了bean profile的功能。在Java配置中,可以使用@Profile 注解指定某个bean属于哪一个profile。

    1)在Java类中配置profile bean

    package com.myapp;
    import javax.sql.DataSource;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Profile;
    import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
    import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
    
    //@Profile注解应用在累计别上。它会告诉spring这个配置类中的bean只有在dev profile 激活时才会创建,没有激活,则不会创建
    @Configuration
    @Profile("dev")
    public class DevelopmentProfileConfig{
       return new 
       EmbeddDatabaseBuilder().setType(EmbeddedDatebaseType.H2).
       addScript("classpath:schema.sql").addScript("classpath:test-
       data.sql").build();
    }
    
    package com.myapp;
    import javax.sql.DataSource;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Profile;
    import org.springframework.jndi.JndiObjectFactoryBean;
    
    //@Profile注解应用在累计别上。它会告诉spring这个配置类中的bean只有在prod profile 激活时才会创建,没有激活,则不会创建
    @Configuration
    @Profile("prod")
    public class ProductiontProfileConfig{
       JndiObjectFactoryBean jndiObjectFactoryBean = new JndiObjectFactoryBean();
       jndiObjectFactoryBean.setJndiName("jdbc/myDS");
       jndiObjectFactoryBean.setResourceRef(true);
       jndiObjectFactoryBean.setProxyInterface(javax.sql.DataSource.class);
       return (DataSource) jndiObjectFactoryBean.getObject();
    }
    
    //可以将这两个bean的声明放置在同一个配置类中
    package com.myapp;
    import javax.sql.DataSource;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Profile;
    import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
    import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
    import org.springframework.jndi.JndiObjectFactoryBean;
    
    @Configuration
    public class DateSourceConfig{
    
     //为dev profile装配bean
     public DataSource embeddedDataSource(){
        return new 
       EmbeddDatabaseBuilder().setType(EmbeddedDatebaseType.H2).
       addScript("classpath:schema.sql").addScript("classpath:test-
       data.sql").build();
     }
     
     //为prod profile 装配bean
     public DataSource jbdiDataSource(){
        JndiObjectFactoryBean jndiObjectFactoryBean = new JndiObjectFactoryBean();
       jndiObjectFactoryBean.setJndiName("jdbc/myDS");
       jndiObjectFactoryBean.setResourceRef(true);
       jndiObjectFactoryBean.setProxyInterface(javax.sql.DataSource.class);
       return (DataSource) jndiObjectFactoryBean.getObject();
     }
    }

    2)在XML中配置profile bean

    //xml中配置的实际效果和在Java类中配置是一样的
    
    //dev profile 的bean
    <beans profile="dev">
        <jdbc:embedded-database id="dataSource">
            <jdbc:script location="classpath:schema.sql" />
            <jdbc:script location="classpath:test-data.sql" />
        </jdbc:embedded-database>
    </beans>
    
    //qa profile 的bean
    <beans profile="qa">
        <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destory-method="close" p:url="jdbc:h2:tcp://deserver/~/test" p:driverClassName="org.h2.Driver" p:username="sa" p:password="password" p:initialSize="20" p:maxActive="30">
        </bean>
    </beans>
    
    //prod profile 的bean
    <beans>
        <jee:jndi-lookup id="dataSource" jndi-name="jdbc/myDataSource" resource-ref="true" proxy-interfase="javax.sql.DataSource" />
    </beans>

    2)激活 profile

    profile bean 配置OK了,如何来激活配置的bean呢?依赖两个独立的属性:spring.profiles.active 和 spring.profiles.default。设置了spring.profiles.active属性的话,那么它的值就会来确定哪个profile是激活的,如果设置了spring.profiles.default属性,那么spring 会查找spring.profiles.default的值,如果两个属性都设置的话,肯定会优先spring.profiles.active属性对应的profile bean 装配

    多种方式设置这两个属性:

    1))作为DispatcherServlet的初始化参数

    2))作为web应用的上下文参数

    3))作为JNDI条目

    4))作为环境变量

    5))作为JVM的系统属性

    6))在集成测试上,使用@ActiveProfiles注解设置

    web.xml 中设置默认的profile

    //为上下文设置默认的profile
    <context-param>
        <param-name>spring.profile.default</param-name>
        <param-value>dev</param-value>
    </context-param>
    
    //为Servlet设置默认的profile 可以列出多个profile名称,并以逗号分隔来实现
    <servlet>
        <servlet-name>app-servlet</servlet-name>
        <servlet-class>
            org.springframework.web.servlet.servlet.DispatcherServlet
        </servlet-class>
        <init-param>
            <param-name>spring.profiles.default</param-name>
            <param-value>dev</param-value>
        </init-param>
    </servlet>

    二、条件化的bean

    spring4引入了一个新的@Conditional注解,它可以用到带有@Bean注解的方法上。如果给定的条件计算结果为true,则会创建这个bean,否则的话,这个bean会被忽略。

    //条件化的创建bean
    @Bean
    @Conditional(MagicExistsCondition.class)
    public MagicBean magicBean(){
      return new MagicBean();              
    }
    
    //@Conditional 将会通过Condition 接口进行条件对比
    public interface Condition{
      public boolean matches(ConditionContext ctcx,AnnotatedTypeMetadata metadata);  
    }
    
    //在Contidion 中检查是否存在magic属性,满足这个条件,matches()方法返回true,则所有的@Conditional 注解上引用MagicExistsCondition的bean都会被创建
    public class MagicExistsCondition implements Condition{
      public boolean matches(ConditionContext context,AnnotatedTypeMetadata metadata){
        Environment env = context.getEnvironment();
        return env.containsProperty("magic");                       
      }  
    }

    注:这里讲解了两个比较特殊的接口,一个是ConditionContext,一个是AnnotatedTypeMetadata,做一个说明:

    public interface ConditionContext{
      //检查bean的定义  
      BeanDefinitonRegistry getRegistry();  
      //检查bean是否存在,甚至探查bean的属性
      ConfigurableListableBeanFactory getBeanFactory();
      //检查环境变量是否存在以及它的值是什么
      Environment getEnvironment();
      //返回ResourceLoader所加载的资源
      ResourceLoader getResourceLoader();
      //返回ClassLoader加载并检查类是否存在
      ClassLoader getClassLoader();              
    }
    
    //检查带有@Bean注解的方法上还有什么其他的注解
    public interface AnnotatedTypeMetadata{
      boolean isAnnotated(String annotationType);
      Map<String,Object> getAnnotationAttributes(String annotationType);      
      Map<String,Object> getAnnotationAttributes(String annotationType,boolean classValueAsString);
      MultiValueMap<String,Object> getAnnotationAttributes(String annotationType);
       MultiValueMap<String,Object> getAnnotationAttributes(String annotationType,boolean classValueAsString);
    }

    注:spring4 中对@Profile注解进行了重构,使其基于@Conditional 和 Condition实现,@Profile在spring4 中的实现:

    /*
    @Profile本身也使用了@Conditional注解,并且引用了ProfileCondition作为Condition实现,ProfileCondition在做出决策的过程中,考虑到了ConditionContext和AnnotatedTypeMetadata中多个因素
    */
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE,ElementType.METHOD})
    @Document
    @Conditional(ProfileCondition.class)
    public @interface Profile{
      String[] value();  
    }
  • 相关阅读:
    程序员是脑力劳动还是体力劳动
    我理解的技术管理的核心工作----搭班子和带团队
    Ubuntu系统下在PyCharm里用virtualenv集成TensorFlow
    我理解的技术管理的核心工作----定战略
    数据分析师岗位的一点理解
    python中读写excel并存入mysql
    mac里用PyCharm中引用MySqlDB始末
    贝叶斯网络的通俗解读
    将sqlserver导出的csv数据导入到ubuntu和mac上的mysql
    Java之Spring Cloud概念介绍(非原创)
  • 原文地址:https://www.cnblogs.com/ssh-html/p/9655295.html
Copyright © 2020-2023  润新知