spring XML文件使用详解

本文详细介绍了Spring框架中XML配置文件的使用,包括<beans>、<description>、<import>、<alias>、<bean>等核心标签。重点讲解了<bean>的属性如id、class、constructor-arg、property,以及依赖注入的多种方式,如setter注入、构造器注入、自动绑定等。此外,还讨论了bean的作用域、继承、工厂方法以及方法替换等高级特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

spring提供了强大的xml文件支持。在此对其标签进行详细的介绍:

1. < beans >

特点:最顶级元素,包含多个。
结构图:

在这里插入图片描述
拥有的属性:
default-lazy-init: 值指定为true/false 默认是false,用于设置< bean >延迟初始化
default-autowire: 取值为no/byName/byType/constructor/。默认为no。控制全体bean采用哪种默认绑定方法
default-destroy-method: 指定管理的bean的销毁方法
default-init-method: 指定管理的bean的初始化方法

统一管理bean,避免重复指定bean的创建规则。

例子:
头文件样式:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd" >

2. < description >
一般是省略的。可以为配置文件添加描述性话语

3.< import >
导入其它配置文件:

例子:

    <import resource="simple2.xml"/>

4.< alias >
设置别名。

 <alias name="ab" alias="x"/>
	      <bean id="ab" class=""></bean>

给名为ab的bean设置别名为x,此后可以使用x或者ab访问该bean

5.< bean>

例子:

<bean id="a" class="com.example.demo.xmlparse.Aclass"></bean> 

属性:

id :区分beans管理下 的bean的唯一标识。这个是一个非必须的属性,特定的情况下可以省略;
name:指定bean的别名(同alias )。与id相比,name的属性更加灵活可以使用特殊的字符如 ‘ / ’ 还可以通过逗号,空格,冒号分割name
class: 大部分情况下是必须的,指定bean的数据类型,在抽象模板中可以不需要指定class

6. < constructor -arg >

配合bean使用,用于使用构造方式处理对象之间依赖关系。当对象中存在多个构造方法的时候,而且请求参数列表数目,类型不同时候,需要使用内部的属性协助。

type:
用于指定构造对象参数的注入类型,由于在xml配置时候,会将普通的入参默认当做字符串处理,因而在这种情况下也可以使用type指定其类型。避免出错。

      <bean id="a" class="com.example.demo.xmlparse.Aclass">
	      	<constructor-arg type="int">
	      		<value>1</value>
	      	</constructor-arg>
	      	<constructor-arg>
	      		<value>2</value>
	      	</constructor-arg>
	      </bean>

如此处理入参,则获取到的bean结果为:

this bean :2 b:1

如果是不使用type的情况下:

     <bean id="a" class="com.example.demo.xmlparse.Aclass">
	      	<constructor-arg >
	      		<value>1</value>
	      	</constructor-arg>
	      	<constructor-arg>
	      		<value>2</value>
	      	</constructor-arg>
	      </bean>

结构为:

this bean :1 b:2

index:
当类型也一致时候可以使用index指定入参的顺序,控制bean的依赖注入关系。此处不给出具体例子了。需要注意的是使用index的时候起始下标是从0开始的

value
可以作为一个属性写入也可以作为子标签在< constructor-arg >中使用:

	<constructor-arg >
	      		<value>1</value>
   </constructor-arg>

	<constructor-arg  value="1" >	</constructor-arg> 

效果是一致的

7.、< property >

此标签用于处理setter依赖关系的关系注入。

<bean id="property" class="com.example.demo.xmlparse.Aclass">
	      	<property name="a" value="2"></property>
	      	<property name="b" value="1"></property>
	      </bean>

属性:
name : 属性名对应
value:
ref: 引用哪个bean

8. < property>与< constructor-arg>中的可配置项

< value> : 可以通过value为主体注入简单数据类型。可以指定String与基本类型+基本类型的包装类型。容器在注入的时候会做适当的转换工作,这个是最底层元素,无法再嵌套别的元素了

