Bean详解

Spring框架的本质其实是:通过XML配置来驱动Java代码,这样就可以把原本由java代码管理的耦合关系,提取到XML配置文件中管理。这样就实现了系统中各组件的解耦,有利于后期的升级和维护。
1.Bean的基本定义和Bean别名
<beans>元素是Spring配置文件的根元素,该元素可以指定如下属性:
default-lazy-init:指定<beans>元素下配置的所有bean默认的延迟初始化行为
default-merge:指定<beans>元素下配置的所有bean默认的merge行为
default-autowire:指定<beans>元素下配置的所有bean默认的自动装配行为
default-init-method:指定<beans>元素下配置的所有bean默认的初始化方法
default-destroy-method:指定<beans>元素下配置的所有bean默认的回收方法
default-autowire-candidates:指定<beans>元素下配置的所有bean默认是否作为自动装配的候选Bean
<beans>元素下所指定的属性都可以在每个<bean>子元素中指定,只要将属性名去掉default即可,这样就可以对特定bean起作用。
定义Bean时,通常要指定两个属性:
id:确定该Bean的唯一标识,Bean的id属性在Spring容器中应该是唯一的。
class:指定该Bean的具体实现类,这里不能是接口,因为在通常情况下,Spring会直接使用new关键字创建该bean的实例。
2.Bean的作用域
Spring支持5种作用域:
singleton:单例模式,在整个Spring IoC容器中,singleton作用域的Bean将只生成一个实例。
prototype:每次通过容器的getBean()方法获取prototype作用域的Bean时,都将产生一个新的Bean实例。
request、session:对于一次HTTP请求,request/session作用域的Bean将只产生一个实例,这意味着,在同一次HTTP请求内,程序每次请求该Bean,得到的总是同一个实例。只有在Web应用中使用Spring,该作用域才真正有效。
global session:每个全局的HTTP Session对应一个Bean实例,在典型的情况下,仅在使用portlet context的时候有效。只有在Web应用中使用Spring,该作用域才真正有效。
注意:如果一个Bean被设置成prototype作用域,程序每次请求该id的Bean,Spring都会新建一个Bean实例,然后返回程序。在这种情况下,Spring容器仅仅使用new关键字创建Bean实例,一旦创建成功,容器就不会再跟踪实例,也不会去维护bean实例的状态。
Java在创建Java实例时,需要进行内存申请,销毁实例时,要进行垃圾回收,这些工作会增加系统开销。因此,使用prototype作用域的Bean的创建、销毁代价比较大。而singleton作用域的Bean实例一旦创建成功,就可以重复使用。
例如:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
//创建一个singleton Bean实例
<bean id="p1" class="mySpring.Person" />
//创建一个prototype Bean实例
<bean id="p2" class="mySpring.Person" scope="prototype"/>
<bean id="date" class="java.util.Date" />
</beans>

测试:

public class myTest {
public static void main(String[] args) {
ApplicationContext ctx=new ClassPathXmlApplicationContext("a/ApplicationContext.xml");
System.out.println(ctx.getBean("p1")==ctx.getBean("p1"));
System.out.println(ctx.getBean("p2")==ctx.getBean("p2"));
System.out.println(ctx.getBean("date"));
Thread.sleep(1000);
System.out.println(ctx.getBean("date"));
}
}

