Mr. Cappuccino的第62杯咖啡——Spring之Bean的生命周期

Spring之Bean的生命周期

    • Aware接口
      • 项目结构
      • 项目代码
      • 运行结果
      • 源代码
      • 使用场景
    • InitializingBean接口
      • 项目结构
      • 项目代码
      • 运行结果
      • 源代码
    • BeanFactoryPostProcessor接口
      • 项目结构
      • 项目代码
      • 运行结果
      • 源代码
    • Bean的生命周期
      • 项目结构
      • 项目代码
      • 运行结果
      • 源代码

Aware接口

实现Aware接口是为了bean能获取某些信息、感知某些信息。Aware自身是一个空的接口,Spring提供了很多它的实现接口,开发者实现这些已有的接口就能获取特定的一些信息。

Spring提供了一些Aware接口的实现接口:
ApplicationContextAware、ApplicationEventPublisherAware、BeanClassLoaderAware、BeanFactoryAware、BeanNameAware、EmbeddedValueResolverAware、EnvironmentAware、ImportAware、LoadTimeWeaverAware、MessageSourceAware、NotificationPublisherAware、ResourceLoaderAware

项目结构

Mr. Cappuccino的第62杯咖啡——Spring之Bean的生命周期_第1张图片

项目代码

pom.xml


<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0modelVersion>

    <groupId>comgroupId>
    <artifactId>spring-bean-life-cycleartifactId>
    <version>1.0-SNAPSHOTversion>

    <properties>
        <maven.compiler.source>8maven.compiler.source>
        <maven.compiler.target>8maven.compiler.target>
    properties>

    <dependencies>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-coreartifactId>
            <version>5.2.1.RELEASEversion>
        dependency>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-beansartifactId>
            <version>5.2.1.RELEASEversion>
        dependency>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-contextartifactId>
            <version>5.2.1.RELEASEversion>
        dependency>
    dependencies>

project>

AwareBean.java

package com.spring.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

/**
 * @author honey
 * @date 2023-08-13 16:08:02
 */
public class AwareBean implements BeanNameAware, BeanClassLoaderAware, ApplicationContextAware {

    private String beanName;
    private ClassLoader classLoader;
    private ApplicationContext applicationContext;

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }

    @Override
    public void setBeanName(String beanName) {
        this.beanName = beanName;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    public String getBeanName() {
        return beanName;
    }

    public ClassLoader getClassLoader() {
        return classLoader;
    }

    public ApplicationContext getApplicationContext() {
        return applicationContext;
    }
}

SpringTest01.java

package com.spring.test;

import com.spring.bean.AwareBean;
import org.springframework.context.support.GenericApplicationContext;

/**
 * @author honey
 * @date 2023-08-13 16:43:37
 */
public class SpringTest01 {

    public static void main(String[] args) {
        GenericApplicationContext applicationContext = new GenericApplicationContext();
        applicationContext.registerBean("awareBean", AwareBean.class);
        applicationContext.refresh();
        AwareBean awareBean = applicationContext.getBean("awareBean", AwareBean.class);
        System.out.println("beanName:" + awareBean.getBeanName());
        System.out.println("classLoader:" + awareBean.getClassLoader());
        System.out.println("applicationContext:" + awareBean.getApplicationContext());
        applicationContext.close();
    }
}

运行结果

Mr. Cappuccino的第62杯咖啡——Spring之Bean的生命周期_第2张图片

源代码


使用invokeAwareMethods方法处理部分Aware实现接口

AbstractApplicationContext.java

Mr. Cappuccino的第62杯咖啡——Spring之Bean的生命周期_第3张图片

DefaultListableBeanFactory.java

AbstractBeanFactory.java

在这里插入图片描述

AbstractAutowireCapableBeanFactory.java


Mr. Cappuccino的第62杯咖啡——Spring之Bean的生命周期_第4张图片
Mr. Cappuccino的第62杯咖啡——Spring之Bean的生命周期_第5张图片
Mr. Cappuccino的第62杯咖啡——Spring之Bean的生命周期_第6张图片


使用Bean对象后置处理器(ApplicationContextAwareProcessor)处理部分Aware实现接口

AbstractApplicationContext.java

Mr. Cappuccino的第62杯咖啡——Spring之Bean的生命周期_第7张图片

Mr. Cappuccino的第62杯咖啡——Spring之Bean的生命周期_第8张图片

