打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
spring的Bean的基础配置2

Spring IOC基础(Spring2.0)

分类: Spring 177人阅读 评论(0) 收藏 举报
 IOC基本原理:
在企业信息中由不同的Bean来封装不同的数据与功能.
用元数据来描述Bean之间的逻辑,并形成企业业务逻辑.
用容器来根据业务逻辑描述实现每个功能,达到整个业务逻辑的实现.
该思想的优点降低了每个功能模块间的耦合度.
该思想的实现核心是元数据描述与容器.

Spring支持三种配置元数据格式:
XML格式。(结构比较复杂的)
Java属性文件格式。(结构简单的配置文件)
Spring公共API编程实现。

容器的职责包括:
实例化、定位、配置应用程序中的对象、建立这些对象间的业务逻辑依赖。
通熟点就是用来管理bean的产生装配和销毁等

Spring IoC容器的基础包
org.springframework.beans
org.springframework.context
Spring IoC容器的基础接口
BeanFactory:供了配制框架及基本功能
ApplicationContext:
1)增加了更多支持企业核心内容的功能。ApplicationContext完全由BeanFactory扩展而来,因而BeanFactory所具备的能力和行为也适用于ApplicationContext。
2)更易与Spring AOP集成、消息资源处理(国际化处理)、事件传递及各种不同应用层的context实现

几种容器的访问使用:
1.使用XmlBeanFactory
InputStream is = new FileInputStream("beans.xml");
BeanFactory factory = new XmlBeanFactory(is);
2.使用ClassPathXmlApplicationContext
ApplicationContext context = new ClassPathXmlApplicationContext( new String[]{"applicationContext.xml", applicationContext-part2.xml"});
(最常见的)
3.使用FileSystemXmlApplicationContext
ApplicationContext context = new FileSystemXmlApplicationContext("beans-config.xml");

配置文件的描述:
结构:
beans (description?,(import | alias | bean)*)
bean (description?,(meta | constructor-arg |
property | lookup-method | replaced-method)*)
import EMPTY
alias EMPTY

配置文件头样例:
<?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:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd">

DTD结构文件头
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
"http://www.springframework.org/dtd/spring-beans-2.0.dtd">

Bean实例化有两种主要方式
1.在大多数情况下,容器将直接通过反射调用指定类的构造器来创建bean
    用构造器来实例化
2.在极少数情况下,容器将调用类的工厂方法来创建bean实例
1)使用静态工厂方法实例化
2)使用实例工厂方法实例化

在对bean进行定义时,除了使用id属性来指定名称之外,为了提供多个名称,需要通过alias属性来加以指定。而所有的这些名称都指向同一个bean,在某些情况下提供别名非常有用,比如为了让应用的每一个组件能更容易的对公共组件进行引用。
然而,在定义bean时就指定所有的别名并不是总是恰当的。有时我们期望能在当前位置为那些在别处定义的bean引入别名。在XML配置文件中,可用单独的<alias/> 元素来完成bean别名的定义。
 使用别名的优点:
   不同的程序就可通过不同的名字来引用同一个数据源而互不干扰.适合同一项目下的不同模块.
例子-Bean的别名
alias的属性
<!ATTLIST alias name CDATA #REQUIRED>
<!ATTLIST alias alias CDATA #REQUIRED>
例子:
<!--先定义普通bean-->
<bean id="book" class="BeanAlias">
    <property name="id">
        <value>1</value>
    </property>
    <property name="name">
        <value>三国演义</value>
    </property>
    <property name="author">
        <value>罗贯中</value>
    </property>
</bean>
<!--定义类的别名,其中,name必须是前面bean 的id,这样mybook才会指向BeanAlias-->
<alias name="book" alias="mybook"/>


将XML配置文件分拆成多个部分是非常有用的。
有两种方式拆分:
1.将文件路径作为字符串数组传给ApplicationContext构
造器。
2.在XML中使用一个或多个的<import/>元素来从另外一个或多个文件加载bean定义。
注意:所有的<import/>元素必须放在<bean/>元素之前以完成bean定义的导入。
XML例子:
<beans>
    <import resource="services.xml"/>
    <import resource="resources/messageSource.xml"/>
    <import resource="/resources/themeSource.xml"/>
    <bean id="bean1" class="..."/>
    <bean id="bean2" class="..."/>
