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. C# List

    命名空间:using System.Collections; class Program {//做个比较 static void Main(string[] args) { //new对象 Cls a ...

  2. 基于ProGuard-Maven-Plugin的自定义代码混淆插件

    介绍 大家可能都会碰到一些代码比较敏感的项目场景,这个时候代码被反编译看到就不好了,这个时候就需要代码混淆插件来对代码进行混淆了. 基于Maven的项目一般会去考虑使用proguard-maven-p ...

  3. Linux抓包工具tcpdump详解

    tcpdump是一个用于截取网络分组,并输出分组内容的工具,简单说就是数据包抓包工具.tcpdump凭借强大的功能和灵活的截取策略,使其成为Linux系统下用于网络分析和问题排查的首选工具. tcpd ...

  4. POJ 2112.Optimal Milking (最大流)

    时间限制:2s 空间限制:30M 题意: 有K台挤奶机(编号1~K),C头奶牛(编号K+1~K+C),给出各点之间距离.现在要让C头奶牛到挤奶机去挤奶,每台挤奶机只能处理M头奶牛,求使所走路程最远的奶 ...

  5. yzoi1109&&viojs1042最小步数的一点看法——回文数

    Description - 问题描述 有一天,雄霸传授本人风神腿法第一式:捕风捉影..............的步法(弟子一:堂主,你大喘气呀.风:你给我闭嘴.)捕风捉影的关键是换气(换不好就会大喘气 ...

  6. underscorejs-countBy学习

    2.20 countBy 2.20.1 语法 _.countBy(list, iteratee, [context]) 2.20.2 说明 排序一个列表组成一个组,并且返回各组中的对象的数量的计数.类 ...

  7. dedecms自定义表单提交成功如何返回当前页面

    在plus/diy.php找到showmsg($bkmsg, $goto);改成showmsg($bkmsg, -1);

  8. sphinx 简介以及安装 以及php拓展开启

    一 sphinx 简介   在 使用mysql数据库过程中,如果想实现全文检索的优化,可以使用mysql自带全文索引,但是不支持中文..关于sphinx的安装网上很多教程写的都 不错比如:http:/ ...

  9. 那些年被我坑过的Python——山外有山(第四章)

    装饰器: 定义: 本质是函数,(装饰其他函数)就是为其他函数添加附加功能原则: 1.不能修改被装饰的函数的源代码 2.不能修改被装饰的函数的调用方式 优点: 装饰器带来的最直观的好处:减少对函数的细化 ...

  10. 黑马程序员—C语言的特点和关键字

    ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- C语言的简介 一. C语言具有下列特点: C语言既具有低级语言直接操纵硬件的特点,又具有高级语言 ...