Spring 高级装配
来源:互联网 发布:软件开发大牛 编辑:程序博客网 时间:2024/05/16 08:23
- 环境与profile
1.配置profile bean
如下代码所示:
在开发环境中会创建一个javax.sql.DataSource的bean。用EmbeddedDatabaseBuilder会搭建一个嵌入式的HyperSonic数据库。他的模式(schema)定义在schema.sql中,测试数据则是通过test-data.sql加载的。
在生产环境中通过JNDI容器中获取一个DataSource,
在Qa环境中则配置Commons DBCP连接池。
package test;import javax.activation.DataSource;import org.apache.commons.dbcp.BasicDataSource;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;@Configurationpublic class DataSourceConfig {/** * 开发环境 * @return */@Bean(destroyMethod="shutdown")@Profile("dev")public DataSource dataSource() {return (DataSource) new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).addScript("classpath:schema.sql").addScript("classpath:test-data.sql").build();}/** * QA环境 * @return */@Bean@Profile("qa")public DataSource qaDataSource(){BasicDataSource dataSource = new BasicDataSource();dataSource.setUrl("jdbc:h2:tcp://dbserver/~/test");dataSource.setDriverClassName("org.h2.Driver");dataSource.setUsername("sa");dataSource.setPassword("password");dataSource.setInitialSize(20);dataSource.setMaxActive(30);return (DataSource) dataSource;}/** * 生产环境 * @return */@Bean@Profile("prod")public DataSource jndiDataSource() {JndiObjectFactoryBean jndiObjectFactoryBean = new JndiObjectFactoryBean();jndiObjectFactoryBean.setJndiName("jdbc/myDS");jndiObjectFactoryBean.setResourceRef(true);jndiObjectFactoryBean.setProxyInterface(javax.sql.DataSource.class);return (DataSource) jndiObjectFactoryBean.getObject();}}注:尽管每个DataSource bean 都背声明在一个profile中,并且只有当规定的profile被激活时,相应的bean才会被创建。而没有用指定profile的bean始终都会被创建,与激活哪个profile没有关系。
- 在xml中配置profile
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jdbc="http://www.springframework.org/schema/jdbc"xmlns:jee="http://www.springframework.org/schema/jee" xmlns:p="http://www.springframework.org/schema/p"xsi:schemaLocation=" http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.3.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.3.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd"> <!-- 开发环境 --><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环境 --><beans profile="qa"><bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"destroy-method="close" p:url="jdbc:h2:tcp://dbserver/~/test"p:driverClassName="org.h2.Driver" p:username="sa" p:password="password"p:initialSize="20" p:maxActive="30" /></beans><!-- 生产环境 --><beans profile="prod"><jee:jndi-lookup id="dataSource" jndi-name="jdbc/myDataBase"resource-ref="true" proxy-interface="javax.sql.DataSource" /></beans></beans>三个bean,但是在运行的时候只会创建一个bean,这取决于哪个bean被激活。
2. 激活profile
Spring在确定哪个profile处于激活状态时,需要两个独立的属性:spring.profiles.active和spring.profiles.default。如果设置了spring.profiles.active属性,那么它的值就用来确定哪个profile被激活。否则就查找spring.profile.default的值。如果两个均没有设置,那就没有激活的profile,因此只会创建那些没有定义在profile的bean。
通过以下几种方式设置这两个属性:
作为DispatcherServlet的初始化参数;
作为Web应用的上下文参数;
作为JNDI条目;
作为环境变量;
作为JVM的系统属性;
在继承测试类上,使用@ActiveProfile注解设置
在web.xml文件中设置默认的profile
<?xml version="1.0" encoding="UTF-8"?><web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"><context-param><param-name>contextConfigLocation</param-name><param-value>/WEB-INF/applicationContext.xml</param-value></context-param><!-- 为上下文设置默认的profile --><context-param><param-name>spring.profiles.default</param-name><param-value>dev</param-value></context-param><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><servlet><servlet-name>appServlet</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!-- 为Servlet设置默认的profile --><init-param><param-name>spring.profile.default</param-name><param-value>dev</param-value></init-param></servlet><servlet-mapping><servlet-name>appServlet</servlet-name><url-pattern>/</url-pattern></servlet-mapping></web-app>按照这种方式设置的spring.profile.default,所有的开发人员都能从版本控制软件中获得应用程序源码,并使用开发环境设置运行代码,不需要额外的配置。
当系统使用spring.profile.active以后,spring.profile.default将没有任何作用,系统会有限使用spring.profile.active的值。
- 条件化的bean
假设有一个名为MagicBean的类,我们希望在只有设置了magic环境属性的时候,Spring才会实例化这个类。
当matches()方法的返回值为真的时候则会创建MagicBean,否则不会创建。
package restfun;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Conditional;public class MagicConfig {/** * 条件化的创建bean * @return */@Bean@Conditional(MagicExistsCondition.class)public MagicBean magicBean() {return new MagicBean();}}
MagicExistsCondition需要实现Condition接口并且实现其中的matches()方法。
ConditionContext中的getRegistry()方法返回的BeanDefinitionRegistry检查bean定义。
ConditionContext中的getBEanFactory()方法返回的ConfigurableListBeanFactory检查bean是否存在,甚至探查bean的属性。
ConditionContext中的getEnvironment()方法返回的Environment检查环境变量是否存在以及它的值是什么。
ConditionContext中的getResourceLoader()方法获取返回的ResourceLoader所加载的资源。
ConditionContext中的getClassLoader()方法获取返回的ClassLoader所加载的资源是否存在。
package restfun;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 MagicExistsCondition implements Condition{@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {Environment env = context.getEnvironment();//检查magic属性return env.containsProperty("magic");}}
- 处理自动装配的歧义性
当有多个bean能够匹配结果的话,这种歧义性会阻碍Springz自动装配属性、构造器参数或方法参数。
处理这个方式有两个:标示首选的bean和限定自动装配的bean.
1.标示首选的bean.
通过在@Component和@Primary结合来使用
package soundsystem;import javax.inject.Named;import org.springframework.context.annotation.Primary;import org.springframework.stereotype.Component;@Component("lonelyHearsClub")@Primarypublic class SgtPeppers implements CompactDisc{.....}
<bean id="cdPlayer" class="xmlCongfig.CDPlayer" primary="true" />
2.限定自动装配的bean
(1)@Qualifier注解是使用限定符的主要方式。为@Qualifier注解所设置的参数就是想要注入的bean的ID。
package test;import org.springframework.stereotype.Component;@Componentpublic class IceCream implements Dessert{@Overridepublic void display() {// TODO Auto-generated method stub}}
@Autowired@Qualifier("iceCream")public void setDessert(Dessert dessert) {this.dessert = dessert;}(2)使用自定义的限定符
为IceCraem类定义其限定符为cold。则在Java配置bean的时候就必须如下配置@Qualifier("cold")。
package test;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.stereotype.Component;@Component@Qualifier("cold")public class IceCream implements Dessert{@Overridepublic void display() {}}
package test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Qualifier;public class Test {private Dessert dessert;@Autowired@Qualifier("cold")public void setDessert(Dessert dessert) {this.dessert = dessert;}public void fn() {dessert.display();}}(3)使用自定义的限定符注解
可以自定义一个限定符注解,如定义了一个@Cold的限定符,该限定符必须实现Qualifier注解。然后在IceCream与bean配置中使用该限定符即可
package test;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;import org.springframework.beans.factory.annotation.Qualifier;@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Qualifierpublic @interface Cold {}
package test;import org.springframework.stereotype.Component;@Component@Coldpublic class IceCream implements Dessert{@Overridepublic void display() {}}
package test;import org.springframework.beans.factory.annotation.Autowired;public class Test {private Dessert dessert;@Autowired@Coldpublic void setDessert(Dessert dessert) {this.dessert = dessert;}public void fn() {dessert.display();}}
- bean的作用域
spring中bean的作用域有:
1.单例(Singleton):在整个应用中,只创建bean的一个实例
2.原型(prototype):每次注入或者通过Spring应用上下文获取的时候,都会创建一个新的bean实例
3.会话(session):在Web应用中,为每个会话请求创建一个bean实例
4.请求(request):在Web应用中,为每个请求创建一个bean实例
package scoped;import org.springframework.beans.factory.config.ConfigurableBeanFactory;import org.springframework.context.annotation.Scope;import org.springframework.context.annotation.ScopedProxyMode;import org.springframework.stereotype.Component;import org.springframework.web.context.WebApplicationContext;@Component/** * 原型模式 @Scope("prototype") 或者 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) 在xml文件中的配置形式 <bean id="notepad" class="scoped.Notepad" scope="protype" /> 会话模式 @Scope(value=WebApplicationContext.SCOPE_SESSION, proxyMode=ScopedProxyMode.INTERFACES) */@Scope(value=WebApplicationContext.SCOPE_SESSION, proxyMode=ScopedProxyMode.INTERFACES)public class Notepad {}
在XML中声明作用域代理
<bean id="notepad" class="scoped.Notepad" scope="session"> <aop:scoped-proxy proxy-target-class="false"/> </bean><aop:scoped-proxy>是与@Scope注解的proxyMode属性功能相同的SpringXML配置元素。它会告诉Spring为bean创建一个作用域代理。默认情况下,它会使用CGLib创建目标代理。但是将proxy-target-class属性设置为false,进而要求它生成基于接口的代理。
- 运行时注入
1.注入外部的值
在Spring中,处理外部值得最简单的方式是声明属性源并通过Spring的Environment来检索属性。
package externals;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.PropertySource;import org.springframework.core.env.Environment;@Configuration//声明属性源@PropertySource("classpath:app.properties")public class ExpressiveConfig {@AutowiredEnvironment env;@Beanpublic BlankDisc disc() {return new BlankDisc(env.getProperty("disc.title"),env.getProperty("disc.artist"));}}
2 使用Spring表达式语言进行装配
Spring表达式语言(Spring ExpressionLanguage, SpEL), 它能够以一种强大和简洁的方式将值装配到bean属性和构造器参数中,在这个过程中所使用的表达式会在运行时计算得到的值。“#{.......}”
SpEL的特性:
使用bean的ID来引用bean;
使用方法和访问对象的属性;
对值进行算术、关系和逻辑运算;
正则表达式匹配;
集合操作。
引用bean、属性和方法
#{sgtPeppers.artist}其中sgtPeppers为一个bean的ID,并且使用了该bean的artist属性。
- Spring Bean 高级装配
- spring(3)高级装配
- 【Spring 核心】高级装配
- Spring 高级装配
- Spring 高级装配
- 【Spring】高级装配
- 【Spring】高级装配
- Spring高级装配
- Spring之高级装配
- spring 第三章节 高级装配
- Spring入门之高级装配
- 读书笔记-spring高级装配bean
- Spring之高级装配(二)
- Spring学习笔记(六) --- 装配Bean之高级装配
- Spring In Action 02 ---高级装配
- Spring学习笔记二:高级装配
- 3.Spring学习笔记之高级装配
- Spring入门之Bean高级装配
- Mysql存储过程使用随机数
- 数据结构实验之栈八:栈的基本操作
- spring 异常拦截处理
- Java面试(七)
- HTML+CSS基础入门-第十六天(CSS-列表属性)
- Spring 高级装配
- android项目中的jar包总结
- Java就业指导
- 119. Pascal's Triangle II
- C++ Primer Plus, Chapter10对象和类,excercise
- C++中基类的析构函数为什么要用virtual虚析构函数
- redis集群报错,(error) MOVED 15495 127.0.0.1:7003
- Python进阶(二十四)-Python中函数的参数定义和可变参数
- 技术人员如何脱颖而出?