结果是: true false Sun May 11 14:39:03 CST 2014 Sun May Sun May 11 14:39:03 CST 2014
request和session作用域只在Web应用中有效,并且要在Web应用中增加额外配置才会生效,因此必须要将HTTP请求对象绑定到为该请求提供服务的线程上,这样才能使得具有request和session作用域的Bean实例能够在后面的调用链中被访问到。对于支持Servlet2.4及更新规范的Web容器,可以在Web应用的web.xml文件中添加如下的Listener配置:
在WEB-INF\web.xml文件中:
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
JSP脚本:
<body>
<%
WebApplicationContext ctx=WebApplicationContextUtils.getWebApplicationContext(application);
Perosn p1=(Perosn)ctx.getBean("perosn");
Perosn p2=(Perosn)ctx.getBean("perosn");
out.println((p1==p2)+"<br />");
out.println(p1);
%>
</body>
结果:刷新页面依旧输出true,但是两次的Perosn Bean不一样。
3.配置依赖
不管是设值注入,还是构造注入,都视为Bean依赖,接受Spring容器管理,依赖关系的值要么是一个确定的值,要么是Spring容器中其他Bean的引用。通常不建议使用配置文件管理Bean的基本类型的属性值,通常只使用配置文件管理容器中Bean与Bean之间的依赖关系。
创建BeanFactory时不会立即创建Bean实例,所以有可能程序可以正确创建BeanFactory实例,但当请求Bean实例时依然抛出一个异常,创建Bean实例或注入它的依赖关系时出现错误。配置错误的延迟出现,也会给系统带来不安全因素。ApplicationContext实例化过程的时间和内存开销大,但可以在容器初始化阶段就检验出配置错误。
Java类的成员变量可以是各种可以是各种数据类型,除了基本类型值、字符串类型值等,还可以是其他Java实例,也可以是容器中的其他Bean实例,甚至是Java集合、数组等,所以Spring允许通过如下元素为setter方法、构造器参数指定参数值:value,ref,bean,list,set,map及props。
(1)设置普通属性值
<value/>元素用于指定基本类型及其包装、字符串类型的参数值,Spring使用XML解析器来解析出这些数据,然后利用java.beans.PropertyEditor完成类型转换:从java.lang.String类型转换为所需的参数值类型。如果目标类型是基本类型及其包装类,通常可以正确转换。
如:
<bean id="exampleBean" class="mySpring.ExampleBean">
//指定int型的参数值
<property name="field1" value="1" />
//指定double型的参数值
<property name="field2" value="2.3" />
</bean>
(2)配置合作者Bean
如果需要为Bean设置的属性值是容器中的另一个Bean实例,则要用<ref />元素。使用<ref/>元素时可指定一个bean属性,该属性用于引用容器中其他Bean实例的id属性值。
如:
Person.java

public class Person {
private String name;
private int age;
private Car car;
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", car=" + car + "]";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
public Person(String name, int age, Car car) {
super();
this.name = name;
this.age = age;
this.car = car;
}
public Person() {
super();
}
}

Car.java

public class Car {
private String brand;
private String corp;
private double price;
private int maxSpeed;
public Car(String brand, String corp, double price) {
super();
this.brand = brand;
this.corp = corp;
this.price = price;
}
@Override
public String toString() {
return "Car [brand=" + brand + ", corp=" + corp + ", price=" + price
+ ", maxSpeed=" + maxSpeed + "]";
}
}

ApplicationContext.xml

<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="car" class="a.Car">
<constructor-arg value="BaoMa" type="java.lang.String"></constructor-arg>
<constructor-arg value="ShangHai" type="java.lang.String"></constructor-arg>
<constructor-arg value="240" type="int"></constructor-arg>
</bean>
<bean id="person" class="a.Person">
<property name="name" value="Tom"></property>
<property name="age" value="20"></property>
<property name="car" ref="car"></property> //也可以写为<property name="car"><ref bean="car" /></property>
</bean>
</beans>

测试:

public class myTest {
public static void main(String[] args) {
ApplicationContext ctx=new ClassPathXmlApplicationContext("a/ApplicationContext.xml");
Person person=ctx.getBean(Person.class);
System.out.println(person);
}
}