Mr. Cappuccino的第62杯咖啡——Spring之Bean的生命周期_第9张图片

从AbstractApplicationContext类的finishBeanFactoryInitialization方法一直进入到AbstractAutowireCapableBeanFactory类的initializeBean方法,具体跳转步骤此处省略,可参照上面的跳转步骤

AbstractAutowireCapableBeanFactory.java

Mr. Cappuccino的第62杯咖啡——Spring之Bean的生命周期_第10张图片

Mr. Cappuccino的第62杯咖啡——Spring之Bean的生命周期_第11张图片

Mr. Cappuccino的第62杯咖啡——Spring之Bean的生命周期_第12张图片

ApplicationContextAwareProcessor.java

Mr. Cappuccino的第62杯咖啡——Spring之Bean的生命周期_第13张图片

Mr. Cappuccino的第62杯咖啡——Spring之Bean的生命周期_第14张图片


使用场景

SpringContextUtils.java

package com.bubble.core.util;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.stereotype.Component;

/**
 * Spring上下文工具类
 *
 * @author honey
 * @date 2021-09-21 18:27:54
 */
@Component
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class SpringContextUtils implements ApplicationContextAware {

    private static ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;
    }

    public static ApplicationContext getApplicationContext() {
        return context;
    }

    public static <T> T getBean(String s, Class<T> clazz) {
        return context.getBean(s, clazz);
    }

    public static Boolean containsBean(String s) {
        return context.containsBean(s);
    }

    public static Boolean containsBean(Class<?> clazz) {
        String first = clazz.getSimpleName().substring(0, 1).toLowerCase();
        String after = clazz.getSimpleName().substring(1);
        return context.containsBean(first + after);
    }

    public static <T> T getBean(Class<T> clazz) {
        return context.getBean(clazz);
    }

    public static void publishEvent(ApplicationEvent event) {
        context.publishEvent(event);
    }
}

InitializingBean接口

InitializingBean接口为bean对象提供了初始化方法,它只包括afterPropertiesSet方法,凡是继承该接口的类,在初始化bean的时候都会执行该方法。

Spring为bean对象提供了三种初始化方式:
1.在bean对象中实现InitializingBean接口;
2.使用@Bean注解注入bean对象时指定initMethod属性;
3.在bean对象的方法上使用@PostConstruct注解;

实现InitializingBean接口是直接调用afterPropertiesSet方法,比通过反射调用init-method指定的方法效率要高一点,但是init-method方式消除了对spring的依赖。如果调用afterPropertiesSet方法时出错,则不调用init-method指定的方法。

@PostConstruct通过Bean对象后置处理器(CommonAnnotationBeanPostProcessor)实现,InitializingBean和@Bean通过IOC工厂(BeanFactory)实现。

项目结构

Mr. Cappuccino的第62杯咖啡——Spring之Bean的生命周期_第15张图片

项目代码

InitBean.java

package com.spring.bean;

import org.springframework.beans.factory.InitializingBean;

import javax.annotation.PostConstruct;

/**
 * @author honey
 * @date 2023-08-13 18:41:58
 */
public class InitBean implements InitializingBean {

    @Override
    public void afterPropertiesSet() {
        System.out.println("InitBean 调用afterPropertiesSet()");
    }

    @PostConstruct
    public void init(){
        System.out.println("InitBean 调用init()");
    }

    public void initMethod(){
        System.out.println("InitBean 调用initMethod()");
    }
}

SpringConfig.java

package com.spring.config;

import com.spring.bean.InitBean;
import org.springframework.context.annotation.Bean;

/**
 * @author honey
 * @date 2023-08-13 18:52:09
 */
public class SpringConfig {

    @Bean(initMethod = "initMethod")
    public InitBean initBean() {
        return new InitBean();
    }
}

SpringTest02.java

package com.spring.test;

import com.spring.bean.InitBean;
import com.spring.config.SpringConfig;
import org.springframework.context.annotation.CommonAnnotationBeanPostProcessor;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;

/**
 * @author honey
 * @date 2023-08-13 18:48:22
 */
public class SpringTest02 {

    public static void main(String[] args) {
        GenericApplicationContext applicationContext = new GenericApplicationContext();
        applicationContext.registerBean("springConfig", SpringConfig.class);
        applicationContext.registerBean(CommonAnnotationBeanPostProcessor.class);
        applicationContext.registerBean(ConfigurationClassPostProcessor.class);
        applicationContext.refresh();
        InitBean initBean = applicationContext.getBean("initBean", InitBean.class);
        System.out.println("InitBean " + initBean);
        applicationContext.close();
    }
}