</beans>
说明:
    采用的都是相对路径,因此,此例中的services.xml一定要与导入文件放在同一目录或类路径,而messageSource.xml和
themeSource.xml的文件位置必须放在导入文件所在目录下的resources目录中。正如你所看到的那样,开头的斜杠‘/’实际上可忽略。

注入依赖
主要有两种注入方式:
1.Setter注入(通过bean中的set方法实现对属性的赋值)
2.构造器注入(给构造参数赋值)
例子:
存在一个类
package books;
public class Books{
    private int id;
    private String bookName;       
    private String author;
    private double price;   
    //无参构造
    public Book(){
    }
    //带参构造
    public Book(int id,String bookName,String author){
        this.id=id;
        this.bookName=bookName;
    }
    public Book(String author){
         this.author=author;
    }
    //三个属性的set/get方法
}
<bean id="book" class="books.Books">
    <!--构造,index为参数位置-->   
    <constructor-arg index="0">
    <!--第一个参数的值-->
        <value>5</value>
    </constructor-arg>
    <!--第二个构造参数-->
    <constructor-arg index="1" value="鹿鼎记"
        type="java.lang.String">
    </constructor-arg>
    <!--构造参数-->
    <constructor-arg>
        <value>金庸</value>
    </constructor-arg>
    <!--属性-->
    <property name="price">
        <value>56</value>
    </property>
</bean>
用静态方法实例化bean并注入
public class Books implements Serializable {
    private int id;
    private String name;
    private String author;
    public static Books createInstance(int id,String name,String author){
        Books book=new Books();
        book.id=id;
        book.name=name;
        book.author=author;
        return book;
    }
}
<bean id="book" class="books.Books" factory-method="createInstance">
    <constructor-arg index="0">
        <value>5</value>
    </constructor-arg>
    <constructor-arg index="1" value="鹿鼎记" type="java.lang.String">
    </constructor-arg>
    <constructor-arg>
        <value>金庸</value>
    </constructor-arg>
    <property name="author">
        <value>布什</value>
    </property>
</bean>

注入来源
property (description?, meta*,(bean | ref | idref | value | null | list | set | map | props))
    constructor-arg (description?,(bean | ref | idref  | value | null | list | set | map | props))
指定注入类型:
<!ATTLIST value type CDATA #IMPLIED>

注入来源-bean
public class Books implements Serializable {
    private int id;
    private String name;
    private Date date;
     ......
}
 ===============================================
<bean id="book" class="books.Books">
    <property name="id">
        <value>88</value>
    </property>
    <property name="name">
        <value>88</value>
    </property>
    <!--属性如果是其它类的话,不能用value,如果是其它配置文件的bean,则用<ref bean="nowdate"></ref>,如果是本配置文件的为:<ref local="nowdate"></ref>-->
    <property name="date">
        <bean name="date" class="java.util.Date"></bean>
    </property>
</bean>

public class Books implements Serializable {
    private int id;
    private String name;
    private Date date;
    private String pubdate;
……
}
========================
<bean id="nowdate" class="java.util.Date">
</bean>
<bean id="book" class="books.Books">
    <property name="id">
        <value>88</value>
    </property>
    <property name="name">
        <value>88</value>
    </property>
    <property name="date">
    <!--<bean name="date" class="java.util.Date"></bean>-->
        <ref bean="nowdate"></ref>
    </property>
    <!-- idref元素用来将容器内其它bean的id传给<constructor-arg/> 或<property/>元素,同时提供错误验证功能。-->
    <property name="pubdate">
        <idref bean="nowdate"></idref>
    </property>
</bean>

注入来源-list /set/map/properties/数组的写法:
public class SomeBean {
    private String[] someStrArray;
    private Some[] someObjArray;
    private List someList;
    private Map someMap;
    private Set someSet;
    private Properties someProps;
}
<!--数组属性的写法-->
<property name="someStrArray">
    <list>
        <value>Hello</value>
        <value>Welcome</value>
    </list>
