Spring-IOC-bean基础

Bean的类型

普通bean
工厂bean

普通bean
我们平时在xml中定义的bean,还有通过@Component定义的bean。

<bean class="com.test.bean.Child"/>
@Component
public class Child {
}
@Bean
public Child child() {
    return new Child();
}

工厂bean
场景:
  Bean的创建需要指定一些策略,或者依赖特殊的场景来分别创建,又或者bean的创建过程太复杂,使用xml或者注解声明比较复杂。
  这种情况下,普通bean的创建就搞不定了。

Factorybean:使用工厂方法创建对象。本身就是一个创建对象的工厂接口。如果定义的bean实现了FactoryBean接口,那这个bean本身就不是普通的bean,不会在实际业务逻辑中起作用,而是由**创建的对象来起作用**。

public class Child {
    // 当前的小孩子想玩球
    private String wantToy = "ball";
    
    public String getWantToy() {
        return wantToy;
    }
public abstract class Toy {
    
    private String name;
    
    public Toy(String name) {
        this.name = name;
}

public class Ball extends Toy { // 球
    
    public Ball(String name) {
        super(name);
    }
}

public class Car extends Toy { // 玩具汽车
    
    public Car(String name) {
        super(name);
    }
}
public interface FactoryBean<T> {
    // 返回创建的对象
    @Nullable
    T getObject() throws Exception;

    // 返回创建的对象的类型(即泛型类型)
    @Nullable
    Class<?> getObjectType();

    // 创建的对象是单实例Bean还是原型Bean,默认单实例
    default boolean isSingleton() {
        return true;
    }
}

定义一个工厂bean,玩具工厂根据小孩的爱好生产玩具:

public class ToyFactoryBean implements FactoryBean<Toy> {
    private Child child;
   
    @Override
    public Toy getObject() throws Exception {
        switch (child.getWantToy()) {
            case "ball":
                return new Ball("ball");
            case "car":
                return new Car("car");
            default:
                // SpringFramework2.0开始允许返回null
                // 之前的1.x版本是不允许的
                return null;
        }
    }
    
    @Override
    public Class<Toy> getObjectType() {
        return Toy.class;
    }
    
    public void setChild(Child child) {
        this.child = child;
    }
}

xml方式:

<bean id="child" class="com.linkedbear.spring.bean.a_type.bean.Child"/>
<bean id="toyFactory" class="com.test.bean.ToyFactoryBean">
        <property name="child" ref="child"/>
 </bean>

注解方式:

@Bean
    public Child child() {
        return new Child();
    }
    
    @Bean
    public ToyFactoryBean toyFactory() {
        ToyFactoryBean toyFactory = new ToyFactoryBean();
        toyFactory.setChild(child());
        return toyFactory;
    }

FactoryBean本身的加载是伴随IOC容器的初始化时机一起的。
FactoryBean创建bean的时机是延迟生成。
FactoryBean中有一个默认方法isSingleton,默认是true。代表是单例的。FactoryBean默认生成的Bean也是单例的。

注意:如果通过上下文取FactoryBean本体,传入getBean(id),FactoryBean的id前面需要加"&“符号。getBean(”&id")。不加&,取出来的还是生产的Bean。

Bean的作用域

spring框架的内置的作用域
在这里插入图片描述

Bean的实例化方式

实例化:通过调用构造方法,创建新的对象。

普通bean实例化
bean标签,@Bean注解都是普通bean的对象。IOC容器初始化时就已经被初始化。

FactoryBean创建bean
注册Bean时,只需要注入FactoryBean,IOC容器会自动识别,并默认在第一次获取时创建对应的Bean并缓存(针对默认的单实例FactoryBean)。

静态工厂创建Bean

public class Cat {
    public Car() {}
}
public class CarStaticFactory {
    pubic static Car getCar() {
      return new Car();
   }
}

下面代码中,上面的是普通bean的注册方式,下面的会直接引用静态方法创建对象。

<bean id="car1" class="com.test.bean.Car"/>

<bean id="car2" class="com.test.CarStaticFactory" factory-method="getCar"/>
public class BeanInstantiateXmlApplication {
    
    public static void main(String[] args) throws Exception {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("resource/applicationContext.xml");
        ctx.getBeansOfType(Car.class).forEach((beanName, car) -> {
            System.out.println(beanName + " : " + car);
        });
    }
}

可以看到创建了两个Car的对象

car1 : com.linkedbear.spring.bean.c_instantiate.bean.Car@3c0ecd4b
car2 : com.linkedbear.spring.bean.c_instantiate.bean.Car@14bf9759

注意:静态工厂类本身不会被注册到IOC容器中

实例工厂创建bean

public class CarInstanceFactory {
    
