Spring——Bean配置

Spring 配置Bean 

配置bean的形式(二种):

1.基于XML文件

2.基于注解

配置bean的方式(三种):

1.通过全类名(反射)

2.通过工厂方式(静态工厂/实例工厂)

3.FactoryBean

依赖注入方式(三种):

1.属性注入

2.构造器注入

3.工厂注入

注意事项:

都需要有默认的构造函数——无参的构造函数

如果没有写任何构造函数,系统则会自己创建一个默认的,如果有构造函数则不会创建

经过了解,但也没有证实,把配置和注入分为此三种,有的博客中把注入和配置搞混,导致有更多种的方式配置

1.属性注入(采用全类名反射配置bean)

使用<property>元素,使用name指定Bean的属性名称,value属性或<value>子节点指定属性值,需要在bean中有相应的set方法

有如下bean:

package com.chenx.spring.beans;

public class HelloWorld {

    private String name;
    
    public void setName(String name) {
        this.name = name;
    }

 
}

属性注入配置以上Bean如下:其中name指的是set方法的名字而不是字段的名称

<bean id="helloWorld" class="com.chenx.spring.beans.HelloWorld">
        <property name="name" value="ccc"></property>
</bean>

2.构造方法注入(采用全类名反射配置bean)

如上相同Bean配置,使用构造方法注入如下:需要在bean中有相应的构造方法

Bean:

package com.chenx.spring.beans;

public class HelloWorld {

    private String name;

    public HelloWorld(String name) {
        this.name = name;
    }

}

通过构造方法注入:

    <bean id="helloWorld" class="com.chenx.spring.beans.HelloWorld">
        <constructor-arg value="ccc"></constructor-arg>
    </bean>

(1)

           从上方构造方法注入可以看到,只用到了value这个属性,那么如何知道value是ccc的这个值赋给哪一个参数呢,可以看到默认是采用按照顺序的方式的,现在,可以通过index来定位此value的位置,如下:

  <bean id="helloWorld" class="com.chenx.spring.beans.HelloWorld">
        <constructor-arg value="ccc" index="0"></constructor-arg>
  </bean>

(2)

         如果在bean构造函数有另一个同样个数参数的构造方法,但是他们的类型不同,如此一来岂不是冲突了,现在,可以通过配置type——此字段的类型,来区分,如下:

    <bean id="helloWorld" class="com.chenx.spring.beans.HelloWorld">
        <constructor-arg value="ccc" index="0" type="java.lang.String"></constructor-arg>
    </bean>

(3)

    构造方法注入的另一种写法:通过value子节点的方式

    <bean id="helloWorld" class="com.chenx.spring.beans.HelloWorld">
        <constructor-arg>
            <value type="java.lang.String">ccc</value>
        </constructor-arg>
    </bean>

 (4)

     若是注入值中包含特殊字符需要使用<![CDATA[.....]]>写入  ,如我写入<ccc>:


    <bean id="helloWorld" class="com.chenx.spring.beans.HelloWorld">
        <constructor-arg>
            <value type="java.lang.String"><![CDATA[<ccc>]]></value>
        </constructor-arg>
    </bean>

////////插入——属性方式注入和构造方式注入的一些细节

    1.Bean的相互引用(属性注入方式)

       如有一个student 的bean,在此bean中包含上面的helloworld的一个字段,此bean的配置方法如下:

      studentBean:

package com.chenx.spring.beans;

public class Student {
    private String name;
    private String age;
    private HelloWorld helloWorld;

    public void setHelloWorld(HelloWorld helloWorld) {
        this.helloWorld = helloWorld;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(String age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age='" + age + '\'' +
                '}';
    }
}

  引用外部bean:student配置如下:通过ref 引用之前配置好的helloworld的bean (引用外部bean)

  <bean id="student" class="com.chenx.spring.beans.Student">
        <property name="age" value="ds"></property>
        <property name="name" value="123"></property>
        <property name="helloWorld" ref="helloWorld"></property>
    </bean>

或者是