</property>
<property name="someObjArray">
    <list>
        <ref bean="some1"/>
        <ref bean="some2"/>
    </list>
</property>
<!--list-->
<property name="someList">
    <list>
        <value>ListTest</value>
        <ref bean="some1"/>
        <ref bean="some2"/>
    </list>
</property>
<!--set-->
<property name="someSet">
    <set>
        <value>ListTest</value>
        <ref bean="some1"/>
        <ref bean="some2"/>
    </set>
</property>
<!--properties-->
<property name="somePorps">
    <props>
        <prop key="k1">Value1</prop>
        <prop key="k2">Value2</prop>
        <prop key="k3">Value3</prop>
    </props>
</property>
<property name="somePorps">
    <value>
        k1=Value1
        k2=Value2
        k3=Value3
    </value>
</property>
<!--map-->
<property name="someMap">
    <map>
        <entry key="MapTest">
            <value>Hello!Justin!</value>
        </entry>
        <entry key="someKey1">
            <ref bean="some1"/>
        </entry>
    </map>
</property>

集合合并
从2.0开始,Spring IoC容器将支持集合的合并。这样我们可以定义parent-style和childstyle的<list/>、<map />、<set/>或<props/>元素,子集合的值从其父集合继承和覆盖而来;也就是说,父子集合元素合并后的值就是子集合中的最终结果,而且子集合中的元素值将覆盖父集全中对应的值。
<beans>
    <bean id="parent" abstract="true" class="example.ComplexObject">
        <property name="adminEmails">
            <props>
                <prop key="administrator">administrator@somecompany.com</prop>
                <prop key="support">support@somecompany.com</prop>
            </props>
        </property>
    </bean>
    <bean id="child" parent="parent">
        <property name="adminEmails">
            <props merge="true">
                <prop key="sales">sales@somecompany.com</prop>
                <prop key="support">support@somecompany.co.uk</prop>
            </props>
        </property>
    </bean>
<beans>

强类型集合与泛型(1.5后支持)
public class Foo {
    private Map<String, Float> accounts;
    public void setAccounts(Map<String, Float> accounts) {
        this.accounts = accounts;
    }
}
=================强类型适合数据自动转换
<beans>
    <bean id="foo" class="x.y.Foo">
        <property name="accounts">
            <map>
                <entry key="one" value="9.99"/>
                <entry key="two" value="2.75"/>
                <entry key="six" value="3.99"/>
            </map>
        </property>
    </bean>
</beans>

例子-参数类型
<bean id="exampleBean" class="examples.ExampleBean">
    <constructor-arg type="int" value="7500000"/>
    <constructor-arg type="java.lang.String" value="42"/>
</bean>

