spring学习笔记(3)Bean命名、定义与配置

基于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>
  1. class为bean的全限定名,指向classpath下类定义所在位置
  2. id为bean的唯一名称标识,在整个IOC容器中必须是唯一的。它必须以字母开头,后面可以是数字、连字符、下划线、句号、冒号等符号。
  3. name也是bean的名称标识,但它可在多个bean命名中重复,几乎可以使用任何符号如问号或以数字开头等。
    以下是几点需要注意的:

    1. id和name都可以指定多个名字,名字之间可用逗号、分号、或者空格间隔
    2. 如果配置了多个name相同的bean,通过getBean方法获取Bean时,将返回最后声明的那个Bean(前面的被后面覆盖)
    3. 如果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”)获取第二个,以此类推。

  4. Bean的每一个属性对应一个property标签,name为属性名,value为注入时为属性构造的数值

  5. lazy-int指明bean的初始化时机
  6. scope:bean的作用域(后面两种在web应用环境下呈现。
    1. singleton:整个IOC容器共享一个Bean
    2. prototype:每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的bean实例.
    3. request:每次HTTP请求将会生成各自的bean实例
    4. 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> booksString[] 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之间的关系

  1. 继承
<bean id="parent" class="xxx1" abstract="true">
<!-- 如果设置了abstract="true"父bean不会被初始化 -->
<bean id="child" class="xxx2" parent="parent">
<!-- 通过parent建立了两个bean的继承关系 -->
  1. 依赖
<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”两个属性,它们的参数如下所示
typeexpression实例命中过滤条件的类
annotationtest.Servicetest包下所有标识了@Service注解
assginabletest.BaseServicetest包下所有继承或实现了BaseService的类
aspectj包名.aspectj表达式对应包下满足aspectj表达式的类
regextest.user*test包下以user开头的类
customtest.myTypeFilter通过代码定义过滤规则,其中myTypeFiler必须实现org.springframework.core.type.TypeFilter接口
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值