< ref> :
使用ref引用容器中的其它对象实例。有三种引用范围可以选择:local,parent,bean;
local只能指定与当前配置对象在同一配置文件下的bean对象
parent只能指定当前容器父容器定义的对象引用
bean均可以指定到。同< value>标签一致,它也是一个底层标签不能内嵌标签

9. < idref >
为当前对象注入所依赖对象的名称,而不是引用,最适合的方式是使用idref,这个标签可以在容器解析配置时候,帮助检查beanName是否存在。
使用范例:

 <bean id="idreftry" class="com.example.demo.xmlparse.ABclass">
	      	<property name="a">
	      		<idref bean="x"></idref>
	      	</property>
	      </bean>

注意:是名称不是引用,此方法注入的值一定是String,而且是已经在容器中托管的bean中的一个beanName

10. 内部bean。
定义的bean是私有的时候使用。
使用示例:

   <bean id="innerBeanTry" class="com.example.demo.xmlparse.ABclass">
	      	<constructor-arg>
	      		<bean class="com.example.demo.xmlparse.Aclass">
	      		</bean>
	      	</constructor-arg>
	      </bean>

因为只供内部使用,所以可以不设置id的值。

11. < list>

对应注入对象类型为list类型及其子类或者数组类型的依赖对象。

     <bean id="listTry" class="com.example.demo.xmlparse.ABclass">
	      	<property name="b">
	      		<list>
	      			<value>1</value>
	      			<ref bean="property"/>
	      			<bean class="com.example.demo.xmlparse.Aclass">
	      				<property name="a" value="12"></property>
	      				<property name="b" value="11"></property>
	      			</bean>
	      		</list>
	      	</property>
	      </bean>

12. < set>

注入一组无序的依赖。对set而言,元素顺序无关紧要。对应注入的依赖是set及其子类的依赖对象。

例子:

      <bean id="setTry" class="com.example.demo.xmlparse.ABclass">
	      	<property name="c">
	      		<set>
	      			<value>1</value>
	      			<ref bean="property"/>
	      			<bean class="com.example.demo.xmlparse.Aclass">
	      				<property name="a" value="12"></property>
	      				<property name="b" value="11"></property>
	      			</bean>
	      		</set>
	      	</property>
	      </bean>

13. < map>

注入map及其子类类型依赖对象,使用该标签。该标签下有子标签< entry>.具体使用例子如下:

   <bean id="mapTry" class="com.example.demo.xmlparse.ABclass">
	      	<property name="d">
	      		<map>
	      			<entry key="first key">
	      				<value>first value</value>
	      			</entry>
	      			<entry key="second key">
	      				<ref bean="property"/>
	      			</entry>
	      			<entry key-ref="property" value="property bean"></entry>
	      			<entry key-ref="a" value-ref="property"></entry>
	      		</map>
	      	</property>
	      </bean>

14.< props>
< props>是简化的< map>,但是不同于< map>,只能注入String类型的数据< prop >中有且仅有key属性,不能内嵌别的标签

例子:

<bean id="propertiesTry" class="com.example.demo.xmlparse.ABclass">
	      	<property name="e">
	      		<props>
	      			<prop key="author1">作者1</prop>
	      			<prop key="author2">作者2</prop>
	      			<prop key="author3">作者3</prop>
	      		</props>
	      	</property>
	      </bean>

15. < null/>

注入null值时候使用,需要注意的是< value></ value >注入的值是空字符串,不是null值。

16.bean的 depends-on 属性

此标签用于隐式指定bean之间的依赖关系。场景如:在静态代码块中初始化代码,或者数据库驱动注册时候。当存在多个隐式的依赖关系时候可以使用“,”进行分割。例子:
此为Aclass类,存在一个静态方法 config();

public class Aclass {

	private static Aclass c;
	
	public static Aclass config() {
		return c;
	}
	public static void setC(Aclass c) {
		Aclass.c = c;
	}
	....省略代码

ABclass类:ABclass的创建需要调用静态方法块内容,静态方法块内容中需要使用Aclass.config().say()方法,而say()需要依赖于Aclass的实体类,因而ABclass与Aclass之间虽然未标明依赖关系但依旧存在一层隐式依赖关系。Aclass需要在ABclass实例化之前实例化。此刻需要使用depends-on,标明隐式依赖关系。

public class ABclass {
	
