7.8 深入理解容器中的Bean

      7.8.1 抽象Bean与子Bean

        把多个<bean.../>配置中相同的信息提取出来,集中成配置模版------这个配置模版并不是真正的Bean,因此Spring不应该创建该配置模版,于是需要为该<bean.../>配置增加abstract=“true” ------这就是抽象Bean。

        抽象Bean不能被实例化,Spring容器不会创建抽象Bean实例。抽象Bean的价值在于被继承,抽象Bean通常作为父Bean被继承。

        抽象Bean只是配置信息的模版,指定abstract=“true”即可阻止Spring实例化该Bean,因此抽象Bean可以不指定class属性。

        将大部分相同信息配置成抽象Bean之后,就实际Bean实例配置成该抽象Bean的子Bean即可。子Bean定义可以从父Bean继承实现类、构造器参数、属性值等配置信息,除此之外,子Bean配置可以增加新的配置信息,并可指定新的配置信息覆盖父Bean的定义。

        通过为一个<bean.../>元素指定parent属性即可指定该Bean是一个子Bean,parent属性指定该Bean所继承的父Bean的id。

        子Bean无法从父Bean继承如下属性:depends-on、autowire、singleton、scope、lazy-init,这些属性将总是从子Bean定义中获得,或采用默认值。

        Interface : Axe

package edu.pri.lime._7_8_1.bean;

public interface Axe {
public String chop();
}

        Class : SteelAxe

package edu.pri.lime._7_8_1.bean.impl;

import edu.pri.lime._7_8_1.bean.Axe;

public class SteelAxe implements Axe{

    public String chop() {
return "用钢斧砍柴真快";
} }

        Interface : Person

package edu.pri.lime._7_8_1.bean;

public interface Person {
public void useAxe();
}

        Class : Chinese

package edu.pri.lime._7_8_1.bean.impl;

import edu.pri.lime._7_8_1.bean.Axe;
import edu.pri.lime._7_8_1.bean.Person; public class Chinese implements Person{ private String name;
private Axe axe;
public void useAxe() {
System.out.println(name + " 说:" + axe.chop());
}
public Axe getAxe() {
return axe;
}
public void setAxe(Axe axe) {
this.axe = axe;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
} }

        Class : American

package edu.pri.lime._7_8_1.bean.impl;

import edu.pri.lime._7_8_1.bean.Axe;
import edu.pri.lime._7_8_1.bean.Person; public class American implements Person{ private String name;
private Axe axe;
public void useAxe() {
System.out.println(name + " say: " + axe.chop());
}
public Axe getAxe() {
return axe;
}
public void setAxe(Axe axe) {
this.axe = axe;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
} }

        XML :

<?xml version="1.0" encoding="UTF-8"?>
<!-- Spring 配置文件的根元素,使用Spring-beans-4.0.xsd语义约束 -->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
<!-- 定义Axe实例 -->
<bean id="steelAxe" class="edu.pri.lime._7_8_1.bean.impl.SteelAxe" />
<!-- 指定abstract=“true”定义抽象Bean -->
<!-- 如果父Bean指定了class 属性,那么子Bean连class属性都可以省略,子Bean将采用与父Bean相同的实现类 -->
<bean id="personTemplate" abstract="true">
<property name="name" value="lime" />
<property name="axe" ref="steelAxe" />
</bean>
<!-- 通过指定parent属性指定Bean配置可从父Bean继承得到配置信息 -->
<bean id="chinese" class="edu.pri.lime._7_8_1.bean.impl.Chinese"
parent="personTemplate" />
<bean id="american" class="edu.pri.lime._7_8_1.bean.impl.American"
parent="personTemplate">
<property name="name" value="oracle" />
</bean>
</beans>

        Class : SpringTest

package edu.pri.lime._7_8_1.main;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; import edu.pri.lime._7_8_1.bean.Person;
import edu.pri.lime._7_8_1.bean.impl.American;
import edu.pri.lime._7_8_1.bean.impl.Chinese; public class SpringTest { public static void main(String[] args){
ApplicationContext ctx = new ClassPathXmlApplicationContext("app_7_8_1.xml");
Person chinese = (Person) ctx.getBean("chinese",Chinese.class);
Person american = (Person) ctx.getBean("american",American.class);
chinese.useAxe();
american.useAxe();
}
}

        Console :