结果:Person [name=Tom, age=20, car=Car [brand=BaoMa, corp=ShangHai, price=0.0, maxSpeed=240]]
(3)使用自动装配注入合作者Bean
Spring能自动装配Bean与Bean之间的依赖关系,即无须使用ref显式指定依赖Bean,而是由Spring容器检查XML配置文件内容,根据某种规则,为调用者Bean注入被依赖的Bean。
Spring的自动装配可通过<beans>元素的default-autowire属性指定,该属性对配置文件中所有的Bean起作用;也可以通过<bean>元素的autowire属性指定,该属性只对该Bean起作用。default-autowire、autowire属性可以接受如下值:
no:不使用自动装配,Bean依赖必须通过ref元素定义,在较大的部署环境下不鼓励这个配置,显示配置合作者能得到更清晰的依赖关系。
byName:根据setter方法名进行自动装配。Spring容器查找容器中的全部Bean,找出其id与setter方法名去掉set前缀,并小写首字母后同名的Bean来完成注入。如果没有找到匹配的Bean,则不注入。
byType:根据setter方法的形参类型来自动装配。Spring容器查找容器中的全部Bean,如果正好有一个Bean类型与setter方法的形参类型匹配,就自动注入这个Bean;如果找到多个,就抛出一个异常;如果没找到,就什么也不会发生。
具体使用:
byName规则
<bean id="chinese" class="mySpring.Chinese" autowire="byName" />
<bean id="gunDog" class="mySpring.GunDog">
<property name="name" value="wangwang" />
</bean>
在Chinese类中一定会有如下setter方法:
public void setGunDog(Dog dog){
this.dog=dog;
}
Spring容器会寻找id为gunDog的Bean,如果能找到,该Bean就会作为调用setGunDog()方法的参数。
byType规则
<bean id="chinese" class="mySpring.Chinese" autowire="byType" />
<bean id="gunDog" class="mySpring.GunDog">
<property name="name" value="wangwang" />
</bean>
在Chinese类中一定会有如下setter方法:
public void setGunDog(Dog dog){
this.dog=dog;
}
上面setter方法的形参类型是Dog,而mySpring.GunDog Bean类实现了Dog接口,但是如果还有一个类同时也实现了Dog接口的话,如下:
<bean id="gunDog" class="mySpring.PetDog">
<property name="name" value="ohoh" />
</bean>
由于容器中有两个类型为Dog的Bean,Spring无法确定应为chinese Bean注入哪个Bean,则程序会抛出异常。
当一个Bean既使用自动装配依赖,又使用ref显式指定依赖时,则显示指定的依赖会覆盖掉自动装配依赖。
(4)注入嵌套Bean
如果某个Bean所依赖的Bean不想被Spring容器直接访问,则可以使用嵌套Bean。这样的Bean称为内部Bean,不能被外部Bean引用,只能在内部使用,这里的bean不用id。
<bean id="person" class="a.Person">
<property name="name" value="Tom"></property>
<property name="age" value="20"></property>
<property name="car">
<bean class="a.Car">
<constructor-arg value="Ford"></constructor-arg>
<constructor-arg value="Changan"></constructor-arg>
<constructor-arg value="200000"></constructor-arg>
</bean>
</property>
</bean>
当形参类型是基本类型、String、日期等,直接使用value指定字面值即可;但形参类型是复合类(如Person、DataSource等),那就需要传入一个Java对象作为实参,主要有两种方法:使用ref引用一个容器中已经配置的Bean,或者使用<bean>元素配置一个嵌套Bean;形参类型是Set、List、Map等集合或者是数组类型时,要进行如下配置。
(5)注入集合值
集合元素<list>,<set>,<map>,<props>的具体设置
Address.java

public class Address{
private String city;
private String street;
...//此处省略getter/setter方法及其他方法
}

Car.java

public class Car {
private String brand;
private String corp;
private double price;
...//此处省略getter/setter方法及其他方法
}

Person.java

public class Person {
private List<Car> cars;
private List<String> schools;
private Map scores;
private Map<String,Car> cars1;
private Properties health;
private String[] books;
...//此处省略getter/setter方法及其他方法
}

ApplicationContext.xml

<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="car1" class="SpringTest.Car">
<property name="brand" value="Ford"></property>
<property name="corp" value="Changan"></property>
<property name="price" value="200000"></property>
</bean> <bean id="car2" class="SpringTest.Car">
<property name="brand" value="BaoMa"></property>
<property name="corp" value="ShangHai"></property>
<property name="price" value="240000"></property>
</bean> <bean id="person" class="SpringTest.Person">
<property name="cars">
<list>
<ref bean="car1"></ref>
<ref bean="car2"></ref>
</list>
</property> <property name="schools">
<list>
<value>小学</value>
<value>中学</value>
<value>大学</value>
</list>
</property> <property name="scores">
<map>
<entry key="数学" value="90" />
<entry key="语文" value="90" />
<entry key="英语" value="90" />
</map>
</property> <property name="cars1">
<map>
<entry key="AA" value-ref="car1"></entry>
<entry key="BB" value-ref="car2"></entry>
</map>
</property> <property name="health">
<props>
<prop key="血压">正常</prop>
<prop key="身高">175</prop>
</props>
</property> <property name="books">
<list>
<value>java学习</value>
<value>javascript学习</value>
<value>javaEE学习</value>
</list>
</property>
</bean>
</beans>

测试:

public class MainTest {
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx=new ClassPathXmlApplicationContext("SpringTest/ApplicationContext.xml");
Person p=(Person)ctx.getBean("person");
System.out.println(p);
ctx.close();
}
}

结果:
Person [cars=[Car [brand=Ford, corp=Changan, price=200000.0], Car [brand=BaoMa, corp=ShangHai, price=240000.0]], schools=[小学, 中学, 大学], scores={数学=90, 语文=90, 英语=90}, cars1={AA=Car [brand=Ford, corp=Changan, price=200000.0], BB=Car [brand=BaoMa, corp=ShangHai, price=240000.0]}, health={血压=正常, 身高=175}, books=[java学习, javascript学习, javaEE学习]]