	static {
		Aclass.config().say();
	}
	....省略代码
	

配置文件设置:

	<bean id="dependsOnTry" class="com.example.demo.xmlparse.ABclass" depends-on="property">< /bean>
	   <bean id="a" class="com.example.demo.xmlparse.Aclass">
		      	<constructor-arg >
		      		<value>1</value>
		      	</constructor-arg>
		      	<constructor-arg>
		      		<value>2</value>
		      	</constructor-arg>
		      </bean>
	      
	      <bean id="property" class="com.example.demo.xmlparse.Aclass">
	      	<property name="a" value="2"></property>
	      	<property name="b" value="1"></property>
	      	<property name="c" ref="a"></property>
	      </bean>

17.bean的可选属性autowire

除开使用配置明确指出依赖关系,还可以使用autowire自动绑定的功能。(非标签方式也可以使用)。这样可以减少手工输入的工作量。spring提供了4种自动绑定的模式:

- no: 容器默认的绑定方式。不自动绑定对象
- byName: 与xml文件中配置的beanName进行匹配。匹配符合的bean定义会被自动绑定到当前实例变量上。适用于setter注入方式。
- byType: 类似与byName 的模式,只是从beanName的判定到beanType判定自动绑定。适用于setter注入方式。
- constructor: constructor指定的是按beanType的自动绑定过程。使用上跟byType类似,适用于构造器注入方式。

注意点:
自动注入的时候如果找不到对应的bean则不进行注入,当找到对应的参数的时候,则会注入,当找到多个可注入对象的时候,因无法判断该注入哪个值会发生异常,因而还是推荐使用手动指定依赖关系。

可以使用< beans >的属性default-autowire 指定beans管理下所有bean的自动注入方式。(一般不推荐)

简单的例子:

	      <bean id="autoByName" class="com.example.demo.xmlparse.Bclass" autowire="byName"></bean>
	      
	      <bean id="autoByType" class="com.example.demo.xmlparse.Bclass" autowire="byType"></bean>
	      
	      <bean id="autoByConstructor" class="com.example.demo.xmlparse.Bclass" autowire="constructor"></bean>
     	  
     	  <alias name="a" alias="x"/>
	      <bean id="a" class="com.example.demo.xmlparse.Aclass">
	      	<constructor-arg >
	      		<value>1</value>
	      	</constructor-arg>
	      	<constructor-arg>
	      		<value>2</value>
	      	</constructor-arg>
	      </bean>

package com.example.demo.xmlparse;

public class Bclass {
	private Aclass a;
		 ....省略代码

测试代码:

//		Bclass b=(Bclass)registry.getBean("autoByName");
//		Bclass b=(Bclass)registry.getBean("autoByType");
		Bclass b=(Bclass)registry.getBean("autoByConstructor");
		b.getA().say();

18. bean的可选属性lazy-init
主要针对于ApplicationContext类型的容器初始化,bean的加载策略,通常对于ApplicationContext容器在容器启动的时候会马上对所有singleton类型的bean进行实例化加载。当想修改这个行为可以使用lazy-init属性加以限制。但是并非指定了lazy-init就一定会延迟加载。未延迟加载的bean对延迟加载的bean存在依赖关系时候,则还是会一开始便初始化设定了延迟加载规则的bean。
可以使用< beans>中的属性 default-lazy-init对beans下的bean进行统一的加载策略设置。

