spring 第4天bean继承,init,destory-method

本文详细探讨了Spring容器中bean的使用,特别是抽象bean的概念及其配置技巧,包括如何利用抽象bean减少配置冗余,以及子bean如何继承父bean的属性等。此外,还介绍了工厂bean的实现方式和bean的生命周期管理。
[size=large][b]深入理解Spring容器中的bean[/b][/size]
[b]使用抽象bean[/b]

1.抽象bean被作为一种模板,在spring中被应用,在ApplicationContext初始化的时候,不会初始化抽象bean, 因此抽象bean的配置中可以没有 class.
2.抽象bean的作用主要是为了减少配置文件中多个bean之间拥有的重复的配置.
3.子bean无法从父bean中继承如下属性:depends-on,autowire,singleton,scope,lazy-init
4.如果 父bean写了class 则 子bean可以不用写class 和父类共用同一个实现类.
5.如果 父bean没有写class,则子bean必须写class
6.如果 父bean写了class,子bean也写了class,子bean覆盖 父bean的属性


<!-- 抽象bean -->
<bean id="personTemplate" class="cn.sh.springmvc_java.Chinese" abstract="true">
<property name="axe" ref="stoneAxe_sf"/>
</bean>
<bean id="personTemplate1" abstract="true">
<property name="axe" ref="steelAxe_sf"/>
</bean>

<!-- 子bean继承 -->
<bean id="china_child" parent="personTemplate"/>

<!-- 子bean 覆盖父类的bean -->
<bean id="china_child1" parent="personTemplate">
<property name="axe" ref="steelAxe_sf"/>
</bean>

spring的bean继承和java中继承完全不一样

1.spring中子bean和父bean可以是不同的类型,但java中继承可以保证子类是一种特殊的父类
2.spring中的bean的继承是实例之间的关系,因此主要表现为参数的延续;而java中的继承是类之间的关系,主要表现在方法和属性的延续
3.spring中子bean不可以作为父bean使用,不具备多态性,java中的子类实例完全可以当成父类实例使用


[b]容器中的工厂bean:[/b]
1和前面介绍的静态工厂创建bean和实例工厂创建bean有区别,这里的工厂bean是spring中一种特殊的bean,该工厂bean必须实现FactoryBean接口,而且实现后的bean
只能作为工厂bean使用.
2.而且通过getBean()来获取工厂bean的时候返回的不是FactoyBean,而是工厂bean生产的java
实例
3.如果要获取 factoryBean 要在bean的id 前面加上 "&"


package cn.sh.springmvc_java.factory;

import org.springframework.beans.factory.FactoryBean;

import cn.sh.springmvc_java.American;
import cn.sh.springmvc_java.People;

/**
* 采用 spring的工厂bean:默认 是singleton
*
*/
public class PeopleFactory1 implements FactoryBean<People>{

//People p=null;
//这个方法只调用一次, 因为 scope="singleton" 如果prototype 就会每次调用
@Override
public People getObject() throws Exception {
/* // TODO Auto-generated method stub
if(p==null){
p=new American();
}*/
System.out.println("1");
return new American();
}

@Override
public Class<?> getObjectType() {
// TODO Auto-generated method stub
return American.class;
}

@Override
public boolean isSingleton() {
// TODO Auto-generated method stub
return true;
}

}



<!--可以去掉prototye 属性,这样 就是默认的单例了-->
<bean id="people" class="cn.sh.springmvc_java.factory.PeopleFactory1" scope="prototype"/>



/**
*测试 采用 factoryBean 创建的对象 发现获取不了配置ID
* xml创建的对象 可以获取配置时候的id
*/
@Test
public void test13(){
ApplicationContext act=new ClassPathXmlApplicationContext("classpath*:applicationContent.xml");
People p=act.getBean("people",People.class);
System.out.println(p.sayHello("Mary"));
System.out.println(p.sayGoodBye("Mary"));
People p1=act.getBean("people",People.class);
System.out.println(p==p1); //单例就为true 否则为false

//获取 factoryBean 本身
System.out.println(act.getBean("&people"));
System.out.println(p.getClass());
p.toString();

People pa=act.getBean("american",People.class);
System.out.println(pa.sayHello("Mary"));
System.out.println(pa.sayGoodBye("Mary"));
pa.toString(); //会打印出 配置的id
}