Spring二 Bean详解的更多相关文章

  1. (转)java之Spring(IOC)注解装配Bean详解

    java之Spring(IOC)注解装配Bean详解   在这里我们要详细说明一下利用Annotation-注解来装配Bean. 因为如果你学会了注解,你就再也不愿意去手动配置xml文件了,下面就看看 ...

  2. spring在IoC容器中装配Bean详解

    1.Spring配置概述 1.1.概述 Spring容器从xml配置.java注解.spring注解中读取bean配置信息,形成bean定义注册表: 根据bean定义注册表实例化bean: 将bean ...

  3. Spring Bean 详解

    Spring Bean 详解 Ioc实例化Bean的三种方式 1 创建Bean 1 使用无参构造函数 这也是我们常用的一种.在默认情况下,它会通过反射调⽤⽆参构造函数来创建对象.如果类中没有⽆参构造函 ...

  4. spring事务配置详解

    一.前言 好几天没有在对spring进行学习了,由于这几天在赶项目,没有什么时间闲下来继续学习,导致spring核心架构详解没有继续下去,在接下来的时间里面,会继续对spring的核心架构在继续进行学 ...

  5. Springboot@Configuration和@Bean详解

    Springboot@Configuration和@Bean详解 一.@Configuration @Target({ElementType.TYPE}) @Retention(RetentionPo ...

  6. Spring MVC配置详解(3)

    一.Spring MVC环境搭建:(Spring 2.5.6 + Hibernate 3.2.0) 1. jar包引入 Spring 2.5.6:spring.jar.spring-webmvc.ja ...

  7. 最漂亮的Spring事务管理详解

    SnailClimb 2018年05月21日阅读 7245 可能是最漂亮的Spring事务管理详解 Java面试通关手册(Java学习指南):github.com/Snailclimb/- 微信阅读地 ...

  8. Spring DI使用详解

    Spring DI使用详解 一.介绍 DI的定义:依赖注入,为类里面的属性设值.例如,我们之前的setName方法就是在为name属性设值. IOC与DI的关系:IOC进行对象的创建,DI进行值的注入 ...

  9. Spring jar包详解

    Spring jar包详解 org.springframework.aop ——Spring的面向切面编程,提供AOP(面向切面编程)的实现 org.springframework.asm——spri ...

随机推荐

  1. 如何制作css3的3d动画——以骰子旋转为例,详解css3动画属性

    首先先来看两个用css3实现的炫酷的3d动画效果 1 2 3 4 5   6 你没看错,这个炫酷的效果都是用css3实现的. 下面是动画实现所需要用到的几个css3属性. 1.perspective: ...

  2. java项目测试log4j

    .literal { background-color: #f2f2f2; border: 1px solid #cccccc; padding: 1px 3px 0; white-space: no ...

  3. skip-grant-tables的作用

    skip-grant-tables:非常有用的mysql启动参数(不启动grant-tables授权表) skip-grant-tables:非常有用的mysql启动参数   介绍一个非常有用的mys ...

  4. js对象的复制,传递,新增,删除和比较

    当我们把一个某个对象拷贝或者传递给某个函数时,往往传递的是该对象的引用. 因此我们在引用上做的任何改动,都将会影响到它所引用的原对象.  复制,拷贝  var o = { add: 'Changdao ...

  5. web版扫雷小游戏(一)

    作为一名程序猿,平时的爱好也不多,说起游戏,我不太喜欢大型的网游,因为太耗时间,偶尔玩玩经典的单机小游戏,比如windows下自带的游戏扫雷(秀一下,高级下最高纪录110s). 现阶段正在致力于web ...

  6. spring 构造注入 异常 Ambiguous constructor argument types - did you specify the correct bean references as constructor arguments

    你可能在做项目的时候,需要在项目启动时初始化一个自定义的类,这个类中包含着一个有参的构造方法,这个构造方法中需要传入一些参数. spring提供的这个功能叫“构造注入”, applicationCon ...

  7. 浏览器中的WebSocket("ws://127.0.0.1:9988");

    <script type="text/javascript"> function WebSocketTest() { if ("WebSocket" ...

  8. 操作Json

    C#可以像Javascript一样操作Json 阅读目录 Json的简介 Json的优点 传统操作Json 简易操作Json Json的简介 JSON(JavaScript Object Notati ...

  9. Unity各平台路径总结

    路径是Unity开发中令人头疼的一个问题,根据我的开发经验,现将开发中遇到的路径问题总结如下: 1. 如何读取Application.streamingAssetsPath下的文件? Edit.iOS ...

  10. Node.js npm

    Node程序包管理器(NPM)提供了以下两个主要功能: 在线存储库的Node.js包/模块,可搜索 search.nodejs.org 命令行实用程序来安装Node.js的包,做版本管理和Node.j ...