lime 说:用钢斧砍柴真快
oracle say: 用钢斧砍柴真快

      7.8.2 Bean继承与Java继承的区别

        Spring中的Bean继承与Java中的继承中,Spring中的Bean继承是实例与实例之间参数值的延续,Java中的继承是一般到特殊的细化;Spring中的Bean继承是对象与对象之间的关系,Java中的继承是类与类之间的关系。

        区别:

          ⊙ Spring中的子Bean和父Bean可以是不同类型,但Java中的继承则可保证子类是一种特殊的父类。

          ⊙ Spring中Bean的继承是实例之间的关系,因此主要表现为参数值的延续;而Java中的继承是类之间的关系,主要表现为方法、属性的延续。

          ⊙ Spring中的子Bean不可作为父Bean使用,不具备多态性;java中的子类实例完全可当成父类实例使用。

        说到底,Spring中的Bean继承与Java中的继承其实就是两码事。表混淆就行了。

      7.8.3 容器中的工厂Bean

        Spring容器中的工厂Bean是一种特殊的Bean,必须实现FactoryBean接口。

        FactoryBean接口是工厂Bean的标准接口,把工厂Bean(实现FactoryBean接口的Bean)部署在容器中之后,如果程序通过getBean()方法来获取它时,容器返回的不是FactoryBean实现类的实例,而是返回FactoryBean的产品(即该工厂Bean的getObject()方法的返回值).

        FactoryBean接口中的方法:

          ⊙ T getObject() : 实现该方法负责返回该工厂Bean生成的Java实例。

          ⊙ Class<?> getObjectType() : 实现该方法返回该工厂Bean生成的Java实例的实现类。

          ⊙ boolean isSingleton() : 实现该方法表示该工厂Bean生成的Java实例是否为单例模式。

        程序把获取指定类的、指定类变量的实现逻辑放在getObject()方法中即可。

        Class : GetFieldFactoryBean

package edu.pri.lime._7_8_3.bean.impl;

import java.lang.reflect.Field;

import org.springframework.beans.factory.FactoryBean;

public class GetFieldFactoryBean implements FactoryBean<Object>{

    private String targetClass;
private String targetField; // 负责返回工厂Bean生成的Java实例
public Object getObject() throws Exception {
// froName(String) : 返回与带有给定字符串名的类或接口相关联的 Class 对象。
Class<?> clazz = Class.forName(targetClass);
// getField(String) : 返回一个指定名称的公共属性
Field field = clazz.getField(targetField);
// get(Object) : 返回指定对象上此Field表示的字段的值
// 为什么get(null):静态属性直接通过.get(null)获取
Object obj = field.get(null);
return obj;
}
public Class<? extends Object> getObjectType() {
// 哪里来的Object?
return Object.class;
}
// 返回该工厂Bean所生产的产品是否为单例
public boolean isSingleton() {
// 非单例Bean
return false;
}
public String getTargetClass() {
return targetClass;
}
public void setTargetClass(String targetClass) {
this.targetClass = targetClass;
}
public String getTargetField() {
return targetField;
}
public void setTargetField(String targetField) {
this.targetField = targetField;
}
}

        XML :

<?xml version="1.0" encoding="UTF-8"?>
<!-- Spring 配置文件的根元素,使用Spring-beans-4.0.xsd语义约束 -->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
<!--
下面配置相当于如下代码:
FactoryBean factory = new edu.pri.lime._7_8_3.bean.impl.GetFieldFactoryBean();
factory.setTargetClass("java.awt.borderLayout"); facotry.setTargetField("NORTH");
north = factory.getObject();
-->
<bean id="north" class="edu.pri.lime._7_8_3.bean.impl.GetFieldFactoryBean">
<property name="targetClass" value="java.awt.BorderLayout"/>
<property name="targetField" value="NORTH"/>
</bean>
<bean id="theValue" class="edu.pri.lime._7_8_3.bean.impl.GetFieldFactoryBean">
<property name="targetClass" value="java.sql.ResultSet"/>
<property name="targetField" value="TYPE_SCROLL_SENSITIVE"/>
</bean>
</beans>

        Class : SpringTest