	 <bean id="autoByName" class="com.example.demo.xmlparse.Bclass" autowire="byName" lazy-init="true"></bean>

测试代码

ApplicationContext registry=new ClassPathXmlApplicationContext("classpath:simple.xml");
Bclass b=(Bclass)registry.getBean("autoByName");

运行结果:

19:15:01.325 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'a'
19:15:01.362 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'autoByType'
19:15:01.403 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'autoByConstructor'
19:15:01.403 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Autowiring by type from bean name 'autoByConstructor' via constructor to bean named 'a'
19:15:01.429 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'autoByName'

可以看出执行是在调用时候才进行的实例化。

19.xml中bean的继承关系 :bean属性 parent 与abstract

使用场景:继承关系下,属性继承父类的bean的属性,特定的属性额外配置其值。与java的继承不同的是,此处继承的是属性的值,java继承的属性跟方法。因而这种继承不同于java继承的纵向继承。常规写法需要对子类重复赋值会存在冗余的情况,因而可以考虑使用xml中bean继承。
使用示例:

     <bean id="parentBean" class="com.example.demo.xmlparse.Bclass">
	      	<property name="a" ref="a"></property>
	      	<property name="b" value="223344"></property>
	      </bean>
	      
	      <bean id="children1" class="com.example.demo.xmlparse.Cclass" parent="parentBean">
	      	<property name="b" value="this is children C"></property>
	      </bean>
	      
	      <bean id="children2" class="com.example.demo.xmlparse.Dclass" parent="parentBean">
	      	<property name="b" value="this is children D"></property>
	      </bean>

测试:

public static void main(String[] args) {
		DefaultListableBeanFactory registry=new DefaultListableBeanFactory();
		XmlBeanDefinitionReader beanDefinitionReader=new XmlBeanDefinitionReader(registry);
		beanDefinitionReader.loadBeanDefinitions("simple.xml");
	    Cclass cclass=registry.getBean(Cclass.class);
	    Dclass dclass=registry.getBean(Dclass.class);
	    System.out.println(cclass.getA().equals(dclass.getA()));
	    System.out.println(cclass.getB().equals(dclass.getB()));
	}

parent可以把这个属性与abstract一起使用,以达到模板化bean的目的。在这种情况下,定义为抽象的bean无须指定其class(少数可以不使用class的情景)。例子:

      <bean id="abstractTry" abstract="true">
	      	<property name="a" ref="a"></property>
	      	<property name="b" value="223344"></property>
	      </bean>
	      <bean id="abstractChildren1" class="com.example.demo.xmlparse.Cclass" parent="abstractTry">
	      		<property name="b" value="this is children C"></property>
	      </bean>
	      <bean id="abstractChildren2" class="com.example.demo.xmlparse.Dclass" parent="abstractTry">
	      		<property name="b" value="this is children D"></property>
	      </bean>

测试代码:

	public static void main(String[] args) {
		DefaultListableBeanFactory registry=new DefaultListableBeanFactory();
		XmlBeanDefinitionReader beanDefinitionReader=new XmlBeanDefinitionReader(registry);
		beanDefinitionReader.loadBeanDefinitions("simple.xml");
	    Cclass cclass=(Cclass)registry.getBean("abstractChildren1");
	    Dclass dclass=(Dclass)registry.getBean("abstractChildren2");
	    System.out.println(cclass.getA().equals(dclass.getA()));
	    System.out.println(cclass.getB().equals(dclass.getB()));
	}

虽然abstractTry的bean并未有具体的类,但是其内部的值依旧被Cclass与Dclass的bean继承了。可以看出来在spring容器启动的过程中,标志位abstract的bean定义是不会被创建的。这个适用于全部所有的beanFactory。可以使用该属性,避免bean定义被容器实例化

20.bean的scope属性
该属性也被叫做bean的作用域。主要是负责管理bean的生命周期以及声明对象所处的限定场景。限定好场景后,在进入其对应的scope之前,容器不会生成并装配这些对象。当不再处于其scope限定范围内时候,容器会销毁这个对象。
容器最初提供了两种bean的scope类型:singleton+prototype
在2.0后扩展了3种类型,其后一共是5种类型:

  • request
  • session
  • global session
  • singleton
  • prototype

往后详细介绍下各个scope的特点:

singleton:
对象实例数:在一个容器中,只存在一个共享实例。所有对该类型的bean依赖全部都引用这个单一实例
存活时间:从容器请求而实例化开始,该类型的bean实例会一直存在,直到容器销毁或者退出
示例图:
在这里插入图片描述
prototype
对象实例数:每次接到请求时候,均会重新生成一个新的对象实例。在容器中存在复数个的同类型对象,适用于对象不共享的情况
存活时间:容器生成prototype类型的bean对象时候,会将对象实例返给请求方,容器不再拥有当前返回对象的引用。请求方需要自行管理该bean对象的生命周期
示例图:
在这里插入图片描述
request
只适用于web应用程序。通常与XmlWebApplicationContext一起使用。
实例数:XmlWebApplicationContext会给每个Http请求创建一个全新的Request-Processor供其使用。
存活时间:请求结束时候,该实例生命周期结束。可以说其是prototype的特殊情况。场景比prototype更加具体

session
只适用于web应用程序。通常与XmlWebApplicationContext一起使用。
同request类似,只不过范围从request扩大到了session范围。

global session
只适用于基于portlet的web应用程序。映射到portlet范围的session。在基于servlet的情况下使用的时候,会按session的情况进行处理。

spring容器支持自定义SCOPE.需要实现接口org.springframework.beans.factory.config.Scope

package org.springframework.beans.factory.config;

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.lang.Nullable;

public interface Scope {


	Object get(String name, ObjectFactory<?> objectFactory);


	@Nullable
	Object remove(String name);


	void registerDestructionCallback(String name, Runnable callback);


	@Nullable
	Object resolveContextualObject(String key);


	@Nullable
	String getConversationId();}

其中get,remove是必须要实现的方法。

这里给出两种实现方式:

其一:编码方式实现

创建线程生命周期的Scope:ThreadScope

public class ThreadScope implements Scope{
	
	private final ThreadLocal threadScope=new ThreadLocal() {
		protected Object initialValue() {
			return new HashMap<>();
		}
	};
	
	@Override
	public Object get(String name, ObjectFactory<?> objectFactory) {
		// TODO Auto-generated method stub
		Map scope=(Map) threadScope.get();
		Object object=scope.get(name);
		if(object==null) {
			object=objectFactory.getObject();
			scope.put(name, object);
		}
		return object;
	}

	@Override
	public Object remove(String name) {
		// TODO Auto-generated method stub
		Map scope=(Map) threadScope.get();
		
		return scope.remove(name);
	}
	....省略代码

设定beanFactory为其注册名为“thread”的scope

	public static BeanFactory getMyBeanFactory() {
		ConfigurableBeanFactory beanFactory=new DefaultListableBeanFactory();
		Scope myScope=new ThreadScope();
		beanFactory.registerScope("thread", myScope);
		AbstractBeanDefinition beanB=new RootBeanDefinition(Bclass.class);
		AbstractBeanDefinition beanA=new RootBeanDefinition(Aclass.class);
		MutablePropertyValues propertyValuesB=new MutablePropertyValues();
		propertyValuesB.add("a", beanA);
		propertyValuesB.add("b", "BClass类b属性编码方式Setter注入");
		beanB.setPropertyValues(propertyValuesB);
		
		MutablePropertyValues propertyValuesA=new MutablePropertyValues();
		propertyValuesA.add("c", new Aclass("Aclass类 c属性编码Setter注入值",0));
		propertyValuesA.add("b", 2);
		propertyValuesA.add("a", "Aclass类 a属性编码Setter注入值");
		beanA.setPropertyValues(propertyValuesA);
		
		beanB.setScope("thread");
		beanA.setScope("singleton");
		((DefaultListableBeanFactory)beanFactory).registerBeanDefinition("threadScope", beanB);
		((DefaultListableBeanFactory)beanFactory).registerBeanDefinition("singletonScope", beanA);
		return beanFactory;
	}

获取注册的Bean

		BeanFactory beanFactory=getMyBeanFactory();
		Aclass aclass=(Aclass)beanFactory.getBean("singletonScope");	
		Bclass bclass=(Bclass)beanFactory.getBean("threadScope");
		if(bclass!=null) {
			System.out.println(bclass.getB());
			bclass.getA().say();
		}

其二:xml配置文件方式:
首先需要创建一个继承了BeanFactory的类,同时初始化时候需要将“thread”注册到容器中。

public class BeanFactoryScopeTry extends DefaultListableBeanFactory{
	public BeanFactoryScopeTry() {
		ThreadScope threadScope=new ThreadScope();
		this.registerScope("thread", threadScope);
	}
}

编写xml文件:

 <bean id="scopeDefineTry" class="com.example.demo.xmlparse.Bclass" scope="thread">
	      	 <property name="a" ref="a"></property>
	      	 <property name="b" value="我的自定义scopeBean"></property>
	      </bean>

调用定义的bean:

BeanFactory beanFactory=new BeanFactoryScopeTry();
		XmlBeanDefinitionReader reader=new XmlBeanDefinitionReader((BeanDefinitionRegistry)beanFactory);
		reader.loadBeanDefinitions("simple.xml");
		Bclass b=(Bclass) beanFactory.getBean("scopeDefineTry");
		b.getA().say();

21.bean属性 :factory-method 与factory-bean

使用工厂方法,解决接口与实现类的耦合性。提供一个工厂类来实例化具体的接口实现类。主体对象只需要依赖工厂类。具体使用的实现类存在变更的时候。可以通过变更工厂类实现,主体类不需要变动。(正常通过依赖注入的方式也可以解决耦合问题情况,但是在依赖注入的过程中总是会有耦合存在的,使用工厂类可以屏蔽两者之间的直接耦合)

方式一:静态工厂方式

静态工厂方法模式指的是其工厂方法由static修饰的,这类方法不需要依赖一个工厂实例,只需要一个工厂类路径即可,因而不需要使用factory-bean,只需要指定其工厂类class。
例子:
配置文件:

<bean id="main" class="com.example.demo.beanfactory.MainBean">
        	<property name="bean" ref="instance"></property>
</bean>
        
<bean id="instance" class="com.example.demo.beanfactory.MyBeanFactory" factory-method="getInstance"></bean>

bean类:


package com.example.demo.beanfactory;

public class BeanFactoryTry {
	private String a;

	public String getA() {
		return a;
	}

	public void setA(String a) {
		this.a = a;
	}
	
}

工厂类:

package com.example.demo.beanfactory;

public class MyBeanFactory {
	public static BeanFactoryTry getInstance() {
		 BeanFactoryTry bean=new BeanFactoryTry();
		 bean.setA("A Value");
		 return bean;
	}
}

调用:

		DefaultListableBeanFactory beanFactory=new DefaultListableBeanFactory();
		XmlBeanDefinitionReader reader=new XmlBeanDefinitionReader(beanFactory);
		reader.loadBeanDefinitions("simple2.xml");
		MainBean bean=(MainBean) beanFactory.getBean("main");
		System.out.println(bean.getBean().getA());

此方式定义的bean (“instance”)其类型值与class不一定一致,其bean值的类型主要与其工厂方法返回值有关。
如果工厂方法需要入参。则需要使用标签< constructor -arg>进行值的入参
如:

      <bean id="instance" class="com.example.demo.beanfactory.MyBeanFactory" factory-method="getInstance">
        	<constructor-arg ref="..."></constructor-arg>
        </bean>

方式二:非静态工厂方法模式

不同于静态工厂方法模式,该类型的工厂方法是非静态的,因而需要依赖一个具体的工厂实现类bean,需要使用到属性factory-bean指定工厂方法所在的工厂bean实例

其余方面的使用方式同静态工厂方式。

例子:

        <bean id="main" class="com.example.demo.beanfactory.MainBean">
        	<property name="bean" ref="instance"></property>
        </bean>
        <bean id="factory" class="com.example.demo.beanfactory.MyBeanFactory"></bean>
        <bean id="instance" factory-bean="factory" factory-method="getNonInstance"></bean>

测试:

	DefaultListableBeanFactory beanFactory=new DefaultListableBeanFactory();
		XmlBeanDefinitionReader reader=new XmlBeanDefinitionReader(beanFactory);
		reader.loadBeanDefinitions("simple2.xml");
		MainBean bean=(MainBean) beanFactory.getBean("main");
		System.out.println(bean.getBean().getA());

工厂方法:

public class MyBeanFactory {

	
	public BeanFactoryTry getNonInstance() {
		 BeanFactoryTry bean=new BeanFactoryTry();
		 bean.setA("A Value");
		 return bean;
	}
	....省略代码

注意点:
Spring的特殊类型FactoryBean的实现类,当xml文件引用其id对象的时候,返回值是其工厂方法产生的bean。这种方式引用时候,不需要使用到factory-bean及factory-method.当想让引用的对象是FactoryBean本身时候,需要在其id 的name前面加前缀:"&".

例子:

        <bean id="main" class="com.example.demo.beanfactory.MainBean">
        	<!-- <property name="bean" ref="instance"></property> -->
        	<property name="bean" ref="factoryBean"></property>
        </bean>
        
        <bean id="factoryBean" class="com.example.demo.beanfactory.MyFactoryBean"></bean>

测试:

		DefaultListableBeanFactory beanFactory=new DefaultListableBeanFactory();
		XmlBeanDefinitionReader reader=new XmlBeanDefinitionReader(beanFactory);
		reader.loadBeanDefinitions("simple2.xml");
		MyFactoryBean factoryBean=(MyFactoryBean) beanFactory.getBean("&factoryBean");
		MainBean bean=(MainBean) beanFactory.getBean("main");
		System.out.println(bean.getBean().getA());

几种常见的FactoryBean:

  • org.springframework.jndi.JndiObjectFactoryBean
  • org.springframework.aop.framework.ProxyFactoryBean

22. < bean> 子标签< lookup-method name="…" bean="…"> (方法注入)

spring依赖注入之后,正常来说被注入 的bean会持有这个注入的bean的引用,就算这个bean是prototype亦是如此。如此导致的结果便是,每次调用被注入的bean的get方法时候,获取的都会是同一个Bean对象。当想要让每次get访问的时候获取到的都是不一样的bean之时,处理方式有两种:
其一:使用标签< lookup-method>方法注入方式实现

配置方式:

  <bean id="prototype" class="com.example.demo.beanfactory.BeanFactoryTry" scope="prototype"></bean>
  <bean id="lookup-method" class="com.example.demo.beanfactory.MainBean">
        	<lookup-method name="getBean" bean="prototype"/>
  </bean>

配置方式中第一个属性:name是com.example.demo.beanfactory.MainBean中的方法。
配置方式中第二个属性:bean是容器中存在的bean的名字。表示,当调用MainBean中的getBean方法时候,把容器中名为prototype的bean值get出来作为返回值,返回。因为此处prototype是原型模式,因而测试案例中返回值两次是不一样的。这种方式是不看MainBean对象中的原先getBean方法的实现是什么 ,哪怕你之前返回值是空,亦不会影响其返回两个不同的bean实例。可以看做是将原先的getBean方法替换了。

测试案例:

		DefaultListableBeanFactory beanFactory=new DefaultListableBeanFactory();
		XmlBeanDefinitionReader reader=new XmlBeanDefinitionReader(beanFactory);
		reader.loadBeanDefinitions("simple2.xml");

		MainBean mainBean=(MainBean) beanFactory.getBean("lookup-method");
		System.out.println(mainBean.getBean());
		System.out.println(mainBean.getBean());

执行结果:

com.example.demo.beanfactory.BeanFactoryTry@2758fe70
com.example.demo.beanfactory.BeanFactoryTry@1f36e637

其二:使用接口的方式实现。

在第一种方式中其实可以看出端倪,主要需要注意的是getBean方法返回的bean值是需要从容器中获取的值。因而可以将MainBean 类与BeanFactory耦合。重写getBean方法,使其return的值是从BeanFactory中获取到的值即可。
Spring提供了接口BeanFactoryAware。实现该接口的类。会自动将容器本身注入到该类当中

配置:

<bean id="prototype" class="com.example.demo.beanfactory.BeanFactoryTry" scope="prototype"></bean>
		<bean id="beanFactoryAware" class="com.example.demo.beanfactory.MainBean">
		</bean>

对MainBean的改造:

public class MainBean implements BeanFactoryAware{
	