运行结果

Mr. Cappuccino的第62杯咖啡——Spring之Bean的生命周期_第16张图片

源代码


@PostConstruct通过Bean对象后置处理器(CommonAnnotationBeanPostProcessor)实现,底层使用反射技术。

AbstractAutowireCapableBeanFactory.java

Mr. Cappuccino的第62杯咖啡——Spring之Bean的生命周期_第17张图片

CommonAnnotationBeanPostProcessor.java

Mr. Cappuccino的第62杯咖啡——Spring之Bean的生命周期_第18张图片

InitDestroyAnnotationBeanPostProcessor.java

Mr. Cappuccino的第62杯咖啡——Spring之Bean的生命周期_第19张图片

Mr. Cappuccino的第62杯咖啡——Spring之Bean的生命周期_第20张图片

在这里插入图片描述


InitializingBean通过IOC工厂(BeanFactory)实现,底层没有使用反射技术。

AbstractAutowireCapableBeanFactory.java

Mr. Cappuccino的第62杯咖啡——Spring之Bean的生命周期_第21张图片

Mr. Cappuccino的第62杯咖啡——Spring之Bean的生命周期_第22张图片


@Bean通过IOC工厂(BeanFactory)实现,底层使用反射技术。

AbstractAutowireCapableBeanFactory.java


BeanFactoryPostProcessor接口

实现BeanFactoryPostProcessor接口,可以在Spring的bean创建之前,修改bean的定义属性。也就是说,Spring允许BeanFactoryPostProcessor在容器实例化任何其它bean之前读取配置元数据,并可以根据需要进行修改,例如可以把bean的scope从singleton改为prototype,也可以把property的值给修改掉。可以同时配置多个BeanFactoryPostProcessor,并通过设置’order’属性来控制各个BeanFactoryPostProcessor的执行次序。
注意:BeanFactoryPostProcessor是在Spring容器加载了bean的定义文件之后,在bean实例化之前执行的。接口方法的入参是ConfigurrableListableBeanFactory。

ConfigurationClassPostProcessor:主要用于处理配置类,使@Bean、@Import、@ComponentScan等注解生效。

项目结构

Mr. Cappuccino的第62杯咖啡——Spring之Bean的生命周期_第23张图片

项目代码

UserBean.java

package com.spring.bean;

/**
 * @author honey
 * @date 2023-08-14 01:02:08
 */
public class UserBean {

    private String name = "Faker";

    public String getName() {
        return name;
    }

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

MyBeanFactoryPostProcessor.java

package com.spring.processor;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

/**
 * @author honey
 * @date 2023-08-14 01:00:25
 */
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 修改bean对象的属性值
        BeanDefinition userBean = beanFactory.getBeanDefinition("userBean");
        userBean.getPropertyValues().addPropertyValue("name", "Honey");
    }
}

SpringTest03.java

package com.spring.test;

import com.spring.bean.UserBean;
import com.spring.processor.MyBeanFactoryPostProcessor;
import org.springframework.context.support.GenericApplicationContext;

/**
 * @author honey
 * @date 2023-08-14 01:04:16
 */
public class SpringTest03 {

    public static void main(String[] args) {
        GenericApplicationContext applicationContext = new GenericApplicationContext();
        applicationContext.registerBean("userBean", UserBean.class);
        applicationContext.registerBean(MyBeanFactoryPostProcessor.class);
        applicationContext.refresh();
        UserBean userBean = applicationContext.getBean("userBean", UserBean.class);
        System.out.println("userBean name:" + userBean.getName());
        applicationContext.close();
    }
}

运行结果

Mr. Cappuccino的第62杯咖啡——Spring之Bean的生命周期_第24张图片

源代码


调用BeanFactoryPostProcessor接口的postProcessBeanFactory方法

AbstractApplicationContext.java

Mr. Cappuccino的第62杯咖啡——Spring之Bean的生命周期_第25张图片

Mr. Cappuccino的第62杯咖啡——Spring之Bean的生命周期_第26张图片

PostProcessorRegistrationDelegate.java


