基于xml的配置
基础配置
<bean id="id" name="name" class="full_name">
<property name="pname" value="pvalue" lazy-init="defalut/true/false" scope="singleton/prototype/request/session" />
</bean>
- class为bean的全限定名,指向classpath下类定义所在位置
- id为bean的唯一名称标识,在整个IOC容器中必须是唯一的。它必须以字母开头,后面可以是数字、连字符、下划线、句号、冒号等符号。
-
name也是bean的名称标识,但它可在多个bean命名中重复,几乎可以使用任何符号如问号或以数字开头等。
以下是几点需要注意的:- id和name都可以指定多个名字,名字之间可用逗号、分号、或者空格间隔
- 如果配置了多个name相同的bean,通过getBean方法获取Bean时,将返回最后声明的那个Bean(前面的被后面覆盖)
- 如果id和name属性都未指定,用户可通过getBean(“full_name”),即通过class值来获取,如果定义了多个类相同的匿名Bean,如:
<bean class="full_name1"> <bean class="full_name1"> <bean class="full_name1">
则可通过getBean(“full_name1”)获取第一个,getBean(“full_name1#1”)获取第二个,以此类推。
Bean的每一个属性对应一个property标签,name为属性名,value为注入时为属性构造的数值
- lazy-int指明bean的初始化时机
- scope:bean的作用域(后面两种在web应用环境下呈现。
- singleton:整个IOC容器共享一个Bean
- prototype:每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的bean实例.
- request:每次HTTP请求将会生成各自的bean实例
- session:每次会话请求对应一个bean实例
拓展配置
1. 引用外部Bean
<bean id="idCard" class="test.IdCard"></bean>
<bean id="user" class="test.User" >
<property name="idCard" ref="idCard" />
</bean>
在这里以对象组合的方式将idCard定义为了user中的一个属性。上面代码使用了简化形式配置,<property name="idCard" ref="idCard" />
相当于
<property name="idCard">
<ref bean="idCard"/>
</property>
在标签中,除了bean属性,还有local、parent等,它们定义了引用Bean的可见域:
1. bean:可以引用同一容器或父容器中定义的Bean
2. local:只能引用同一配置文件中的Bean
3. parent:只能引用父容器的Bean
关于父子容器(上下文)的有关定义:
1. 父子容器可以通过ConfigurableApplicationContext或ConfigurableBeanFactory来实现,这两个接口中分别有setParent及setParentBeanFactory方法,可以与当前的子容器进行父子容器关联。也可以在动态加载资源文件时设定,如方法:ClassPathXmlApplicationContext(String configLocation,ApplicationContext parent)
2. 子容器可以访问父容器中的Bean,但父容器不能访问子容器的Bean。在容器内,Bean的id必须是唯一的,但子容器可以拥有一个和父容器id相同的Bean。父子容器层级体系增强了Spring容器架构的扩展性和灵活性,因为第三方可以通过编程的方式,为一个已经存在的容器添加一个或多个特殊用途的子容器,以提供一些额外的功能
2. 内部Bean
在Bean1内部定义一个Bean2,Bean2仅能被Bean1调用,其他Bean不可见,形式如:
<bean id="user" class="test.User" >
<property name="idCard">
<bean class="test.IdCard">
<property name="number" value="123"><null /></property>
</bean>
</property>
</bean>
值得注意的是,我们以标签将idCard的number属性设置成了null值
3. 级联属性
<bean id="user" class="test.User" >
<property name="idCard.number" ><null />
</property>
</bean>
此时,在User类中必须有定义IdCard idCard
属性
4. 集合类型属性
1. List集合或数组
<bean id="user" class="test.User" >
<property name="books">
<list>
<value>book1</value>
<value>book2</value>
<value>book3</value>
</list>
</property>
</bean>
此时,在User类中要有定义List<String> books
或String[] books
属性
2. Set集合
<bean id="user" class="test.User" >
<property name="books">
<set>
<value>book1</value>
<value>book2</value>
<value>book3</value>
</set>
</property>
</bean>
对应User类中Set<String> books
,当然,books的类型还可以为Set的实现类。
3. Map集合
1. 使用<map>
配合<entry>
标签进行组合
<bean id="user" class="test.User" >
<property name="books">
<map>
<entry>
<key><value>book1</value></key>
<value>100</value>
</entry>
<entry>
<key><value>book2</value></key>
<value>200</value>
</entry>
</map>
</property>
</bean>
如果map的键为bean,可使用<key><ref bean="beanName"></key>
如果map的值为bean,可使用<key>xxx<key><ref bean="beanName"></key>
2. 使用<props>
标签进行组合
<bean id="user" class="test.User" >
<property name="books">
<props>
<prop key="book1">100</prop>
<prop key="book2">200</prop>
</props>
</property>
</bean>
对应以上两种情况,User类中要定义Map books或其实现类
4. 集合合并
<bean id="user" class="test.User"><!-- 父bean -->
<property name="books" >
<set>
<value>book1</value>
<value>book2</value>
<value>book3</value>
</set>
</property>
</bean>
<bean id="subUser" parent="user"><!-- 指定父bean为user -->
<property name="books" ><!-- 子bean -->
<set merge="true"><!--和父bean中同名元素集合合并 -->
<value>book1</value>
<value>book4</value>
<value>book5</value>
</set>
</property>
</bean>
调用测试函数:
public static void main(String args[]){
ApplicationContext atc = new ClassPathXmlApplicationContext("spring.xml");
User user = (User) atc.getBean("subUser");
System.out.println(user.getBooks().size());
//print 5 即合并时相同元素会消除
}
如果将merge=”true”去掉,则测试打印结果为3,即父bean中的属性会被子bean中的覆盖
5. 自动装配
格式如:<bean autowire="no/byName/byType/constructor/audodetect/default">
装配类型 | 说明 |
---|---|
no | 默认值,不进行自动装配 |
byName | 根据属性名自动装配。此选项将检查容器并根据名字查找与属性完全一致的bean,并将其与属性自动装配 |
byType | 如果容器中存在一个与指定属性类型相同的bean,那么将与该属性自动装配;如果存在多个该类型bean,那么抛出异常,并指出不能使用byType方式进行自动装配;如果没有找到相匹配的bean,则什么事都不发生,也可以通过设置dependency-check=”objects”让Spring抛出异常。 |
constructor | 与byType方式类似,不同之处在于它应用于构造器参数。如果容器中没有找到与构造器参数类型一致的bean, 那么抛出异常 |
autodetect | 通过bean类的内省机制(introspection)来决定是使用constructor还是byType方式进行自动装配。如果发现默认的构造器,那么将使用byType方式,否则采用 constructor。 |
default | 由上级标签的default-autowire属性确定。 |
注意:在配置bean时,标签中Autowire属性的优先级比其上级标签高,即是说,如果在上级标签中定义default-autowire属性为byName,而在中定义为byType时,Spring IoC容器会优先使用标签的配置。
小结:
1. 使用自动装配,配置文件简洁了许多。但是,我们不论是使用byName还是byType的方法,Spring不一定就能很准确的为我们找到JavaBean依赖的对象。
2. 如果使用自动装配,Spring配置文件的可读性也大大降低,我们不能很容易的看出个bean之间的依赖关系,这也在一定程度上降低了程序可维护性;也容易造成潜在的错误,比如说通过byName来装配,如果将属性名字改了后,Spring就不会将其自动装配给Bean的属性了。
6. bean之间的关系
- 继承
<bean id="parent" class="xxx1" abstract="true">
<!-- 如果设置了abstract="true"父bean不会被初始化 -->
<bean id="child" class="xxx2" parent="parent">
<!-- 通过parent建立了两个bean的继承关系 -->
- 依赖
<bean id="bean" class="xxx" depends-on="dobean">
指定bean后于dobean创建和销毁(销毁只对作用域为singleton的bean才有效,因为只有“singleton”Bean能被Spring管理销毁)
关于“depends-on”有什么好处呢?主要是给出明确的初始化及销毁顺序,比如要初始化当前Bean时要确保指定Bean的资源准备好了,否则使用当前Bean时会看不到准备的资源;而在销毁时要先在当前Bean的把对指定Bean资源的引用释放掉才能销毁指定Bean,否则可能销毁指定Bean时而当前Bean还保持着资源访问,造成资源不能释放或释放错误。
基于java类注解的配置
spring提供了专门的application实现类来管理基于注解的Bean方式配置AnnotationConfigApplicationContext。我们通过@configuration来注解一个java类来标识一个容器,用@Bean来定义一个类,它有与xml文件配置中一样的属性如name、autowire、initMethod、destroyMethods等。如下面实例:
@Configuration//从地位上相当于是一个xml文件,用于定义Bean
@Import(Beans1.class)//引入另一个java类配置文件
public class Beans {
//定义一个Bean
@Scope("singleton")//设置Bean作用范围为单例
@Bean(name = "person",)
public User userMaker(){
User user = new User();
user.setName("user");
user.setPassword("password");
return user;
}
public static void main(String args[]){
ApplicationContext atc = new AnnotationConfigApplicationContext(Beans.class);
//还可以通过注册的方式来获取
/*
AnnotationConfigApplicationContext atc = new AnnotationConfigApplicationContext();
atc.register(Beans.class);
//atc.register(otherBeans.class);//还可以注册多个
atc.refresh();//刷新容器使注册生效
*/
User user = atc.getBean("person",User.class);
System.out.println(user.getName() + "——" + user.getPassword());
//执行main方法控制台会打印出: user——password
}
}
上面的userMaker方法相当于xml文件中的:
<bean name="person">
<property name="name" value="user"/>
<property name="password" value="password"/>
</bean>
基于普通注解的配置
使用形如@Component,@Repository,@Service,@Controller等注解。
- 后面三个注解的功能与第一个基本一致,但我们常将它们用于:
1. Repository : 对DAO实现类注解
2. Service : 对Service实现类注解
3. Controller : 对控制层实现类注解
注解实例如:
package test;
@Component("user")
public class User{}
- 则与
<bean id="user" class="test.User">
等价。 - 要使注解配置信息生效,需在容器中配置:
<context:component-scan base-package="test">
它会自动扫描test包下所有的类。 - 如果希望扫描特定的类,可以使用resource-pattern属性:`这样,只会扫描以User为前缀的包。
- 如果需要配置包含特定的类和去除特定的类,可使用
<context:include-filter />
和<context:exclude-filter />
标签。上述两个标签有”type”和”expression”两个属性,它们的参数如下所示
type | expression实例 | 命中过滤条件的类 |
---|---|---|
annotation | test.Service | test包下所有标识了@Service注解 |
assginable | test.BaseService | test包下所有继承或实现了BaseService的类 |
aspectj | 包名.aspectj表达式 | 对应包下满足aspectj表达式的类 |
regex | test.user* | test包下以user开头的类 |
custom | test.myTypeFilter | 通过代码定义过滤规则,其中myTypeFiler必须实现org.springframework.core.type.TypeFilter接口 |