	private BeanFactory beanFactory;
	
	@Override
	public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
		// TODO Auto-generated method stub
		this.beanFactory=beanFactory;
	}

	private BeanFactoryTry bean;

	public BeanFactoryTry getBean() {
		return (BeanFactoryTry) beanFactory.getBean("prototype");
	}

	public void setBean(BeanFactoryTry bean) {
		this.bean = bean;
	}
	
}

测试结果殊途同归,在此省略…

对于不喜欢将BeanFactory与具体类耦合的类。Spring提供了ObjectFactoryCreatingFactoryBean.此类返回一个ObjectFactory实例。

package com.example.demo.beanfactory;

import org.springframework.beans.factory.ObjectFactory;


public class MainBeanObjectFactory {
	
	private ObjectFactory<BeanFactoryTry> objectFactory;
                                                                                                                                                            	
	public void setObjectFactory(ObjectFactory<BeanFactoryTry> objectFactory) {
		this.objectFactory = objectFactory;
	}

	private BeanFactoryTry bean;

	public BeanFactoryTry getBean() {
		return objectFactory.getObject();
	}

	public void setBean(BeanFactoryTry bean) {
		this.bean = bean;
	}
	
}

配置文件

		<bean id="prototype" class="com.example.demo.beanfactory.BeanFactoryTry" scope="prototype"></bean>
		
		<bean id="objectFactory" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
			<property name="targetBeanName">
				<idref bean="prototype"/>
			</property>
		</bean>
		<bean id="objectFactoryMainBean"  class="com.example.demo.beanfactory.MainBeanObjectFactory">
			<property name="objectFactory" ref="objectFactory"></property>
		</bean>

此处给objectFactoryMainBean填入的引用虽然是objectFactory,但其实注入的值是prototype的对应ObjectFactory实例。
调用测试方法:

		DefaultListableBeanFactory beanFactory=new DefaultListableBeanFactory();
		XmlBeanDefinitionReader reader=new XmlBeanDefinitionReader(beanFactory);
		reader.loadBeanDefinitions("simple2.xml");
		MainBeanObjectFactory mainBean=(MainBeanObjectFactory) beanFactory.getBean("objectFactoryMainBean");
		System.out.println(mainBean.getBean());
		System.out.println(mainBean.getBean());

结果依旧是不同的两个bean值。

23.方法替换< replaced-method>方法

< replaced-method>标签用于替换掉bean中的方法。其内部属性包括两个部分:

  • name 要替换的方法名
  • replacer 替换的类的bean名。这个类需要实现接口MethodReplacer.

例子:
替换类,实现MethodReplacer

public class MyMethodReplacer implements MethodReplacer{
	private static final Log logger=LogFactory.getLog(MyMethodReplacer.class);
	@Override
	public Object reimplement(Object obj, Method method, Object[] args) throws Throwable {
		// TODO Auto-generated method stub
		logger.info("before excuting method");
		System.out.println(method.getName()+"on Object :"+obj.getClass().getName());
		logger.info("end of excuting method");
		return null;
	}

}

配置文件:

<bean id="replacer" class="com.example.demo.beanfactory.MyMethodReplacer"></bean>
		<bean id="replaceAMethod" class="com.example.demo.xmlparse.Aclass">
			<property name="a" value="name of A"></property>
			<property name="b" value="999"></property>
			<replaced-method name="say" replacer="replacer"></replaced-method>
		</bean>

测试结果:

20:49:53.657 [main] INFO com.example.demo.beanfactory.MyMethodReplacer - before excuting method
sayon Object :com.example.demo.xmlparse.Aclass E n h a n c e r B y S p r i n g C G L I B EnhancerBySpringCGLIB EnhancerBySpringCGLIBa85dfd94
20:49:53.657 [main] INFO com.example.demo.beanfactory.MyMethodReplacer - end of excuting method

可以发现原有的say()方法被替换。

部分代码不清楚的地方,这里放上github示例代码信息。

源码github下载地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值