    public Car getCar() {
        return new Car();
    }
}
<bean id="carInstanceFactory" class="com.test.bean.CarInstanceFactory"/>
<bean id="car3" factory-bean="carInstanceFactory" factory-method="getCar"/>

Bean的生命周期-初始化与销毁

创建 / 实例化阶段:此时会调用类的构造方法,产生一个新的对象

初始化阶段:此时对象已经创建好,但还没有被正式使用,可能这里面需要做一些额外的操作(如预初始化数据库的连接池)

运行使用期:此时对象已经完全初始化好,程序正常运行,对象被使用

销毁阶段:此时对象准备被销毁,已不再使用,需要预先的把自身占用的资源等处理好(如关闭、释放数据库连接)

回收阶段:此时对象已经完全没有被引用了,被垃圾回收器回收

spring框架除了回收阶段干预不了,其他阶段都可以干预。

回想一下ServletServlet里面有两个方法initdestroy。这两个方法都被Web容器调用,用来初始化和销毁Servlet的。这种方法的设计思想就是“回调机制”。它都不是给自己设计的,而是由父类/接口定义好的,由第三者(框架,容器等)来调用。

init-method和destroy-method

1.init-method,destroy-method

public class Dog {
    
    private String name;
    
    public void setName(String name) {
        this.name = name;
    }
    
    public void init() {
        System.out.println(name + "被初始化了。。。");
    }
    public void destroy() {
        System.out.println(name + "被销毁了。。。");
    }
}
<bean class="com.test.bean.Cat"
          init-method="init" destroy-method="destroy">
     <property name="name" value="小熊"/>
 </bean>
@Bean(initMethod = "init", destroyMethod = "destroy")
    public Dog dog() {
        Dog dog = new Dog();
        dog.setName("小熊");
        return dog;
    }

方法特征:
  方法访问权限无限制要求(通过反射调用)
  方法无参数
  方法无返回值
  可以抛出异常(异常不由自己处理,交予spring框架可以打断Bean的初始化/销毁步骤)

public class InitMethodXmlApplication {
    
    public static void main(String[] args) throws Exception {
        System.out.println("准备初始化IOC容器。。。");
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("resuorce/applicationContext.xml");
        System.out.println("IOC容器初始化完成。。。");
        
        System.out.println();
        
        System.out.println("准备销毁IOC容器。。。");
        ctx.close();
        System.out.println("IOC容器销毁完成。。。");
    }
}
准备初始化IOC容器。。。
小熊被初始化了。。。
IOC容器初始化完成。。。

准备销毁IOC容器。。。
小熊被销毁了。。。
IOC容器销毁完成。。。

在IOC容器初始化之前,默认情况下Bean已经创建好了,而且完成了初始化动作。容器调用销毁动作时,先销毁所有Bean,最后IOC容器全部销毁完成。

Bean的声明周期中,是先对属性赋值,后执行init-method标记的方法。

2.JSR250规范
对于使用模式注解的Bean,通过使用注解@PostConstruct,@PreDestroy注解,分别对应init-method和destroy-method。

@Component
public class Pen {
    
    private Integer ink;
    
  @PostConstruct
    public void addInk() {
        System.out.println("钢笔中已加满墨水。。。");
        this.ink = 100;
    }
    
    @PreDestroy
    public void outwellInk() {
        System.out.println("钢笔中的墨水都放干净了。。。");
        this.ink = 0;
    }
    
    @Override
    public String toString() {
        return "Pen{" + "ink=" + ink + '}';
    }
}

3.InitializingBean和DisposableBean

@Component
public class Pen implements InitializingBean, DisposableBean {
    
    private Integer ink;
    
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("钢笔中已加满墨水。。。");
        this.ink = 100;
    }
    
    @Override
    public void destroy() throws Exception {
        System.out.println("钢笔中的墨水都放干净了。。。");
        this.ink = 0;
    }
    
    @Override
    public String toString() {
        return "Pen{" + "ink=" + ink + '}';
    }
}

总的初始化执行循序:
@PostConstruct → InitializingBean → init-method 。

注意:原型 Bean 在销毁时不处理 destroy-method 标注的方法

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值