   <bean id="student" class="com.chenx.spring.beans.Student">
        <property name="age" value="ds"></property>
        <property name="name" value="123"></property>
        <property name="helloWorld">
            <ref bean="helloWorld"></ref>
        </property>
    </bean>

引用内部bean:还可以通过自己创建引用内部bean:(只能在内部使用,不能被外部使用)

    <bean id="student" class="com.chenx.spring.beans.Student">
        <property name="age" value="ds"></property>
        <property name="name" value="123"></property>
        <property name="helloWorld">
            <bean class="com.chenx.spring.beans.HelloWorld">
                <constructor-arg value="ccc"></constructor-arg>
            </bean>
        </property>
    </bean>

    2.Bean的相互引用(构造器注入方式)

       如上相同的bean:采用构造器注入的方式

    <bean id="student2" class="com.chenx.spring.beans.Student">
        <constructor-arg value="dd"></constructor-arg>
        <constructor-arg value="11"></constructor-arg>
        <constructor-arg ref="helloWorld"></constructor-arg>
    </bean>

 

   3.null和级联属性

      null:

    <bean id="student2" class="com.chenx.spring.beans.Student">
        <constructor-arg value="dd"></constructor-arg>
        <constructor-arg value="11"></constructor-arg>
        <constructor-arg><null/></constructor-arg>
    </bean>

  级联属性:

可以通过hellowrold.name 修改 参数值

注意点:

1.首先必须初始化此参数,也就是有<constructor-arg ref="helloWorld"></constructor-arg>(hellowWorld配置过)

2.因为用到了hellowrold.name 所以需要有helloworld的get的方法(set也要有) ,还得在Helloworld中有setName的方法

    <bean id="student2" class="com.chenx.spring.beans.Student">
        <constructor-arg value="dd"></constructor-arg>
        <constructor-arg value="11"></constructor-arg>
        <constructor-arg ref="helloWorld"></constructor-arg>
        <property name="helloWorld.name" value="ss"></property>
    </bean>

4.集合属性

(1)List(Set类似)

(外部bean)

   在Student的里面加入List<HelloWorld> ,关于此来配置:(注意ref引入的需要都在同一个包中)

    <bean id="student" class="com.chenx.spring.beans.Student">
        <property name="name" value="dd"></property>
        <property name="age" value="111"></property>
        <property name="helloWorldList">
            <list>
                <ref bean="helloWorld"></ref>
                <ref bean="helloWorld"></ref>
            </list>
        </property>
    </bean>

(内部bean)

 <bean id="student" class="com.chenx.spring.beans.Student">
        <property name="name" value="dd"></property>
        <property name="age" value="111"></property>
        <property name="helloWorldList">
            <list>
                <bean class="com.chenx.spring.beans.HelloWorld">
                    <property name="name" value="11"></property>
                </bean>

                <bean class="com.chenx.spring.beans.HelloWorld">
                    <property name="name" value="12"></property>
                </bean>
            </list>
        </property>

    </bean>

(2)Map

    <bean id="student" class="com.chenx.spring.beans.Student">
        <property name="name" value="dd"></property>
        <property name="age" value="111"></property>
        <property name="map">
            <map>
                <entry key="A" value-ref="helloWorld"></entry>
                <entry key="B" value-ref="helloWorld"></entry>
            </map>
        </property>

    </bean>

(3) Properties(可以用来存数据库连接信息)

    <bean id="student" class="com.chenx.spring.beans.Student">
        <property name="name" value="dd"></property>
        <property name="age" value="111"></property>
        <property name="properties">
            <props>
                <prop key="username">xx</prop>
                <prop key="password">xx</prop>
                <prop key="driverclass">xx</prop>
                <prop key="url">xxx</prop>
            </props>
        </property>

    </bean>

5.使用util scheme配置独立的Bean, 以便多次共享引用