[b]获取bean在配置文件中ID[/b]
实现BeanNameAware 的setBeanName(String name);



package cn.sh.springmvc_java;

import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
/**
* BeanNameAware 实现后,可以获取该bean的定义时的id
* InitializingBean 实现后,可以在 spring初始化Bean完成后,执行指定的方法
* DisposableBean :Bean在被销毁前,执行特点的方法
*
* 注意: DisposableBean的 destory 方法 和 配置文件中的destory-method 只对scope的 singleton Bean有用
* 可以将 Beans 的 default-init-method 和 default-destory-method和Bean的 方法 联合起来用
*/
public class American implements People,BeanNameAware,InitializingBean,DisposableBean {

private String beanName;

@Override
public void setBeanName(String name) {
// TODO Auto-generated method stub
System.out.println("执行BeanNameAware 的set方法 获取BeanName");
this.beanName=name;
}

@Override
public String sayHello(String name) {
// TODO Auto-generated method stub
return name+",hello";
}

@Override
public String sayGoodBye(String name) {
// TODO Auto-generated method stub
return name+",Good Bye";
}

@Override
public String toString() {
// TODO Auto-generated method stub
System.out.println("china实现类,部署该Bean是指定的ID为:"+beanName);
return null;
}

//实现InitializingBean后,可以在初始化完成后 调用下面的方法 这样有代码污染
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("正在执行InitializingBean接口的afterPropertiesSet");
}

//在配置文件中配置 init-method 这种没有代码污染 推荐
public void init(){
System.out.println("init-method:正在初始化....");
}

@Override
public void destroy() throws Exception {
System.out.println("实现DisposableBean,即将被销毁...");
}

public void close(){
System.out.println("destory-method:即将被销毁.....");

}

public String getBeanName() {
return beanName;
}

}

[b]容器中bean的生命周期[/b]
1.spring可以管理singleton 作用域的bean的生命周期,spring可以精确的知道该bean何时被创建,何时初始化完成,容器何时销毁该bean.
2.对于prototype的bean.spring只负责创建,之后,完全交割客户端代码,容器不在跟踪其生命周期.

依赖关系注入之后的行为 spring提供了两种方式完成
1.使用init-mehtod
2.实现initializingBean 接口
3.如果这两个都写了, 会先执行 initialingBean 接口的方法 然后执行 init-method

Bean销毁之前的行为
1.使用 destory-method
2.实现despoableBean接口


<bean id="peopleFactory" class="cn.sh.springmvc_java.factory.PeopleFactory"/>
<bean id="china" factory-bean="peopleFactory" factory-method="getPeople">
<constructor-arg value="chin"/>
</bean>
<bean id="american" factory-bean="peopleFactory" factory-method="getPeople" scope="prototype" init-method="init" destroy-method="close">
<constructor-arg value="ame"/>
</bean>


