深入理解Spring容器中的bean
使用抽象bean
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的属性
spring的bean继承和java中继承完全不一样
1.spring中子bean和父bean可以是不同的类型,但java中继承可以保证子类是一种特殊的父类
2.spring中的bean的继承是实例之间的关系,因此主要表现为参数的延续;而java中的继承是类之间的关系,主要表现在方法和属性的延续
3.spring中子bean不可以作为父bean使用,不具备多态性,java中的子类实例完全可以当成父类实例使用
容器中的工厂bean:
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 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;
}
}
/**
*测试 采用 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
}
获取bean在配置文件中ID
实现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;
}
}
容器中bean的生命周期
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接口
//测试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();
}