  在配置的过程中会遇到配置bean的时候,创建重复的代码,现在创建一个独立的bean以供相同引用的代码使用,无需再重复编写


    <bean id="student" class="com.chenx.spring.beans.Student">
        <property name="name" value="dd"></property>
        <property name="age" value="111"></property>
        <property name="list" ref="hellos"></property>

    </bean>
    
    <util:list id="hellos">
        <ref bean="helloWorld"></ref>
        <ref bean="helloWorld"></ref>
        <ref bean="helloWorld"></ref>
        <ref bean="helloWorld"></ref>
    </util:list>

 

6.使用p命名空间 为Bean的属性赋值    

    为了简化Xml文件的配置

  <bean id="student" class="com.chenx.spring.beans.Student" p:name="yy" p:age="rr" p:list-ref="hellos"></bean>

7.自动装配

Spring IOC容器可以帮助我们自动装配Bean 只需要在<bean>的autowire属性里指定自动装配模式

byType:根据类型自动装配,如果有多个类型相同的bean,则不能装配

byName:根据名称自动装配,必须将目标Bean的名称和属性名完全相同

此方式有缺陷,一旦配置则会匹配所有属性,不够灵活

   <bean id="student" class="com.chenx.spring.beans.Student" p:name="yy" p:age="rr" autowire="byName"></bean>

8.继承

使用parent 属性 继承配置 ,被继承的bean称为父bean,继承这个bean的bean是子bean

子bean中父bean中继承其属性,子bean也可覆盖bean中的属性

父bean可用作模板,也可作为实例,可使用属性abstract抽象属性配置bean使其不可作为实例,只能被继承

 <bean id="student" class="com.chenx.spring.beans.Student" p:name="yy" p:age="rr"></bean>
 <bean id="student2" class="com.chenx.spring.beans.Student" parent="student" p:name="pp"></bean>
    

  作为abstrace bean 用作继承:(一个bean如果没有class 其必须是抽象bean)autowire,abstract不会被继承

<bean id="student" p:name="yy" p:age="rr" abstract="true"></bean>
<bean id="student2" class="com.chenx.spring.beans.Student" parent="student" p:name="pp"></bean>

9.依赖

 Spring通过depends-on属性设定bean前置依赖的bean ,前置依赖bean会在本bean实例化之前先创建好

如果有多个依赖,可以通过逗号,空格方式配置bean的名称(依赖并不是把其配置到此bean中,只是在此之前必须配置此依赖的bean)

    <bean id="helloWorld" class="com.chenx.spring.beans.HelloWorld" p:name="111"></bean>
    <bean id="student" class="com.chenx.spring.beans.Student" p:name="yy" 
            p:age="rr" depends-on="helloWorld" ></bean>

10.作用域

使用scope属性来配置bean的作用域

singleton:单例:默认值 :容器初始化时创建bean实例,在整个容器的生命周期里只创建这一个bean,换句话说,通过getBean()获取到的实例都是同一个。

prototype:多例: 容器初始话的时候不创建bean的实例,而在每次请求时都创建一个新的bean实例,并返回

<bean id="helloWorld" class="com.chenx.spring.beans.HelloWorld" p:name="111" scope="prototype"></bean>

3.工厂方式注入(采用静态工厂方法配置)

   介绍完属性方法注入和构造器注入之后介绍静态方法注入,可以看出来,属性和构造器其实不同之处在于bean中一个是使用set方法一个是使用构造器的方式,在配置文件中相应的一个使用property 属性参数,一个使用constructor-arg进行配置。

 全类名反射配置:像是在配置文件中说明你要什么,然后IOC就会自动把相应的东西给你

