大概看了一下第三章的内容,我从项目中仔细寻找,始终没有发现哪里有这种配置,但是看完觉得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();
}

三、spring中高级装配(1)的更多相关文章

  1. 四、spring中高级装配(2)

    这个是接着上一篇写的,这章内容较多,分开来记录一下... 三.处理自动装配的歧义性 自动装配让spring完全负责bean引用注入到构造参数和属性中,不过,仅有一个bean匹配所需的结果时,自动装配才 ...

  2. Spring学习(三)-----Spring自动装配Beans

    在Spring框架,可以用 auto-wiring 功能会自动装配Bean.要启用它,只需要在 <bean>定义“autowire”属性. <bean id="custom ...

  3. (三)Spring 高级装配 bean的作用域@Scope

    1.默认情况下,spring通过@Autowared注入的bean是单例的bean,但有些情况是不满足的,例如:购物车,每个会话,或每个用户登录使用的购物车都是独立的 spring的定义的作用域: a ...

  4. Spring高级装配

    Spring高级装配 目录 一.Profile(根据开发环境创建对应的bean) 二.条件化的创建bean(根据条件创建bean) 三.处理自动装配歧义性(指定首选bean.限定符限制bean) 四. ...

  5. Spring(3)——装配 Spring Bean 详解

    装配 Bean 的概述 前面已经介绍了 Spring IoC 的理念和设计,这一篇文章将介绍的是如何将自己开发的 Bean 装配到 Spring IoC 容器中. 大部分场景下,我们都会使用 Appl ...

  6. Spring 自动装配及其注解

    一.属性自动装配 首先,准备三个类,分别是User,Cat,Dog.其中User属性拥有Cat和Dog对象. package com.hdu.autowire; public class User { ...

  7. spring 自动装配 default-autowire=&quot;byName/byType&quot;

    <PRE class=html name="code">spring 自动装配 default-autowire="byName/byType"   ...

  8. Spring高级装配(一) profile

    Spring高级装配要学习的内容包括: Spring profile 条件化的bean声明 自动装配与歧义性 bean的作用域 Spring表达式语言 以上属于高级一点的bean装配技术,如果你没有啥 ...

  9. Spring Bean装配学习

    解释:所谓装配就是把一个类需要的组件给它设置进去,英文就是wire,wiring:注解Autowire也叫自动装配. 目前Spring提供了三种配置方案: 在XML中进行显式的配置 在Java中进行显 ...

随机推荐

  1. (unix domain socket)使用udp发送>=128K的消息会报ENOBUFS的错误

    一个困扰我两天的问题, Google和Baidu没有找到解决方法! 此文为记录这个问题,并给出原因和解决方法. 1.Unix domain socket简介 unix域协议并不是一个实际的协议族,而是 ...

  2. sqlite支持linq

    A small library to easily access SQLite databases from .NET/Mono/MonoTouch applications In order to ...

  3. IJ:IJ来了2-调试开发环境

    ylbtech-IJ:IJ来了2 1.返回顶部 1. 2. 3. 4. 2. 配置SVN返回顶部 1.SVN安装时,要选上command line client tools 2. 3.   4. 3. ...

  4. VS2012上添加SharePoint2013模板,SharePoint2013 Tool安装配置

    今天需要在SharePoint2013上做开发,但是安装的VS2012默认只有sharepoint2010的模板,因此需要安装配置好,这里我们通过Web平台安装程序4.0来配置的 Web 平台安装程序 ...

  5. 深入学习 Block

    本文翻译自苹果的文档,有删减,也有添加自己的理解部分. 如果有Block语法不懂的,可以参考fuckingblocksyntax,里面对于Block 为了方便对比,下面的代码我假设是写在ViewCon ...

  6. winform 窗体设置成无边框、可拖拽、四周圆角

    最近做一个及时通讯系统的登录界面,现在将界面用到的无边框.可拖拽.四周圆角的方法分享如下: 1.无边框的窗体: 把FormBorderStyle的属性设置为none 2.可拖拽:private Poi ...

  7. jetbrains软件使用

    1.注册(有条件的话建议使用官方渠道注册https://www.jetbrains.com/store) 2018 license server http://idea.congm.in 2.禁用双击 ...

  8. 传统的线程互斥技术:Synchronized关键字

    多个线程操作同一个方法或变量时常常出现错误,要保证每个线程都正常运行就要通过加锁,每次只有一个能够拿到锁通过.如下: package cn.sp.thread; /** * Created by 2Y ...

  9. -------Pokemon Master------很水-------

    A - Pokemon Master Time Limit:2000MS Memory Limit:65536KB 64bit IO Format:%lld & %llu Submit Sta ...

  10. DecimalFormat数字格式化用法“0”和“#”的区别

    1. 以“0”补位时: 如果数字少了,就会补“0”,小数和整数都会补: 如果数字多了,就切掉,但只切小数的末尾,整数不能切: 同时被切掉的小数位会进行四舍五入处理. 2. 以“#”补位时: 如果数字少 ...