Mr. Cappuccino的第62杯咖啡——Spring之Bean的生命周期_第27张图片
Mr. Cappuccino的第62杯咖啡——Spring之Bean的生命周期_第28张图片


修改bean对象的属性值

AbstractApplicationContext.java

Mr. Cappuccino的第62杯咖啡——Spring之Bean的生命周期_第29张图片

具体跳转步骤此处省略

AbstractAutowireCapableBeanFactory.java


Mr. Cappuccino的第62杯咖啡——Spring之Bean的生命周期_第30张图片
Mr. Cappuccino的第62杯咖啡——Spring之Bean的生命周期_第31张图片


Bean的生命周期

Spring bean的生命周期主要包含四个阶段:实例化 Instantiation --> 属性赋值 Populate --> 初始化 Initialization --> 销毁 Destruction

Spring bean的生命周期核心代码:AbstractBeanFactory#getBean()

  1. 实例化Bean对象,执行构造方法;
  2. 属性赋值,对Bean对象中的属性进行赋值,如在Bean对象中使用@Autowired注解实现依赖注入以及通过BeanFactoryPostProcessor修改Bean对象中的属性值;
  3. 初始化阶段,执行Bean对象中Aware相关接口的实现方法;
  4. 初始化阶段,执行BeanPostProcessor#postProcessBeforeInitialization(),在初始化方法之前执行;
  5. 初始化阶段,执行初始化方法;
  6. 初始化阶段,执行BeanPostProcessor#postProcessAfterInitialization(),在初始化方法之后执行;
  7. 销毁Bean对象;
  1. 实例化Bean对象,当客户向容器请求一个尚未初始化的Bean对象时,或初始化Bean对象的时候需要注入另一个尚末初始化的依赖时,容器就会调用doCreateBean()方法进行实例化,实际上就是通过反射的方式创建出一个bean对象;
  2. Bean对象的实例创建完成后,接着就是给这个Bean对象进行属性填充,也就是注入这个Bean依赖的其它Bean对象;
  3. 属性填充完成后,初始化Bean对象,初始化阶段又可以分为几个步骤:
    3.1. 执行Bean对象中Aware相关接口的实现方法;
    3.2. Spring会检测Bean对象是否实现了xxxAware接口,通过Aware类型的接口,可以让我们拿到Spring容器的某些资源。如实现BeanNameAware接口可以获取到BeanName,实现BeanFactoryAware接口可以获取到BeanFactory等等;
    3.3. 执行BeanPostProcessor的前置处理方法postProcessBeforeInitialization(),对Bean进行一些自定义的前置处理;
    3.4. 判断Bean是否实现了InitializingBean接口,如果实现了则会执行InitializingBean的afterPropertiesSet()进行初始化;
    3.5. 执行用户自定义的初始化方法,如init-method等;
    3.6. 执行BeanPostProcessor的后置处理方法postProcessAfterInitialization() ,对Bean进行一些自定义的后置处理;
  4. 初始化完成后,Bean对象就成功创建了,之后就可以使用这个Bean对象, 当Bean对象不再需要时,则会进行销毁操作;
    4.1. 首先判断Bean对象是否实现了DestructionAwareBeanPostProcessor接口,如果实现了则会执行DestructionAwareBeanPostProcessor后置处理器的销毁回调方法;
    4.2. 其次会判断Bean对象是否实现了DisposableBean接口,如果实现了将会调用其实现的destroy()方法;
    4.3. 最后判断这个Bean是否配置了dlestroy-method等自定义的销毁方法,如果是则会自动调用其配置的销毁方法;

项目结构

Mr. Cappuccino的第62杯咖啡——Spring之Bean的生命周期_第32张图片

项目代码

AutowireBean.java

package com.spring.bean;

/**
 * @author honey
 * @date 2023-08-14 01:48:12
 */
public class AutowireBean {
}

LifeCycleBean.java

package com.spring.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

/**
 * @author honey
 * @date 2023-08-14 01:47:44
 */
public class LifeCycleBean implements BeanNameAware, BeanClassLoaderAware, ApplicationContextAware, InitializingBean, DisposableBean {

    private String name;

    public LifeCycleBean() {
        System.out.println("1.执行无参构造方法");
        System.out.println("LifeCycleBean 执行LifeCycleBean()");
    }

    @Autowired
    public void setAutowireBean(AutowireBean autowireBean) {
        System.out.println("2.设置对象属性");
        System.out.println("LifeCycleBean 执行setAutowireBean() autowireBean = " + autowireBean);
    }