构造器参数自动匹配与index:
构造器参数将根据类型来进行匹配。如果bean定义中的构造器参数类型明确,那么bean定义中的参数顺序就是对应构造器参数的顺序。
例子
package x.y;
public class Foo {
public Foo(Bar bar, Baz baz) {
// ... }
}
============
<beans>
    <bean name="foo" class="x.y.Foo">
        <constructor-arg>
            <bean class="x.y.Bar"/>
        </constructor-arg>
        <constructor-arg>
            <bean class="x.y.Baz"/>
        </constructor-arg>
    </bean>
</beans>
通过使用index属性可以显式的指定构造器参数出现顺序

XML配置的快捷方式
方式一:
<property name="myProperty">
    <value>hello</value>
</property>
方式二:
<property name="myProperty" value="hello"/>
这两种方式等价,方式二是方式一的简写

依赖不完全依靠注入实现
1.一个bean对另一个bean的依赖最简单的做法就是将一个bean设置为另外一个bean的属性。
2.还有另外一种方法,如果一个bean能感知IoC容器,只要给出它所依赖的id,那么就可以通过编程的方式从容器中
取得它所依赖的对象。
例子:
<bean id="beanOne" class="ExampleBean" dependson="manager, accountDao">
    <property name="manager" ref="manager" />
</bean>
<bean id="manager" class="ManagerBean" />
<bean id="accountDao" class="x.y.jdbc.JdbcAccountDao" />

延迟初始化bean- lazy-init属性
ApplicationContext实现的默认行为就是在启动时将所有singleton bean提前进行实例化。提前实例化意味着作为初始化过程的一部分,ApplicationContext实例会创建并配置所有的singleton bean。
如果你不想让一个singleton bean在ApplicationContext实现在初始化时被提前实例化,那么可以将bean设置为延迟实例化。一个延迟初始化bean将告诉IoC 容器是在启动时还是在第一次被用到时实例化。
<bean id="lazy" class="com.foo.ExpensiveToCreateBean" lazyinit="true">
......
</bean>
<bean name="not.lazy"   class="com.foo.AnotherBean">
......
</bean>

自动装配-autowire 属性
<!ATTLIST bean autowire (no | byName | byType | constructor | autodetect | default) "default">
Spring IoC容器可以自动装配(autowire)相互协作bean之间的关联关系。因此,如果可能的话,可以自动让Spring通过检查BeanFactory中的内容,来替我们指定bean的协作者(其他被依赖的bean)。由于autowire可以针对单个bean进行设置,因此可以让有些bean使用autowire,有些bean不采用。autowire的方便之处在减少或者消除属性或构造器参数的设置,这样可以减少配置文件的大小与配置过程.
如果直接使用property和constructor-arg注入依赖的话,那么将总是覆盖自动装配。而且目前也不支持简单类型的自动装配,这里所说的简单类型包括基本类型、String、Class以及简单类型的数组

自动装配的模式和说明
1.no
不使用自动装配。必须通过ref元素指定依赖,这是默认设置。由于显式指定协作者可以使配置更灵活、更清晰,因此对于较大的部署配置,推荐采用该设置。而且在某种程度上,它也是系统架构的一种文档形式。
2.byName
根据属性名自动装配。此选项将检查容器并根据名字查找与属性完全一致的bean,并将其与属性自动装配。例如,在bean定义中将autowire设置为by name,而该bean包含master属性(同时提供setMaster(..)方法),Spring就会查找名为master的bean定义,并用它来装配给master属性。
3.byType
如果容器中存在一个与指定属性类型相同的bean,那么将与该属性自动装配。如果存在多个该类型的bean,那么将会抛出异常,并指出不能使用byType方式进行自动装配。若没有找到相匹配的bean,则什么事都不发生,属性也不会被设置。如果你不希望这样,那么可以通过设置dependency-check="objects"让Spring抛出异常。
4.constructor
与byType的方式类似,不同之处在于它应用于构造器参数。如果在容器中没有找到与构造器参数类型一致的bean,那么将会抛出异常。
5.autodetect
通过bean类的自省机制(introspection)来决定是使用constructor还是byType方式进行自动装配。如果发现默认的构造器,那么将使用byType方式。

设置Bean使自动装配失效-autowire-candidate 属性
对单个bean设置其是否为被自动装配对象。当采用XML格式配置bean时,<bean/>元素的autowire-candidate属性可被设为false,这样容器在查找自动装配对象时将不考虑该bean。
这并不意味着被排除的bean自己就不能使用自动装配来注入其他bean,它是可以的,或者更准确地说,应该是它不会被考虑作为其他bean自动装配的候选者。

依赖检查-dependency-check属性
Spring除了能对容器中bean的依赖设置进行检查外。还可以检查bean定义中实际属性值的设置,也包括采用自动装配方式设置属性值的检查。
当需要确保bean的所有属性值(或者属性类型)被正确设置的时候,那么这个功能会非常有用。当然,在很多情况下,bean类的某些属性会具有默认值,或者有些属性并不会在所有场景下使用,因此这项功能会存在一定的局限性。就像自动装配一样,依赖检查也可以针对每一个bean进行设置。依赖检查默认为not, 它有几种不同的使用模式

依赖检查使用模式
模式和说明
none  没有依赖检查,如果bean的属性没有值的话可以不用设置。
simple 对于原始类型及集合(除协作者外的一切东西)执行依赖检查
object 仅对协作者执行依赖检查
all 对协作者,原始类型及集合执行依赖检查




方法注入:
解决方案-方法注入
放弃控制反转。通过实现BeanFactoryAware接口,让bean A能够感知bean 容器,并且在需要的时候通过使用getBean("B")方式向容器请求一个新的bean B实例。
例子:
public class Books implements Serializable,BeanFactoryAware{
    private int id;
    private String name;
    private Date date;
    private BeanFactory factory;
    public void setBeanFactory(BeanFactory factory) {
        this.factory = factory;
    }
    public Date getDate() {
        return (Date) this.factory.getBean("date");
    }
……
}

<bean id="date" class="java.util.Date">
</bean>
<bean id="book" class="books.Books">
    <property name="id">
        <value>88</value>
    </property>
    <property name="name">
        <value>88</value>
    </property>
</bean>
适合每次使用的注入bean都需要重新生成.
我们的例子中可以观察到每次都调用的是date对象的不同实例.

另外一种方法注入-lookup
Lookup方法注入利用了容器的覆盖受容器管理的bean方法的能力,从而返回指定名字的bean实例。
Lookup方法注入的内部机制是Spring利用了CGLIB库在运行时生成二进制代码功能,通过动态创建Lookup方法bean的子类
而达到复写Lookup方法的目的。
public class MyClass {
    public void method() {
        System.out.println("调用类中的方法method!");
    }
}
class MethodInterceptorImpl implements MethodInterceptor {
    public Object intercept(Object obj,Method method,Object[] args,MethodProxy proxy) throws
Throwable {
        System.out.println(method);
        System.out.println(obj.getClass());
        proxy.invokeSuper(obj, args);
        return null;
     }
}
public class CGlibMain {
    public static void main(String[] args) {
//产生的新的类
        Enhancer enhancer = new Enhancer();
//制定父类
        enhancer.setSuperclass(MyClass.class);
//设置回调接口
        enhancer.setCallback( new MethodInterceptorImpl() );
//新类的一个实例
        MyClass my = (MyClass)enhancer.create();
        my.method();
    }
}

Singleton作用域
1.Prototype作用域
2.其他作用域
3.自定义作用域


例子-Singleton作用域配置
<bean id=“…." class=“…"/>
Singleton作用域是Spring中的缺省作用域。
<bean id=“…" class=“…" scope="singleton"/>
<bean id=“…" class=“…" singleton="true"/>

Prototype作用域概述
Prototype作用域的bean会导致在每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方
法)时都会创建一个新的bean实例。
一般原则,对所有有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用
<bean id=“…" class=“…" scope="prototype"/>
<bean id=“…" class=“…" singleton="false"/>
关于作用域的说明
对于prototype作用域的bean,Spring不能对一个prototype bean的整个生命周期负责:容器在初始化、配置、装饰或者是装配完一个prototype实例后,将它交给客户端,随后就对该prototype实例放弃管理。
不管何种作用域,容器都会调用所有对象的初始化生命周期回调方法,而对prototype而言,任何配置好的析构生命周期回调方法都将不会被调用。
清除prototype作用域的对象并释放任何prototype bean所持有的昂贵资源,都是客户端代码的职责
他作用域,即request、session以及global session仅在基于web的应用中使用.
global session是专门为portlet而设计的.
如果在普通的Spring IoC容器中,比如像XmlBeanFactory或ClassPathXmlApplicationContext,尝试使用这些作用域,你将会得到一个IllegalStateException异常。

IoC容器的关闭
AbstractApplicationContext ctx = new ClassPathXmlApplicationContext(…);
ctx.registerShutdownHook();
注意该方法来自AbstractApplicationContext ,
包含:
ClassPathXmlApplicationContext ,
FileSystemXmlApplicationContext

容器控制bean的周期总结
调用构造器.
属性注入.
BeanNameAware 接口提供Bean ID.
BeanClassLoaderAware接口提供当前环境的ClassLoader.
BeanFactoryAware 提供产生该Bean的BeanFactory.
InitializingBean提供其他初始化操作接口.
DisposableBean 提供bean释放前的用户操作接口.
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
在EasyJWeb使用spring容器
Spring系统学习
spring的第一天
解决Spring bean Date转化问题
spring注入null对象
Spring中事物管理一二
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服