package edu.pri.lime._7_8_3.main;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringTest { public static void main(String[] args){
ApplicationContext ctx = new ClassPathXmlApplicationContext("app_7_8_3.xml");
// 获取FactoryBean的产品
System.out.println(ctx.getBean("north"));
System.out.println(ctx.getBean("theValue"));
// 获取FactoryBean本身
// 在Bean id前增加&符号,会让Spring返回FactoryBean本身
System.out.println(ctx.getBean("&theValue"));
}
}

        Spring容器会自动检测容器中的所有Bean,如果发现某个Bean实现类实现了FactroyBean接口,Spring容器就会在实例化该Bean、根据<property.../>执行setter方法之后,额外调用该Bean的getObject()方法,并将该方法的返回值作为容器中的Bean。

        Spring框架提供的FieldRetrievingFactoryBean,实现原理与GetFieldFactoryBean的原理基本相同。

      7.8.4 获得Bean本身的id

        对于实际的Java应用而言,Bean与Bean之间的关系是通过依赖注入管理的,通常不会通过调用容器的getBean()方法来获取Bean实例。可能的情况是,应用中已经获得了Bean实例的引用,但程序无法知道配置该Bean时指定的id,可是程序又确实需要获取配置该Bean时指定的id属性。

        除此之外,当程序员在开发一个Bean类时,该Bean何时被部署到Spring容器中,部署到Spring容器时所指定的id是什么,开发该Bean类的程序员无法提前预知。

        在某些极端情况下,业务要求程序员在开发Bean类时能预先知道该Bean的配置id,此时可借助Spring提供的BeanNameAware接口,通过该接口即可提前预知该Bean的配置id。

        BeanNameAware接口提供了一个方法:setBeanName(String name),该方法的name参数就是Bean的id,实现该方法的Bean类就可以通过该方法来获取部署该Bean的id了。

        Class : Chinese

package edu.pri.lime._7_8_4.bean;

import org.springframework.beans.factory.BeanNameAware;

//Spring容器会检测容器中的所有Bean,如果发现某个Bean实现了BeanNameAware接口,
//Spring容器就会在创建该Bean之后,自动调用该Bean的setBeanName()方法,
//调用该方法时,会将该Bean的配置id作为参数传给该方法------
//该方法的实现部分将SPring容器的参数(Bean的配置id)赋给该Chinese对象的name实例变量,
//之后可通过该name实例变量来访问容器本身
public class Chinese implements BeanNameAware { private String name; public void setBeanName(String name) {
this.name = name;
} public void info() {
System.out.println("Chinese实现类" + ",部署该Ben时指定的id为:" + name);
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
}
}

        XML :

<?xml version="1.0" encoding="UTF-8"?>
<!-- Spring 配置文件的根元素,使用Spring-beans-4.0.xsd语义约束 -->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <bean id="chinese" class="edu.pri.lime._7_8_4.bean.Chinese" /> </beans>

        Class : SpringTest

package edu.pri.lime._7_8_4.main;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; import edu.pri.lime._7_8_4.bean.Chinese; //Spring容器初始化Chinese Bean时回调setBeanName()方法,回调该方法时,
//该Bean的配置id将会作为参数传给beanName实例变量。
public class SpringTest {
public static void main(String[] args){
ApplicationContext ctx = new ClassPathXmlApplicationContext("app_7_8_4.xml");
Chinese chinese = ctx.getBean("chinese",Chinese.class);
chinese.info();
} }

      7.8.5 强制初始化Bean

        在大多数情况下,Bean之间的依赖非常直接,Spring容器在放回Bean实例之前,先要完成Bean依赖关系的注入。

        在极端情况下,Bean之间的依赖不够直接。比如:某个类的初始化块中使用其他Bean,当初始化块时,被依赖Bean可能还没有被实例化,此时将会引发异常。

        为了显示指定被依赖Bean在目标Bean之前初始化,可以使用depends-on属性,该属性可以在初始化主调Bean之前,强制初始化一个或多个Bean。

    <bean id="chinese" class="edu.pri.lime._7_8_4.bean.Chinese" depends-on="steelAxe"/>
<bean id="steelAxe" class="edu.pri.lime._7_8_5.bean.SteelAxe"/>

啦啦啦

