`

转:Spring装配bean

阅读更多
在Spring中,对象间的协作是通过IoC机制完成的。
反向控制也叫依赖注入(Dependency Injection,DI),简单来说就是将JavaBean需要的
对象通过配置文件加载进来。

Spring提供了两种装配Bean的容器,一是BeanFactoy,另一个是ApplicationContext。
两者做为容器,所有的Bean都应该通过容器装配,而容器也知道自己都装配了哪些Bean。

Bean装配实际上就是让容器知道程序中都有哪些Bean,可以通过以下两种方式实现:
配置文件(最为常用,体现了依赖注入DI的思想)
编程方式(写的过程中向BeanFactory去注册)

ApplicationContext与BeanFactory都是接口,ApplicationContext是由BeanFactory
接口扩展而来,它增强了BeanFactory的功能。

Bean容器能够加载的对象并不一定是严格遵循JavaBeans规范的Java类,任何可实例化的类都
可以通过Spring Bean容器加载进来。通常称这些类为POJO。

要记住,BeanFactory不仅仅只具备实例化Bean的功能,它还知道所有的Bean,可以配置和管理它们。


Spring给出一些BeanFactory的实现类,其中最为常用的是XmlBeanFactory。
1、通过文件系统
Resource res = new FileSystemResource("beans.xml");
XmlBeanFactory factory = new XmlBeanFactory(res);
2、通过类路径
ClassPathResource res = new ClassPathResource("beans.xml");
XmlBeanFactory factory = new XmlBeanFactory(res);
3、通过ApplicationContext加载
ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(
new String[] {"applicationContext.xml", "applicationContext-part2.xml"});
BeanFactory factory = (BeanFactory) appContext;


sping-frameword-1.2.7-with-dependencies中的dist里面是spring的包
将其中的spring.jar加入工程的类路径里面,下一步是写个javaBean

package bean ;

public class HelloBean
{
public HelloBean
{
   System.out.println("init!");
}
private String msg ;

//加上getter和setter方法
};

public class Demo
{
public static void main(String[] args)
{
   Resource res = new ClassPathResource("bean.xml") ;
   //配置文件放在类路径的根路径下
   BeanFactory factory = new XmlBeanFactory(res) ;
   //在dist文件夹里面有spring-beans的dtd文档
   HelloBean bean = (HelloBean)factory.getBean("hello") ;
   //根据xml配置文件中的id号去找bean,然后从这个工厂中取出bean
   System.out.println(bean.getMsg());

   HelloBean bean1 = (HelloBean)factory.getBean("hello") ;
   System.out.println(bean==bean1); //因为配置文件中的singleton设置为true,
   //故是单例模式,所以两个bean肯定一样,所以打印true

   //只有ApplicationContext才能实现bean的非延迟加载功能,所以要想让bean中的
   //"init!"字符串在"before getbean!"字符串之前显示的话,那么首先必须得是单例模式,
   //然后还得设置lazy-init="false",才可以做到,如果singleton="false"的话,是无法
   //做到非延迟加载的!可以通过下面的代码来验证,看"before getbean!"和"init!"这两个
   //字符串出现的先后顺序就一目了然了。
   ApplicationContext factory = new ClassPathXmlApplicationContext("bean.xml");
   System.out.println("before getbean!");
   HelloBean bean2 = (HelloBean)factory.getBean("hello");
}
}

配置文件bean.xml:

将<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
   "http://www.springframework.org/dtd/spring-beans.dtd">
拷贝进去……

<beans>
//singleton属性表明容器的bean是否使用单例模式……
//默认情况下,beanFactory就是延迟加载的
<bean id="hello" class="bean.HelloBean" singleton="true"
    lazy-init="false">
   <property name="msg">
    <value>Hello,Spring!</value>
   </property>
</bean>

</beans>

//上面的配置文件将属性的值注入到bean的属性中,这就是依赖注入的一个例子
//同时将那个javaBean注册到容器中
通常可以通过三种方式装配Bean

通过setter方法
通过构造函数
自动装配
其中,使用setter方法装配Bean是最为常用的。

如下代码的执行结果是什么?
FirstBean bean = (FirstBean)factory.getBean("my");
FirstBean bean1 = (FirstBean)factory.getBean("my");
System.out.println(bean==bean1);
结果依赖于bean元素的singleton属性,如果设置true,则以单例模式加载bean,
则永远指向同一个bean;反之则每次实例化一个。
也即在单例模式下,BeanFactory维护所有的bean

如果想让一个单例模式的bean被清理掉的话,不能简单的将bean置为null,而是必须使用
destroySingletons方法
还有一个destroyBean(String beanName,Object bean)
这两个方法都可以来垃圾回收单例模式中的bean


--------------------------------------------------------------


延迟加载:

如下代码执行的结果是什么?
System.out.println("before loading");
FirstBean bean = (FirstBean)factory.getBean("my");
System.out.println(“after loading”);
在bean的构造函数中,包含:
System.out.println(“bean init”);
结果依赖于bean的lazy-init属性,如果设置为true,则在第一次加载该bean时初始化;
否则在初始化容器时就加载所有bean。
延迟加载仅在bean单例模式下起作用。

-------------------------------------------------------------------------


初始化和清理:

Spring的初始化肯定是在依赖注入(属性设置)全部完成后才去做的。
框架提供的初始化方法肯定是先于我们自己定义的初始化方法的!比如,如果继承了
InitializingBean的话,会有一个这个接口提供的初始化方法,叫做afterPropertySet,
它的执行就是先于你定义的初始化方法的……

同理,DisposableBean接口中也定义了一个清理的方法,这个方法肯定也是先于你定义的
清理方法的!

建议使用你自己定义的初始化和清理方法,不要使用容器提供的,这样可以避免bean被污染!!!

在许多情况下,需要在对象加载后立即初始化资源,而在删除对象前先清理资源
在spring中,提供了两种方式实现初始化和清理工作。
通过设置bean的init-method和destroy-method指定初始与清理方法
通过实现InitializingBean及DisposableBean接口,由容器在加载与删除bean时自动调用。

//既然定义了一个init方法,所以可以在javaBean中设置下面的初始化方法:
public void init()
{

}

//同样销毁方法也可以类似的定义:
public void destroy()
{

}
//特别注意,如果你想运行上面自定义的destroy方法的话,你必须首先执行
factory.destroySingletons();
//否则不会去执行你上面自定义的destroy方法的!

原型bean在创建之后就脱离了factory的管理,所以呢,对于原型bean,只能初始化,而
不可以清理

<bean id="first" class="mybeans.FirstBean" init-method="init"
   destroy-method="destroy" >
      <property name="message">
        <value>Hi, Rod Johnson</value>
      </property>
</bean>
可以通过destroySingletons方法删除所有单例bean
原型bean在创建后即脱离BeanFactory的维护,所以只能调用初始化方法,而不能做清理工作。

===========================================================================

下午课程开始:

public class HelloBean implements BeanNameAware, BeanFactoryAware
{
private BeanFactory factory ;
private String name ;

public void setBeanName(String a)//由BeanNameAware继承来
{
   this.name = a ;
}

//由BeanFactoryAware继承而来。
public void setBeanFactory(BeanFactory factory)
    throws BeanException
{
   this.factory = factory
}
}

-------------------------------------------------------


下面说说编程式加载Bean方式:

XmlBeanFactory提供两种编程方式加载Bean:
registerSingleton和registerBeanDefinition,前者不参与bean生命周期
后者参与bean的生命周期。

public static void main(String[] args)
{
Resource res = new ClassPathResource("bean.xml");

XmlBeanFactory factory = new XmlBeanFactory(res);
factory.registerSingleton("bb",new HelloBean());
HelloBean bean = (HelloBean)factory.getBean("bb");
System.out.println(bean.getMsg());

factory.destroySingletons();
}

如果使用BeanDefinition的话

public static void main(String[] args)
{
Resource res = new ClassPathResource("bean.xml");

XmlBeanFactory factory = new XmlBeanFactory(res);
RootBeanDefinition rbd = new RootBeanDefinition();
rbd.setBeanClass(HelloBean.class);
rbd.setInitMethodName("init");
//上面这句话告诉Spring自定义的方法名字叫做init,如果不写的话,自定义的
//初始化方法不会执行的。

/*
RootBeanDefinition rbd1 = new RootBeanDefinition(Integer.class);
ContructorArgumentValues cav = new ConstructorArgumentValues();
cav.addGenericArgumentValue("12");
rbd1.setConstructorArgumentValues(cav);

factory.registerBeanDefinition("aa",rbd1);
System.out.println(factory.getBean("aa"));
*/
factory.registerBeanDefinition("aa",rbd);


HelloBean bean = (HelloBean)factory.getBean("aa");
System.out.println(bean.getMsg());

factory.destroySingletons();
}

老师的关键代码如下:

XmlBeanFactory factory = new XmlBeanFactory(res);
RootBeanDefinition rbd = new RootBeanDefinition();
rbd.setBeanClass(HelloBean.class);
rbd.setInitMethodName("init");

RootBeanDefinition rbdi = new RootBeanDefinition(Integer.class);
ConstructorArgumentValues cav = new ConstructorArgumentValues();
cav.addGenericArgumentValue("12");
rbdi.setConstructorArgumentValues(cav);

=====================================================================

bean里面的属性是各式各样的,我们上面使用的实体类只是使用了String类型,根本没有考虑
其他的类型

bean装配方式:

通过Setter方法、通过构造函数、自动装配三种方法都可以达到装配Bean的目的。
其中使用setter方法装配Bean是最为常用的。

先说一下setter方法的装配:
setter方法可以装配基本类型、Bean类型、内部bean类型、集合类型、设置空值

所谓Bean类型属性是指这个属性类型是个javaBean,并且这个javaBean必须已经在Spring
中注册过了!

对于基本数据类型,
可以包括八种基本类型以及其包装类

<property name="" value="" />就可以了,不用在意具体类型,Spring会自动转换的。

装配基本类型:
包括八种基本类型及它们的包装类,还有String类型。
不必关心具体类型,spring可以通过反射机制了解到属性的类型信息
可以通过<property>的子元素<value>来设置基本类型的值,也可以通过其属性value来设置,
效果完全相同。

<bean id="first" class="mybeans.FirstBean" >
     <property name="message">
       <value>Hi, Rod Johnson</value>
     </property>
     <property name="age" value="1" />
//注意不能同时使用value子元素和value属性
</bean>

--------------------------------------------------------------------------

装配bean类型属性:
只有通过配置文件向容器注册的bean才能通过注入机制设置到其它bean的属性上。
使用<ref>子元素或ref属性设置
Spring即是通过这种方式建立起bean间的依赖关系,实现强大的bean管理功能。

举例说明:
BasicDataSource

引入包commons-dbcp、commons-pool以及commons-collections三个包引入
还有mysql的驱动程序
将BasicDataSource中的setter方法注入Spring中去。

在bean.xml中:
//将BasicDataSource中的setter方法中的对应值设置进去!
<beans>
<bean id="data" class="org.apache.commons.dbcp.BasicDataSource">
   <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
   <property name="url" value="jdbc:mysql:///j2ee"/>
   <property name="username" value="root" />
   <property name="password" value="root" />

</bean>

<bean id="course" class="bean.CourseBean">
   <property name="dataSource" ref="data"/>
   //由于是bean,所以使用ref!
</bean>
</beans>

建立一个Bean,对应数据库中的一个表
public class CourseBean
{
private int id ;
private String name ;
private DataSource dataSource ;
//加入getter和setter方法

public void save()
{

}
}

然后就可以进行一下数据库的操作了……

在main函数中执行下面的代码:
---------------------------------------------------------------
Resource res = new ClassPathResource("bean.xml");
XmlBeanFactory factory = new XmlBeanFactory(res);
CourseBean course = (CourseBean)factory.getBean("course");
//由于数据源和courseBean之间的依赖关系已经通过配置文件给配置好了,所以这里
//只需要得到courseBean,就自然有了数据源的bean了。
course.setName("adsf");
course.save();


-----------------------------------------------------------------


所谓DAO就是既有值,又可以将这个值存入数据库的对象,也就是数据库访问对象
Data Access Object

所谓VO就是仅仅有值,也就是value object,值对象。
上面的这个course就是DAO了。

上面的save方法可以简单的写成下面的样子:

public void save()
{
   try
   {
    Connection con = this.dataSource.getConnection();
    String sql = "insert into courses (coursename,period)"+
        "values(rtrim(?),rtrim(?))" ;
    PreparedStatement pstmt = con.prepareStatement(sql) ;
    pstmt.setString(1,this.coursename);
    pstmt.setInt(2,this.period.intValue());
  
    pstmt.executeUpdate();
   }
   catch (SQLException e)
   {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
}

======================================================================

如果一个bean在使用前,其某个属性的值必须已经通过注入机制注入,spring可以协助检查这个属性
是否被初始化。
bean的属性dependency-check即用来实现这样的功能,其可选值包括
none --不检查
objects --仅检查bean类型
simple --仅检查基本类型(8种)和String类型
all --全检查
default --默认,不检查


此外,因为可能会调用其它对象的方法,有时一个对象在使用前必须要求另外一个对象已经初始化完成
这种依赖关系可以通过depends-on属性来实现,spring会保证在初始化当前对象前将depends-on
指定的对象也初始化出来。

如果依赖多个对象,使用逗号将它们的名字分开。

内部Bean
<bean id="outer" class="...">
<property name="target">
   <bean class="com.mycompany.PersonImpl">
    <property name="name">
     <value>Tony</value>
    </property>
   </bean>
</property>
</bean>

----------------------------------------------------


Spring支持以下四种集合的装配:
<list>--java.util.List
<set>--java.util.Set
<map>--java.util.Map
<props>--java.util.Properties


list:
<property name="someList">
<list>
   <value>someValue</value>
   <ref bean="myDataSource"/>
   <list>
    <value>anyValue</value>
   </list>
</list>
</property>


set:
<property name="someSet">
<set>
   <value>just some string</value>
   <ref bean="myDataSource"/>
</set>
</property>

map:
<property name="someMap">
<map>
   <entry>
    <key><value>yup an entry</value></key>
    <value>just some string</value>
   </entry>
   <entry>
    <key><value>yup a ref</value></key>
    <ref bean="myDataSource"/>
   </entry>
</map>
</property>

props:
<property name="people">
<props>
   <prop key="HarryPotter">
    The magic property
   </prop>
   <prop key="JerrySeinfeld">
    The funny property
   </prop>
</props>
</property>
==========================================================
==========================================================

如果属性没有setter方法的话,需要考虑使用构造方法装配pbean的属性,这就是
构造装配
一般在以下情况使用:

属性没有setter方法,是只读属性
属性只需要设置一次,以后就不会再更改
一般使用构造装配只装配少量属性

注意在构造装配下,构造函数中应该包含有需要装配的属性

比如:
<bean id="i" class="java.lang.Integer">
<constructor-arg value="23" />
</bean>

这就是利用构造函数将Integer注入到容器中去。

Integer i = (Integer)factory.getBean("i");
System.out.println(i);

-----------------------------------------------------


<bean id="first" class="mybeans.FirstBean">
      <constructor-arg>
        <value>http://www.sohu.com</value>
      </constructor-arg>
      <constructor-arg>
        <value>http://localhost:8080</value>
      </constructor-arg>
      <property name="age" value="1" />
</bean>
多个参数时使用多个constructor-arg指定,出现次序决定了参数次序,或者使用index属性指定


======================================================

自动装配:

可以通过spring框架自动为bean装配属性。
自动装配只能装配bean类型,即取代ref元素。
使用自动装配只需在bean元素中加入属性autowire,自动装配可被手动装配覆盖。
也可以选择在beans中加入default-autowire属性,为所有bean设置默认自动装配。

“no“-不使用自动装配,spring推荐。
“byName”-依据名称或ID装配bean,如果没有找到,则不装配,可依赖dependency-check
属性检查是否装配。
“byType”-依据类型自动装配,如果存在两个以上同种类型,则抛出异常。
“constructor”-依据当前bean构造函数装配,查找与构造函数参数同类型bean
“autodetect”-自动检测,先通过constructor,再使用byType

Spring是不推荐使用自动装配的,首先是系统开销的问题,还有就是同名的设置可能会导致
意外的问题……

====================================================================

通过BeanFactory获取Bean与直接new一个Bean是完全不同的。
不相同的地方在于:从factory中得到的bean是被注入依赖关系的bean,而new出来的bean
则没有依赖关系,属性是空的。

通过BeanFactory获取的bean能将所有依赖注入到bean中,属性的值会依设置而定。
New出来的bean属性值必须主动设置。
在需要使用spring框架情况下,所有bean都应该由容器来管理。


===================================================================

单例和原型的问题:依赖于singleton参数,true为单例模式。
延迟加载:体现在整个容器初始化的时候立刻加载bean还是等到使用这个bean的时候才加载。
   factory.getBean的时候就已经是开始使用bean了,并不一定要访问其中的属性
   才算是使用。

   只有ApplicationContext才能做到容器初始化的时候立刻加载bean,BeanFactory
   是做不到的。

注册bean的时候,name属性是用的别名,id属性标明真名。name一般是在web开发里面去用,name
里面是可以包含一些特殊符号的,用于告诉开发者当前的属性代表什么具体的实际意思。

setter方法、构造函数和自动装配三种装配bean的方式

=====================================================================

ApplicationContext:

ApplicationContext与BeanFactory的作用相类似,都起到装配、管理Bean的作用。
不同的是,ApplicationContext在此基础上增强了BeanFactory的功能,这包括国际化、
加载资源、发布事件等等。

国际化的支持:

Spring提供了两个实现了MessageSource接口的类,它们都在
org.springframework.context.support包中:

ResourceBundleMessageSource使用JFC中标准的java.util.ResourceBundle来操作资源
ReloadableResourceBundleMessageSource 可以在不重启虚拟机的情况下重新加载资源。

ResourceBundleMessageSource是具体的类而且有setter方法,所以可以注入
根据setBasename,
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="bean.res" />
</bean>

千万注意一点,只要是资源包的话,id必须起名字为“messageSource”!!!!

这里还需要在bean包下面建立一个资源包res.properties,
在里面写上:
msg=Hello,{0}

public static void main(String[] args)
{
ClassPathXmlApplicationContext context =
   new ClassPathXmlApplicationContext("bean.xml");
String s = context.getMessage("msg",new Object[]{"Spring-Hibernate"},new Locale("zh"));
System.out.println(s);
}

这就打印出了“Hello,Spring-Hibernate”

--------------------------------------------------------


假如有多个资源包呢?
比如我又在bean包里面建了一个ress.properties
m=M

那么
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
   <value>bean.res</value>
   <value>bean.ress</value>
</list>
</property>
</bean>

--------------------------------------------------------

可以通过IOC机制加载资源,如
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
      <property name="basename">
         <value>springResource</value>
      </property>
</bean>
或者
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
    <list>
   <value>format</value>
   <value>exceptions</value>
   <value>windows</value>
       </list>
</property>
</bean>

千万注意一点,只要是资源包的话,id必须起名字为“messageSource”!!!!
分享到:
评论

相关推荐

    spring装配bean实例代码

    博客地址:https://blog.csdn.net/u010476739/article/details/76732201 spring装配bean的方式实例

    Spring Boot技术知识点:Bean装配1

    Spring Boot技术知识点:Bean装配1

    spring装配bean的3种方式总结

    主要给大家介绍了关于spring装配bean的3种方式,文中通过示例代码介绍的非常详细,对大家的学习或者使用Spring具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧

    基于框架的Web开发-装配Bean自动装配.doc

    1.4 装配Bean-自动装配(重要!) Spring从两个角度来实现自动化装配: 组件扫描(component scanning):Spring会自动发现应用上下文中所创建的bean。 自动装配(autowiring):Spring自动满足bean之间的依赖。 1 ...

    Spring装配bean方法实例总结

    主要介绍了spring装配bean方法实例总结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

    spring自动装配例子

    ean的自动装配,有4种 (1)no:不做任何操作 (2)byName:根据属性 名 自动装配,设值注入 &lt;bean id="xxx" class="xxx" &gt;&lt;/bean&gt; (3)byType:根据属性 类型 自动装配,相同类型多个会抛出异常,设值注入 &lt;bean...

    Spring装配Bean教程之XML安装配置bean详解

    大家都知道spring有多重配置方式,基于XML,基于注解,基于java类的配置,其中基于XML是最强大的一种,下面这篇文章主要给大家介绍了关于Spring装配Bean之XML安装配置bean的相关资料,需要的朋友可以参考借鉴,下面...

    Spring中的Bean的管理_Bean的装配方式_基于注解的装配_项目

    目的:Spring容器已经成功获取了UserController实例,并通过调用实例中的方法执行了各层中的输出语句。 运行结果为: User [id=1, name=张三, password=123] userDao say hello world! UserService say hello world ...

    day38 16-Spring的Bean的装配:注解的方式

    NULL 博文链接:https://364232252.iteye.com/blog/2369853

    浅谈Spring装配Bean之组件扫描和自动装配

    本篇文章主要介绍了浅谈Spring装配Bean之组件扫描和自动装配,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

    基于java的企业级应用开发:Bean的装配方式.ppt

    创建Spring配置文件,配置Bean; 创建测试类,测试程序。 @Repository("userDao") public class UserDaoImpl implements UserDao{ public void save(){ System.out.println("userdao...save..."); } } public class...

    Spring装配Bean之用Java代码安装配置bean详解

    主要给大家介绍了关于Spring装配Bean之用Java代码安装配置bean的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用spring具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧。

    Spring基于@Conditional条件化装配bean

    主要介绍了Spring @Conditional条件化装配bean,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

    spring入门教程之bean的继承与自动装配详解

    众所周知Spring里面的bean就类似是定义的一个组件,而这个组件的作用就是实现某个功能的,下面这篇文章主要给大家介绍了关于spring入门教程之bean继承与自动装配的相关资料,需要的朋友可以参考借鉴,下面随着小编来...

    spring在IoC容器中装配Bean详解

    主要介绍了spring在IoC容器中装配Bean详解,具有一定借鉴价值,需要的朋友可以参考下

    springIOC核心组件分析.vsdx

    spring-beans:Bean工厂与装配 spring-context:上下文,即IOC容器 spring-context-support:对IOC的扩展,以及IOC子容器 spring-context-indexer:类管理组件和Classpath扫描 spring-expression:表达式语句 切面编程: ...

    Spring自动装配Bean实现过程详解

    主要介绍了Spring自动装配Bean实现过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

    模拟实现Spring的IOC

    1、Spring主要两个作用:实例化Bean,动态装配Bean。并将所有的bean放到spring容器中,调用时从容器中取。Spring容器就是一个bean的Map:private Map, Object&gt; beans = new HashMap, Object&gt;(); 2、本工程,模拟...

    吴天雄--Spring笔记.doc

    第一天内容:Spring框架简介(EJB、JMX、Spring核心功能、Spring模块详解、Spring重要概念(容器)、Spring容器初始化的整个流程、Spring后处理器),IOC详解,Spring环境搭建,Spring创建Bean的三种方式,scope属性...

    java面试Spring.pdf

    1. Spring 介绍 1.1 Spring 的优点 1.2 Spring 的缺点 1.3 详细讲解一下核心容器(spring context应用上下文) 模块 ...Spring的自动装配 Spring框架中都用到了哪些设计模式? Spring框架中有哪些不同类型的事件?

Global site tag (gtag.js) - Google Analytics