Spring之高级装配(二)
来源:互联网 发布:vb控件工具箱 编辑:程序博客网 时间:2024/06/05 01:03
上一节提到Spring之装配bean(一),我们已经了解到了装配的基础知识,这部分是更为高级的bean装配技术。
高级装配内容:
- spring profile
- 有条件的bean
- 处理自动装配的歧义性
- bean的作用域
1.spring profile
应用程序从一个环境迁移到另一个环境。开发阶段,某些环境相关做法可能并不适合迁移到生产环境中,甚至几遍迁移过去也无法正常工作,所以在不同的环境中使用的bean可能不同。下面以datasource为例:
在Java配置类中配置(“dev”和“prod”生产环境):
@Configurationpublic class DataSourceConfig{ @Bean(destroyMethod="shutdown") @Profile("dev") public DataSource dataSource(){ return new EmbeddedDatabaseBuilder() .addScript("classpath:schema.sqsl") .addScript("classpath:test-data.sql") .build(); } @Bean @Profile("prod") public DataSource dataSource(){ JndiObjectFactoryBean jndi=new JndiObjectFactoryBean(); jndi.setJndiName("jdbc/myDS"); jndi.setResourceRef(true); jndi.setProxyInterface(javax.sql.DataSource.class); return (DataSource) jndi.getObject(); }}
在xml中配置:
<beans xmlns="......."> <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> <beans profile="qa"> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destory-method="close" p:url="jdbc:h2:tcp://dbserver/~/test" ....... p:maxActive="30"/> </beans></beans>
激活(使用)哪一个profile:
<!--为应用山下文设置默认的profile--><context-param> <param-name>spring.profiles.default</param-name> <param-name>dev</param-name></context-param><!--为Servlet设置默认的profile--><servlet> <servlet-name>appServlet</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <init-param> <param-name>spring.profiles.default</param-name> <param-value>dev</param-value> </init-param> <load-on-startup>1</load-on-startup></servlet>
2.有条件的bean
假设你希望一个或多个bean只有在应用的类路径下包含特定的库时才创建。或者我们希望某个bean只有当另外某个特定的bean也声明了之后才会创建。我们还可能要求只有某个特定的环境变量设置之后才会创建某个bean。在Spring4之前,很难实现这种级别的条件化配置,但是Spring4引入了一个新的@Conditioinal注解,他可以用到带有@Bean注解的方法上。如果给定的条件计算结果为true,就会创建这个bean,否则的话,这个bean就会被忽略。
有条件的bean一般在java配置注入bean的方法中使用到。
@Configurationpublic class ConditionalConfig { @Bean @Conditional(MagicExistsConditional.class) //条件化的创建bean public MagicBean magicBean() { return new MagicBean(); }}
public class MagicExistsConditional implements Condition{ @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { Environment evn = context.getEnvironment(); return evn.containsProperty("magic"); }}
如你所见,设置给@Conditional的类可以是任意实现了Condition接口的的类型。而实现这个接口只需要实现matches方法,如果matches方法返回true就创建该bean,如果返回false则不创建bean,上例中我们就是根据环境变量中是否存在magic变量,来决定matches的返回值,进而决定是否创建MagicBean的。
但是在实际生产中,ConditionContext context, AnnotatedTypeMetadata metadata这两个参数可以对类中的其他信息进行判断,有兴趣可以查一下这两个类的api。
3.处理自动装配的歧义性
如果不仅有一个bean能够匹配结果的话,这种歧义性阻碍Spring自动装配属性、构造器参数或方法参数。 下面是一个例子:
@Autowiredpublic void setDessert(Dessert dessert){ this.dessert = dessert;}
@Componentpublic class Cake implements Dessert{...}@Componentpublic class Cookies implements Dessert{...}@Componentpublic class IceCream implements Dessert{...}
在这里,当Spring试图自动装配setDessert()中的Dessert参数时,它并没有唯一、无歧义的可选值。因而,Spring会抛出NoUniqueBeanDefinitionException;
解决方案1:将其中一个bean设置为首选
@Component@Primarypublic class Cake implements Dessert{...}
或者在xml中
<bean id = "iceCream"class = "com.desserteater.Icecream"primary = "true"> </bean>
解决方法2:使用限定符(qualifier)来帮助Spring将可选的bean的范围缩小
@Autowired@Qualifier("cake")public void setDessert(Dessert dessert){ this.dessert = dessert;}
4、bean的作用域
- 单例(singleton):在整个应用中,只创建bean的一个实例。
- 原型(prototype):每次注入或者通过Spring应用上下文获取的时候,都会创建一个新的bean实例。
- 会话(Session):在Web应用中,为每个会话创建一个bean实例。
- 请求(Request):在Web应用中,为每个请求创建一个bean实例。
单例是默认的作用域,但是正如之前所述,对于易变的类型,这并不合适。如果选择其他的作用域,要使用@Scope注解,他可以与@Component(自动装配)或@Bean(JavaConfig)一起使用。
例如,如果你使用组件扫描来发现声明bean,那么你可以在bean的类上使用@Scope注解,将其声明为原型bean,如下:
@Component@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)//@Scope("prototype")public class Notepad{...}
或者
<bean id="notepad" class="com.myapp.Notepad" scope="prototype" />
使用会话和请求作用域
@Component@Scope( value=WebApplicationContext.SCOPE_SESSION, proxyMode=ScopedProxyMode.INTERFACES)public ShoppingCart cart(){...}
这里,我们将value设置成了WebApplicationContext中的SCOPE_SESSION常量(它的值是session)。这会告诉Spring为Web应用中的每个会话创建一个ShoppingCart。这会创建多个ShoppingCart bean 实例,但是对于给定的会话只会创建一个实例,在当前会话相关的操作中,这个bean实际上相当于单例。
@Scope同时还有一个proxyMode属性,它被设置成了ScopedProxyMode.INTERFACES。这个属性解决了将会话或请求作用域的bean注入到单例bean中所遇到的问题。作用域代理能够延迟注入请求和会话作用域的bean。
在xml中注入:
<bean id="cart" class="com.myapp.ShoppingCart" scope="session"> <aop:scoped-proxy /></bean>
- Spring之高级装配(二)
- Spring之高级装配
- Spring入门之高级装配
- Spring学习笔记二:高级装配
- Spring之装配bean(二)
- Spring学习笔记(六) --- 装配Bean之高级装配
- 3.Spring学习笔记之高级装配
- Spring入门之Bean高级装配
- Spring学习总结之高级装配
- Spring实战之三:高级装配
- Spring学习之路-高级装配
- Sring入门之高级装配(二)md
- Spring Bean 高级装配
- spring(3)高级装配
- 【Spring 核心】高级装配
- Spring 高级装配
- Spring 高级装配
- 【Spring】高级装配
- MQ实现“延迟消息”功能
- Mesos 配置项解析
- 现金贷将遇强监管,“赚钱机器”今后只能赚上市股民的钱
- Videojs播放RTMP流媒体
- 选择排序
- Spring之高级装配(二)
- 自动滚动的RecyclerView(水平和垂直方向)
- 【JavaScript学习】事件:事件流
- linux下的图形串口调试工具-xgcom
- Wireshark分析数据包
- 利用Python实现网络爬取图片
- 在main函数之前被调用的函数
- java线程详细学习一-----线程的创建和启动
- 大话设计模式读书笔记之外观模式