7 -- Spring的基本用法 -- 8... 抽象Bean与子Bean;Bean继承与Java继承的区别;容器中的工厂Bean;获得Bean本身的id;强制初始化Bean的更多相关文章

  1. 7 -- Spring的基本用法 -- 5... Spring容器中的Bean;容器中Bean的作用域;配置依赖;

    7.5 Spring容器中的Bean 7.5.1 Bean的基本定义和Bean别名 <beans.../>元素是Spring配置文件的根元素,该元素可以指定如下属性: default-la ...

  2. 7 -- Spring的基本用法 -- 5...

    7.5 Spring容器中的Bean 7.5.1 Bean的基本定义和Bean别名 <beans.../>元素是Spring配置文件的根元素,该元素可以指定如下属性: default-la ...

  3. 7 -- Spring的基本用法 -- 8...

    7.8 深入理解容器中的Bean 7.8.1 抽象Bean与子Bean 把多个<bean.../>配置中相同的信息提取出来,集中成配置模版------这个配置模版并不是真正的Bean,因此 ...

  4. spring的基本用法

    1,关于spring容器: spring容器是Spring的核心,该 容器负责管理spring中的java组件, ApplicationContext ctx = new ClassPathXmlAp ...

  5. 7 -- Spring的基本用法 -- 3...

    7.3 Spring 的核心机制 : 依赖注入 Spring 框架的核心功能有两个. Spring容器作为超级大工厂,负责创建.管理所有的Java对象,这些Java对象被称为Bean. Spring容 ...

  6. (spring-第1回【IoC基础篇】)Spring容器中Bean的生命周期

    日出日落,春去秋来,花随流水,北雁南飞,世间万物皆有生死轮回.从调用XML中的Bean配置信息,到应用到具体实例中,再到销毁,Bean也有属于它的生命周期. 人类大脑对图像的认知能力永远高于文字,因此 ...

  7. Spring中Bean的命名问题及ref和idref之间的区别

    一直在用Spring,其实对其了解甚少,刚去了解了一下Spring中Bean的命名问题以及ref和idref之间的区别,略作记录,以备后查. Spring中Bean的命名 1.每个Bean可以有一个i ...

  8. 7 -- Spring的基本用法 -- 3... Spring 的核心机制 : 依赖注入

    7.3 Spring 的核心机制 : 依赖注入 Spring 框架的核心功能有两个. Spring容器作为超级大工厂,负责创建.管理所有的Java对象,这些Java对象被称为Bean. Spring容 ...

  9. 可以随时拿取spring容器中Bean的工具类

    前言 在Spring帮我们管理bean后,编写一些工具类的时候需要从容器中拿到一些对象来做一些操作,比如字典缓存工具类,在没有找到字典缓存时,需要dao对象从数据库load一次,再次存入缓存中.此时需 ...

随机推荐

  1. JVM调优总结(一):基本概念

    一.数据类型 Java虚拟机中,数据类型可以分为两类:基本类型和引用类型. 基本类型的变量保存原始值,即:他代表的值就是数值本身: 而引用类型的变量保存引用值.“引用值”代表了某个对象的引用,而不是对 ...

  2. javascript显示年月日时间代码

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  3. R语言使用tryCatch进行简单的错误处理

    最近在看<机器学习:实用案例解析>,做邮件过滤器的时候,参考书中的代码读取邮件文件进行分类器训练,在读取过程中会出现下面的错误:   seq.default(which(text == & ...

  4. 自然语言交流系统 phxnet团队 创新实训 项目博客 (四)

    刚开始做时,一点头绪都没有,整天的上网找资料,各种谷歌百度,各种博客论坛,搜索的关键词也无非是智能自然语言交流.智能机器人.中文问答系统等等等等.而我们的思路也是些零散的,例如我们知道会用到分词,会用 ...

  5. Resnet小记

    ResNet之Deeper Bottleneck Architectures 2016年12月28日 22:17:48 阅读数:2350 去年的时候,微软一帮子人搞了个152层的神经网络!WTF!详情 ...

  6. Opengl绘制我们的小屋(三)纹理绘制

    本准备先说光照相关实现,但是发现对那个模型实在看不下去了,于是先绘制纹理. 先看下基本纹理贴上去的显示效果.具体模型图请看上篇文章的实现,这篇只讲纹理实现. 我们常见的纹理绘制差不多如下,先写一个纹理 ...

  7. python3 异步模块asyncio

    yield方法引入, 这里存在的问题是,如果你想创建从0到1,000,000这样一个很大的序列,你不得不创建能容纳1,000,000个整数的列表. 但是当加入了生成器之后,你可以不用创建完整的序列,你 ...

  8. IT 运营架构杂谈【前言】

    [ 什么是IT 服务 ?]   OGC官方的ITIL 服务定义: 中文定义:实施和管理 IT 服务,满足业务的需要.IT 服务管理由IT 服务提供方通过人员.流程和信息技术的适当组合而进行.   [ ...

  9. tpshop防止sql注入补丁

    本补丁 由 QQ 木偶人  提供 首先在  www\Application\Common\Common\function.php 文件添加一个方法 /** * 转换SQL关键字 * * @param ...

  10. EF5+MVC4系列(8) ActionResult的返回值

    我们在MVC的代码中,经常会看到这样的一个 代码 可能有人会有疑问,既然我定义的是ActionResult,为什么返回值会是View方法呢? 其实这个View方法的返回值的类型是ActionResul ...