如何手动实现Spring Bean的生命周期全过程

spring bean注入方式

构造器注入

    <!--构造器注入-->
    <bean id="user" class="com.sean.spring.User">
        <constructor-arg index="0" value="德莱文"/>
        <constructor-arg index="1" value="18"/>
    </bean>

setter注入

    <!--setter注入-->
    <bean id="user" class="com.sean.spring.User">
        <property name="name" value="无敌"></property>
        <property name="age" value="18"></property>
    </bean>

如果我们一个类中多个参数,那么我们要赋值岂不是通过以上两种方法要写很多,除了通过xml注入,还可以通过注解的方式注入注入。
context:annotation-config ,用于激活那些已经在spring容器里注册过的bean

    <context:annotation-config></context:annotation-config>
    <bean id="user" class="com.sean.spring.User"/>

然后在类中需要注入值的属性上添加@Autowired,如果需要设置,可通过 @Value直接给值

    @Autowired
    @Value("无敌")
    public void setName(String name) {
        this.name = name;
    }
    @Autowired
    @Value("25")
    public void setAge(Integer age) {
        this.age = age;
    }

当然项目中有很多类,通过这种方式,岂不是也要配置很多的bean,别怕,Spring提供了扫描包的方式。
context:component-scan自动将带有@component,@service,@Repository等注解的对象注册到spring容器中的功能。

<context:component-scan base-package="com.sean.spring" />

只需在类中添加@Component

@Component
public class User{

    private Long id;

    private String name;

    private Integer age;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    @Autowired
    @Value("无敌")
    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }


    public String getUser(){
        String user = "我的名字是"+ name+"我今年" + age+"岁";
        return user;
    }
}

测试后输出:

我们将applicationContext.xml配置文件作如下修改:
在这里插入图片描述
关于spring配置注解context:annotation-configcontext:component-scan区别,网上很多博客都有讲解
https://www.cnblogs.com/leiOOlei/p/3713989.html

Spring bean 的生命周期

  • 如果Bean实现了BeanNameAwaresetBeanName方法,那么它就会调用这个方法。
  • 如果Bean实现了BeanFactoryAwaresetBeanFactory方法,那么它就会调用这个方法。
  • 如果Bean实现了ApplicationContextAwaresetApplicationContext方法,且Spring IoC容器也必须是一个ApplicationContext接口的实现类,那么才会调用这个接口,否则不调用
  • 如果Bean实现了BeanPostProcessorpostProcessBeforeInitialization方法,那么它就会调用这个方法。
  • 如果Bean实现了InitializingBeanafterPropertiesSet方法,那么它就会调用这个方法。
  • 如果Bean自定义了初始化方法,那么它就会调用这个方法。
  • 如果Bean实现了BeanPostProcessorpostProcessAfterInitialization方法,完成这些调用,这时候Bean就完成了初始化
  • 当服务器关闭,调用对应额方法完成Bean的销毁
  • 如果Bean实现了DisposableBeandestroy方法,那么它就会调用这个方法。
  • 如果自定义销毁对象,那么就会调用它。

下边我们来测试一下,先测试一下BeanPostProcessor接口。
我们下一个实现类BeanPostProcessorImpl

public class BeanPostProcessorImpl implements BeanPostProcessor {
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("【"+this.getClass().getSimpleName()+"】"+beanName + "开始实例化");
        return  bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("【"+this.getClass().getSimpleName()+"】"+beanName + "实例化完成");
        return  bean;
    }
}

这样一个BeanPostProcessor 就被我们用代码实现了,它会处理Spring IoC容器所有的Bean

测试生命周期

public class User implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean {

    private Long id;

    private String name;

    private Integer age;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }


    public void init(){
        System.out.println("【"+this.getClass().getSimpleName()+"】" + "执行自定义初始化方法");
    }

    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("【"+this.getClass().getSimpleName()+"】" + "setBeanFactory");
    }

    public String getUser(){
        String user = "我的名字是"+ name+"我今年" + age+"岁";
        return user;
    }

    public void setBeanName(String s) {
        System.out.println("【"+this.getClass().getSimpleName()+"】"+ "setBeanName");
    }

    public void myDestroy() throws Exception {
        System.out.println("【"+this.getClass().getSimpleName()+"】"+ "自定义销毁");
    }

    public void destroy() throws Exception {
        System.out.println("【"+this.getClass().getSimpleName()+"】"+ "destroy");
    }

    public void afterPropertiesSet() throws Exception {
        System.out.println("【"+this.getClass().getSimpleName()+"】" + "afterPropertiesSet");
    }

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("【"+this.getClass().getSimpleName()+"】"+ "setApplicationContext");
    }
}

这个类实现了所有生命周期所能实现的方法,以便于观察生命周期的过程,其中init方法是自定义初始化方法,myDestroy方法是自定义销毁方法。
我们修改配置文件spring-config.xml

<?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
  http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="beanPostProcessor" class="com.sean.spring.BeanPostProcessorImpl"/>
    <!--setter注入-->
    <bean id="user" class="com.sean.spring.User" init-method="init" destroy-method="myDestroy">
        <property name="name" value="无敌"></property>
        <property name="age" value="18"></property>
    </bean>
</beans>

写一个测试类,看一下结果

    @Test
    public void test1(){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring/spring-config.xml");
        User user = context.getBean(User.class);
        logger.debug(user.getUser());
        ((ClassPathXmlApplicationContext) context).close();
    }

打印日志:
在这里插入图片描述
在项目或者面试中,经常会碰到Spring 循环依赖问题,从源码解决Spring 循环依赖问题

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章