装配bean
Spring主要的三种装配机制:
- 在XML中进行显式配置;
- 在Java中进行显式配置;
- 隐式的bean发现机制和自动装配。
Spring从两个角度实现自动化装配:
组件扫描:@Component(自定义bean名称)注解 此外,@Named()有类似功能,不建议用
@Configuration
@ComponentScan(指定扫描的基础包)
@ComponentScan(basePackages={“pakage1”,”pakage2”}) 扫描多个基础包
自动装配:
测试:
@Runwith(SpringJUnit4ClassRunner.Class)在测试开始的时候创建上下文
@ContextConfiguration(classes=XXConfig.class)在那个文件中加载
@Autowired:自动装配不仅能过用在构造器上,而且能够用在属性setter方法上。
此外@Inject也能够代替,它源于Java依赖注入的规范。
@Test
- 通过Java装配bean
1 创建配置类 @Configuration
2 生命简单的bean @Bean
3 借助JavaConfig实现注入
2.通过XML装配Java
- 借助于 Spring Tool Suite 创建XML配置文件和管理Spring配置文件
- 声明一个简单的bean
- 借助构造器注入初始化bean
- 构造器注入bean引用 <constructor-arg ref=”xxxx” />
- 将字面注入到构造器中 <contructor-arg value=”xxx” />
- 使用List装配集合
<constructor-arg>
<list>
<value>xxx</value>
<value>yyy</value>
</list>
</constructor-arg>
也可以使用Set集合,但不能重复和保证无序。
- setter属性注入:
强依赖使用构造器注入
<property>元素为属性的Setter方法所提供的功能和<constructor-arg>元素是一样的。前者对应着p-命名空间,后者对应c-命名空间。
- 将字面注入到属性中
<property name=””, value=”xxxxxx”/>
< property name = “abc”>
<list>
<value>xxx</value>
<value>yyy</value>
</list>
</ property >
注意装配引用和装配置字面唯一的区别就是带不带-ref。
如何配置混合装配。
- 使用@Import将两个JavaConfig配置类组合在一起
@Configuration
@Import({xxx1Config.class, xxx2Config.class})
2.在JavaConfig中引用XML配置
@Configuration
@Import(xxx1Config.class )
@ImportResource(“classpath:xxx-config.xml”)
拆分XML配置
同样使用<import resource=”xxx.xml”/>
在XML配置中引用JavaConfig配置
<bean class=”xxx.Config”/>
<import resource = “xxxx.xml”
高级装配
环境与profile:开发和生产阶段对数据库会有不同的配置。用profile进行bean的激活管理。
在XML中配置profile:可以同时定义三个bean,类型都是javax.sql.DataSource.并且ID都可以相同。那么如何激活某个profile??
使用profile进行测试
Spring提供了@ActiveProfiles注解:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={xxTestConfig.class})
@ActiveProfiles(“active”)
Public class xxxxxTest{ }
条件化的bean ,Spring4引入了新的@Contional注解
Condition接口matches方法中两个重要的变量:
ConditionContext和AnnotatedTypeMetadata
Spring4中的Profile重构,
@Conditional(value={ProfileCondition.class})
@Target(value={METHOD, TYPE})
@Retention(value=RUNTIME)
@Documented
自动装配的歧义性
Spring不能够从多个bean选择并能够自动装配,就会抛出异常。NoUniqueBeanDefinitionException.
解决方案:
- 标示首选的bean。
@Component
@Primary
Public class IceCream implements Dessert{}
- 多个首选bean出现歧义的解决方案:限定自动装配的bean
@Qualifier注解是使用限定符的主要方式,与@Autowired和@Inject协同使用。
@Autowired
@Qualifier(“iceCream”) //参数是想要被注入的bean的ID
Public void setDessert(Dessert dessert){
This.dessert = dessert;
}
- 解决基于默认的bean ID作为限定符的问题:创建自定义的限定符。
就是在bean声明上添加@Qualifier并且和@Component联用
@Component
@Qualifier(“newname”)//这种情况,newname限定符分配给了IceCream bean。
Public class IceCream implements Dessert {}
能够解决对IceCream类名的任意重构。
- 使用自定义的限定符注解:解决限定符注解的冲突
通过声明自定义的限定符注解,我们能够同时使用多个限定符,不会再有Java编译器的限制或错误,此外,与原始的@Qualifier并借助于String类型来指定限定符,自定义的限定符更安全。
Bean的作用域
Spring定义的作用域:
单例(singleton)
原型(prototype)
会话(session)
请求(request)
使用会话和请求作用域
@Component
@Scope(value=WebApplicationContext.SCOPE_SESSION,
proxyMode=ScopedProxyMode.INTERFACES)
public ShoppingCart cart(){…}
proxyMode=ScopedProxyMode.INTERFACES //代理要实现接口,并调用委托给实现bean。
proxyMode=ScopedProxyMode.TARGET_CLASS//带来要实现具体的类,使用CGLib生成基于类的代理。
在XML中声明作用域代理:
<bean id =”cart” class=”com.myapp.ShoppingCart” scope=”session”>
<aop:scoped-proxy proxy-target-class=”false” />要求基于接口的代理。默认使用CGLib
</bean>
- 运行时值注入
注入外部的值:
声明属性源并通过spring的Environment来检索属性。
@Configuration
@PropertySource(“xxx/xx/app.properties”)
Public class ExpressiveConfig{
@Autowired
Environment env;
@Bean
Public BlankDisc disc () {
Return new BlankDisc(env.getPreoperty(“xxx”), env.getProperty(“xxx”));
}
}
- 深入学习spring的Environment
String getProperty(String key)
String getProperty(String key, String defaultValue)
T getProperty(String key, Class<T> type)
T getProperty(String key, Class<T> type , T defaultValue)
String[] getActiveProfiles():返回激活profile名称的数组。
String[] getdefaultProfiles():返回默认profile名称的数组。
boolean acceptsProfiles(String…profiles):如果environment支持profile的话,就返回true。
- 使用属性占位符:${xxx}
- 使用spring表达式语言进行装配
- 使用bean的ID来引用bean
- 调用方法和访问对象的属性
- 对值进行算术、关系和逻辑运算
- 集合操作
- SpEL样例
#{T(System).currentTimeMillis()}
- SpEL对bean的装配:
Pubic BlankDisc(@Value(“#{SystemPropreties[‘disc.title’]}”) String title,
@Value(“#{SystemPropreties[‘disc.artist’]}”) String artist){
This.title=title;
This.artist=artist;
}//和占位符非常相似
表示字面值:整数、浮点数、String、Boolean值。
引用bean、属性、方法
#{segPeppers}
#{segPeppers.artist}
#{artistSelector.selectArtist()}
#{artistSelector.selectArtist()?.toUpperCase()}//如果方法返回值为null的话,那么SpEL将不会调用toUpperCase()的方法。
在表达式中使用类型以及运算符:
#{2 * T(java.lang.Math).PI * circle.radius}
#{counter.total == 100}
#{counter.total eq 100}