    public void setName(String name) {
        System.out.println("2.设置对象属性");
        System.out.println("LifeCycleBean 执行setName() name = " + name);
        this.name = name;
    }

    @Override
    public void setBeanName(String name) {
        System.out.println("3.执行Aware接口中的方法");
        System.out.println("LifeCycleBean 执行setBeanName()");
    }

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        System.out.println("3.执行Aware接口中的方法");
        System.out.println("LifeCycleBean 执行setBeanClassLoader()");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("3.执行Aware接口中的方法");
        System.out.println("LifeCycleBean 执行setApplicationContext()");
    }

    @Override
    public void afterPropertiesSet() {
        System.out.println("5.执行初始化方法");
        System.out.println("LifeCycleBean 执行afterPropertiesSet()");
    }

    @PostConstruct
    public void postConstruct() {
        System.out.println("5.执行初始化方法");
        System.out.println("LifeCycleBean 执行postConstruct()");
    }

    public void initMethod() {
        System.out.println("5.执行初始化方法");
        System.out.println("LifeCycleBean 执行initMethod()");
    }

    @Override
    public void destroy() {
        System.out.println("7.执行销毁方法");
        System.out.println("LifeCycleBean 执行destroy()");
    }

    @PreDestroy
    public void preDestroy() {
        System.out.println("7.执行销毁方法");
        System.out.println("LifeCycleBean 执行preDestroy()");
    }

    public String getName() {
        return name;
    }
}

LifeCycBeanFactoryPostProcessor.java

package com.spring.processor;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

/**
 * @author honey
 * @date 2023-08-14 02:13:45
 */
public class LifeCycBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 修改bean对象的属性值
        BeanDefinition userBean = beanFactory.getBeanDefinition("lifeCycleBean");
        userBean.getPropertyValues().addPropertyValue("name", "Honey");
    }
}

LifeCycleBeanPostProcessor.java

package com.spring.processor;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

/**
 * @author honey
 * @date 2023-08-14 02:01:57
 */
public class LifeCycleBeanPostProcessor implements BeanPostProcessor {

    private final String beanName = "lifeCycleBean";

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (this.beanName.equals(beanName)) {
            System.out.println("4.bean对象后置处理器初始化方法之前执行");
            System.out.println("LifeCycleBean 执行postProcessBeforeInitialization()");
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (this.beanName.equals(beanName)) {
            System.out.println("6.bean对象后置处理器初始化方法之后执行");
            System.out.println("LifeCycleBean 执行postProcessAfterInitialization()");
        }
        return bean;
    }
}

SpringConfig02.java

package com.spring.config;

import com.spring.bean.AutowireBean;
import com.spring.bean.LifeCycleBean;
import com.spring.processor.LifeCycBeanFactoryPostProcessor;
import com.spring.processor.LifeCycleBeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;

/**
 * @author honey
 * @date 2023-08-14 02:17:17
 */
@Import({LifeCycBeanFactoryPostProcessor.class, LifeCycleBeanPostProcessor.class})
public class SpringConfig02 {

    @Bean(initMethod = "initMethod")
    public LifeCycleBean lifeCycleBean() {
        return new LifeCycleBean();
    }

    @Bean
    public AutowireBean autowireBean() {
        return new AutowireBean();
    }
}

SpringTest04.java

package com.spring.test;

import com.spring.bean.LifeCycleBean;
import com.spring.config.SpringConfig02;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @author honey
 * @date 2023-08-14 02:15:22
 */
public class SpringTest04 {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig02.class);
        LifeCycleBean lifeCycleBean = applicationContext.getBean("lifeCycleBean", LifeCycleBean.class);
        System.out.println("-----------------------------------");
        System.out.println("LifeCycleBean " + lifeCycleBean);
        System.out.println("-----------------------------------");
        applicationContext.close();
    }
}

运行结果

Mr. Cappuccino的第62杯咖啡——Spring之Bean的生命周期_第33张图片

源代码

AbstractBeanFactory.java

Mr. Cappuccino的第62杯咖啡——Spring之Bean的生命周期_第34张图片
Mr. Cappuccino的第62杯咖啡——Spring之Bean的生命周期_第35张图片

AbstractAutowireCapableBeanFactory.java



你可能感兴趣的:(Spring,mr,spring,java)