//测试init -method 和 destory -method
@Test
public void test15(){
AbstractApplicationContext act=new ClassPathXmlApplicationContext("classpath*:applicationContent.xml");
People pa=act.getBean("american",People.class);
pa.toString();
//未来让spring容器注册关闭钩子
act.registerShutdownHook();
System.out.println("aaa");
pa=null;
System.gc();
}
<think>我们正在处理用户的问题:SpringXML配置中不允许使用destroy-method属性。用户在使用Spring框架时遇到了这个问题,需要了解原因和解决方案。根据用户的问题,我们首先需要明确:在Spring的XML配置中,<bean>元素通常支持destroy-method属性,用于指定在bean销毁时调用的方法。但是,用户遇到了不允许使用的情况,可能是由于某些配置或环境限制。接下来,我们分析可能的原因:1.**XMLSchema定义的限制**:如果用户使用的XMLSchema版本不支持destroy-method属性,或者命名空间声明不正确,可能导致解析错误。2.**Bean定义的类型**:如果bean不是由Spring容器直接管理(例如,它是通过工厂方法创建的),可能会有限制。3.**配置位置**:destroy-method属性通常用于<bean>元素,但如果在错误的元素上使用(比如在<property>内部),则不允许。另外,参考用户提供的引用内容:-引用[1]提到了ContextNamespaceHandler,这通常用于处理<context:>命名空间下的元素,与<bean>元素不同。-引用[2]和[3]是关于基于Java的配置和属性扫描,与XML配置中的destroy-method属性没有直接关系。因此,我们重点分析XML配置中的<bean>元素。**解决方案步骤:**1.**检查XML命名空间和Schema定义**:确保XML文件的头部声明了正确的命名空间,并且包含了beans的Schema定义。正确的声明应该类似于:```xml<beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd">```如果缺少正确的Schema定义,可能导致属性不被识别。2.**确认destroy-method的使用位置**:destroy-method是<bean>元素的属性,例如:```xml<beanid="exampleBean"class="com.example.ExampleBean"destroy-method="cleanup"/>```确保它被用在<bean>标签上,而不是其他标签。3.**检查IDE或编辑器的问题**:有时候,IDE的XML校验可能因为缓存或配置问题而错误地标记属性为不允许。尝试清理项目或重新导入。4.**Spring版本兼容性**:虽然destroy-method是一个长期存在的属性,但极低版本的Spring可能不支持,但这种情况很少见。确保使用的Spring版本在3.0以上(通常都支持)。5.**替代方案**:如果确实无法使用destroy-method属性,可以考虑使用其他方式实现销毁方法:-实现`DisposableBean`接口,并实现`destroy()`方法。-使用JSR-250的`@PreDestroy`注解(需要启用注解扫描):```xml<context:annotation-config/>```然后在bean的方法上加上`@PreDestroy`。6.**查看错误信息**:如果用户得到的是具体的错误信息(如编译错误或部署错误),请根据错误信息进一步诊断。例如,如果错误信息是“Attribute'destroy-method'isnotallowed”,则很可能是XML结构问题。**总结**:用户遇到destroy-method属性不允许使用的问题,首先需要检查XML的命名空间和Schema定义是否正确,确保destroy-method被用在<bean>标签上。如果问题仍然存在,可以考虑使用替代方案(如实现DisposableBean接口或使用@PreDestroy注解)。最后,根据指令,我们需要生成相关问题:§§相关问题§§1.如何正确配置SpringXML中的bean销毁方法?2.Spring中除了destroy-method,还有哪些方式可以定义bean的销毁方法?3.为什么在SpringXML配置中会出现属性不被允许的错误?</think>### Spring XML配置中destroy-method属性不允许的原因与解决方案 在Spring XML配置中,`destroy-method`属性通常用于指定bean销毁时调用的方法。若遇到该属性不被允许的情况,主要可能由以下原因及解决方案: #### 原因分析 1. **XML Schema验证失败** - 当XML头部命名空间声明或Schema定义不完整时,IDE/解析器会严格校验属性合法性。 - 示例错误:缺少`spring-beans`的Schema定义: ```xml <!-- 错误示例:缺少xsi:schemaLocation中的spring-beans定义 --> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> ``` 2. **作用域限制** - `prototype`作用域的bean默认不执行销毁方法,显式声明`destroy-method`可能被IDE标记为冗余。 3. **注解配置冲突** - 若同时使用`@PreDestroy`注解和XML配置的`destroy-method`,可能触发校验警告。 #### 解决方案 1. **完善XML Schema定义** 确保`xsi:schemaLocation`包含完整的`spring-beans`定义: ```xml <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 http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="myBean" class="com.example.MyBean" destroy-method="cleanup"/> </beans> ``` 2. **使用替代销毁机制** - **实现`DisposableBean`接口**(强制实现`destroy()`方法): ```java public class MyBean implements DisposableBean { @Override public void destroy() { /* 清理逻辑 */ } } ``` - **JSR-250 `@PreDestroy`注解**(需启用注解扫描): ```xml <context:annotation-config/> ``` ```java public class MyBean { @PreDestroy public void cleanup() { ... } } ``` 3. **检查作用域配置** 对`prototype`作用域的bean,销毁方法需通过其他方式触发(如手动调用`ConfigurableBeanFactory.destroyBean()`)。 #### 最佳实践建议 - 优先使用`@PreDestroy`注解,与组件扫描更兼容[^3]。 - 对于第三方库的bean(无法修改源码),再使用XML的`destroy-method`。 - 始终验证XML Schema定义,避免解析错误[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值