 工厂方式配置:像是多了一个环节,在属性和构造器的基础上多了一个膜具的工厂(需要自己配置膜具),工厂提供了一个窗口,然后你需要在配置文件中告知此窗口你需要哪个膜具(只需要膜具的名称),接着就会帮你自动注入

总结:相比而言,全类名反射配置有点像自己造膜具,而工厂方式像是自己造膜具,接着取膜具,全类名反射配置显然少了一个步骤更方便。

 静态工厂方式配置:

 首先创建工厂(staticfactory),创建膜具(map),开辟窗口(getmap)

package com.chenx.spring.beans;

import java.util.HashMap;
import java.util.Map;

public class StaticFactory {
    private static Map<String,HelloWorld> map=new HashMap<String,HelloWorld>();

    static {
        map.put("aa",new HelloWorld("1"));
        map.put("bb",new HelloWorld("2"));
    }

    public static HelloWorld getMap(String name) {
        return map.get(name);
    }
}

  工厂方式注入具体配置:哪个工厂(class), 哪个窗口(factory-method), 哪个膜具(constructor-arg)

    <bean id="helloWorld" factory-method="getMap"  class="com.chenx.spring.beans.StaticFactory">
        <constructor-arg value="aa"></constructor-arg>
    </bean>

4.工厂方法注入(采用实例工厂方法配置)

  实例工厂方式和静态工厂方式注入有点类似,也需要加一个工厂的bean,只不过把static去了

  

package com.chenx.spring.beans;

import java.util.HashMap;
import java.util.Map;

public class InstanceFactory {
    private Map<String,HelloWorld> map=null;

    public InstanceFactory(){
        map=new HashMap<String,HelloWorld>();
        map.put("aa",new HelloWorld("1"));
        map.put("vv",new HelloWorld("2"));
    }

    public HelloWorld getMap(String name) {
        return map.get(name);
    }
}

  配置文件:实例工厂需要先实例化工厂

   <bean id="factory" class="com.chenx.spring.beans.InstanceFactory"></bean>
   <bean id="helloWorld" factory-bean="factory" factory-method="getMap">
       <constructor-arg value="vv"></constructor-arg>
   </bean>

5.FactoryBean配置

///摘抄

一般情况下,Spring通过反射机制利用<bean>的class属性指定实现类实例化Bean,在某些情况下,实例化Bean过程比较复杂,如果按照传统的方式,则需要在<bean>中提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。Spring为此提供了一个org.springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑。FactoryBean接口对于Spring框架来说占用重要的地位,Spring自身就提供了70多个FactoryBean的实现。它们隐藏了实例化一些复杂Bean的细节,给上层应用带来了便利。从Spring3.0开始,FactoryBean开始支持泛型,即接口声明改为FactoryBean<T>的形式。以Bean结尾,表示它是一个Bean,不同于普通Bean的是:它是实现了FactoryBean<T>接口的Bean,根据该Bean的ID从BeanFactory中获取的实际上是FactoryBean的getObject()返回的对象,而不是FactoryBean本身。

//My

  总之更加灵活

  自定义FactoryBean步骤:

  创建一个bean implements FactoryBean<> ,接着override 其中的三个方法,相当于配置bean:(getobject返回的实例)(getobjectType返回的类型)(isSingleton是否是单例)

package com.chenx.spring.beans;

import org.springframework.beans.factory.FactoryBean;

public class MyFactoryBean implements FactoryBean<HelloWorld> {
    
    @Override
    public HelloWorld getObject() throws Exception {
        return new HelloWorld("1");
    }

    @Override
    public Class<?> getObjectType() {
        return HelloWorld.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

}

  配置文件:(配置此后,其返回的是getobject中的返回值)

    <bean id="helloWorld" class="com.chenx.spring.beans.MyFactoryBean"></bean>

  还可以在自定义FactoryBean中加入属性,然后就可在配置文件中配置

6.基于注解的方式配置Bean

   转载:!!

   https://blog.csdn.net/u011266694/article/details/78918382

  THE END

发布了73 篇原创文章 · 获赞 14 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/daguniang123/article/details/92788812