Spring 的简单模拟实现

发布于:2022-12-26 ⋅ 阅读:(434) ⋅ 点赞:(0)

目前进度

Spring源码学习,进行简单模拟实现,一步步搭建。
当前完成:

  1. ComponentScan 扫描指定路径包(不递归,且认为都是class文件,直接类加载方式)
  2. Scope 区分单例与多例Bean(单例Bean创建放入单例池)
  3. Autowired 依赖注入(不考虑循环依赖)
  4. BeanDefinition 只考虑了typescopelazy(未实现)
  5. InitializingBean IOC注入完成后执行afterPropertiesSet
  6. BeanPostProcessor 初始化前后执行前置后置方法
  7. Aware 普通对象依赖注入后,初始化前,注入Spring属性

目的

  1. 通过手写模拟,了解Spring的底层源码启动过程
  2. 通过手写模拟,了解BeanDefinition、BeanPostProcessor的概念
  3. 通过手写模拟,了解Spring解析配置类等底层源码工作流程
  4. 通过手写模拟,了解依赖注入,Aware回调等底层源码工作流程
  5. 通过手写模拟,了解Spring AOP的底层源码工作流程

搭建基础

  1. 创建一个 ApplicationContext 对象, 通过该对象读取一个 Config 配置类信息。
  2. 通过 ApplicationContext 对象的 getBean()方法获取 bean 对象, 并调用 bean 对象方法。
    基础框架文件目录

KunApplicationContext

package com.spring;

/**
 * @author guokun
 * @date 2022/9/5 17:03
 */
public class KunApplicationContext {
    private Class<?> configClass;

    public KunApplicationContext(Class<?> configClass) {
        this.configClass = configClass;

        // To Do: 根据Config中指定的扫描路径扫描
    }

    public Object getBean(String beanName) {
        return null;
    }
}

测试类 Test

import com.kun.config.KunAppConfig;
import com.kun.service.KunService;
import com.spring.KunApplicationContext;

/**
 * @author guokun
 * @date 2022/9/5 17:05
 */
public class Test {
    public static void main(String[] args) {
        KunApplicationContext kunApplicationContext = new KunApplicationContext(KunAppConfig.class);
        KunService kunService = (KunService) kunApplicationContext.getBean("kunService");
        kunService.test();
    }
}

ComponentScan 注解

package com.spring.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author guokun
 * @date 2022/9/5 17:17
 *
 * 运行时生效
 * 类注解
 *  扫描指定路径下得所有Component
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ComponentScan {
    String value() default "";
}

Component 注解

package com.spring.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author guokun
 * @date 2022/9/5 17:17
 * 运行时生效
 * 类注解
 *  声明为需要创建的bean类,可以指定bean的名字
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {
    String value() default "";
}

KunService 服务类(Bean类)

package com.kun.service;

import com.spring.annotation.Component;

/**
 * @author guokun
 * @date 2022/9/5 17:15
 */
@Component("kunService")
public class KunService {
    public void test() {
        System.out.println("kunService test()");
    }
}

实现包扫描

  1. 包扫描流程在前面基础框架可以知道应该在 ApplicationContext 对象创建时进行。(构造方法中调用)
public KunApplicationContext(Class<?> configClass) {
        this.configClass = configClass;

        componentScan();
    }

    private void componentScan(Class<?> configClass) {
           
    }
}
  1. 首先需要判断对应的 Config 类中有没有 ComponentScan注解,才可以扫描指定的包
  • 通过 isAnnotationPresent()查看某个类是否含有某个注解
  • 通过getAnnotation()获取某个类的某个注解对象
private void componentScan() {
        // 扫描包
        if (configClass.isAnnotationPresent(ComponentScan.class)) {
            ComponentScan componentScanAnnotation = configClass.getAnnotation(ComponentScan.class);
            // 获取包路径 xx.xx.xx
            String packagePath = componentScanAnnotation.value();
        }
}
  1. 由于JVM是读取class文件的,因此我们可以通过AppClassLoader来获取指定包的相对文件路径(注意需要将包格式转换为文件路径格式)
    private void componentScan() {
        // 扫描包
        if (configClass.isAnnotationPresent(ComponentScan.class)) {
            ComponentScan componentScanAnnotation = configClass.getAnnotation(ComponentScan.class);
            // 获取包路径 xx.xx.xx
            String packagePath = componentScanAnnotation.value();
            // 格式转换为 xx/xx/xx (因为我们要去加载的是class文件,通过文件系统去读取)
            String filePath = packagePath.replace(".", "/");
            // 获取类加载器(AppClassLoader)
            ClassLoader classLoader = KunApplicationContext.class.getClassLoader();
            // 使用AppClassLoader去获取指定包下的class文件夹路径
            URL targetClassUrl = classLoader.getResource(filePath);

        }
    }
  1. 打开对应目录文件,并加载所有的Class,然后检查是否含有Component注解
  • 在Spring中使用ASM技术扫描,无需加载类,此处直接通过将所有类加载后判断是否有Component注解实现
  • 此处先只考虑当前包,不考虑子包
  • 假设该目录下所有文件都是class文件,不去考虑其他类型文件
// 获取对应的文件目录
assert targetClassUrl != null;
File targetClassDir = new File(targetClassUrl.getFile());
// 检查是否是一个文件目录
if (targetClassDir.isDirectory()) {
    // 获取所有子文件 (先只考虑当前包,不考虑子包,假设子文件都是class文件)
    File[] classFiles = targetClassDir.listFiles();
    assert classFiles != null;
    List<Class<?>> classList = new ArrayList<>(classFiles.length);
    for (File classFile : classFiles) {
        // 获取class文件名称 xx.class
        String classFileName = classFile.getName();
        // 获取类名(去除.class)
        String className = classFileName.substring(0, classFileName.length() - 6);
        String classFullName = packagePath + "." + className;
        try {
            // 使用类加载器(AppClassLoader)加载类
            Class<?> loadClass = classLoader.loadClass(classFullName);
            // 检查是否含有Component注解
            if (loadClass.isAnnotationPresent(Component.class)) {

            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
  1. 获取beanName,如果Component注解上为空串则使用类名的小驼峰命名作为beanName
// 检查是否含有Component注解
if (loadClass.isAnnotationPresent(Component.class)) {
    // 获取beanName
    Component componentAnnotation = loadClass.getAnnotation(Component.class);
    String beanName = componentAnnotation.value();
    // 如果beanName没有设置则使用类名的小驼峰命名作为beanName
    if ("".equals(beanName)) {
        beanName = Introspector.decapitalize(loadClass.getSimpleName());
    }
}
  1. 创建注解Scope来区分单例与多例bean
package com.spring.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author guokun
 * @date 2022/9/5 19:44
 * 运行时类注解
 * value: singleton(单例) prototype(多例)
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Scope {
    String value() default "singleton";
}

区分是否单例

// 检查是否含有Component注解
if (loadClass.isAnnotationPresent(Component.class)) {
    // 获取beanName
    Component componentAnnotation = loadClass.getAnnotation(Component.class);
    String beanName = componentAnnotation.value();
    // 如果beanName没有设置则使用类名的小驼峰命名作为beanName
    if ("".equals(beanName)) {
        beanName = Introspector.decapitalize(loadClass.getSimpleName());
    }
    // 查看是否是单例bean
    if (loadClass.isAnnotationPresent(Scope.class) 
            && "prototype".equals(loadClass.getAnnotation(Scope.class).value())) {
        // 多例bean
    } else {
        // 单例bean
    }
}

创建BeanDefinition

  • BeanDefinition
package com.spring;

/**
 * @author guokun
 * @date 2022/9/5 20:06
 */
public class BeanDefinition {

    private Class<?> type;
    private String scope;
    private boolean isLazy;

    public Class<?> getType() {
        return type;
    }

    public void setType(Class<?> type) {
        this.type = type;
    }

    public String getScope() {
        return scope;
    }

    public void setScope(String scope) {
        this.scope = scope;
    }

    public boolean isLazy() {
        return isLazy;
    }

    public void setLazy(boolean lazy) {
        isLazy = lazy;
    }
}

  • ApplicationContext中使用一个HashMap来存储BeanDefinition
private HashMap<String, BeanDefinition> beanDefinitionMap = new HashMap<>();
  • 将扫描的Bean的信息封装成BeanDefinition并放入map集合中
private void componentScan() {
    // 扫描包
    if (configClass.isAnnotationPresent(ComponentScan.class)) {
        ComponentScan componentScanAnnotation = configClass.getAnnotation(ComponentScan.class);
        // 获取包路径 xx.xx.xx
        String packagePath = componentScanAnnotation.value();
        // 格式转换为 xx/xx/xx (因为我们要去加载的是class文件,通过文件系统去读取)
        String filePath = packagePath.replace(".", "/");
        // 获取类加载器(AppClassLoader)
        ClassLoader classLoader = KunApplicationContext.class.getClassLoader();
        // 使用AppClassLoader去获取指定包下的class文件夹路径
        URL targetClassUrl = classLoader.getResource(filePath);
        // 获取对应的文件目录
        assert targetClassUrl != null;
        File targetClassDir = new File(targetClassUrl.getFile());
        // 检查是否是一个文件目录
        if (targetClassDir.isDirectory()) {
            // 获取所有子文件 (先只考虑当前包,不考虑子包,假设子文件都是class文件)
            File[] classFiles = targetClassDir.listFiles();
            assert classFiles != null;
            List<Class<?>> classList = new ArrayList<>(classFiles.length);
            for (File classFile : classFiles) {
                // 获取class文件名称 xx.class
                String classFileName = classFile.getName();
                // 获取类名(去除.class)
                String className = classFileName.substring(0, classFileName.length() - 6);
                String classFullName = packagePath + "." + className;
                try {
                    // 使用类加载器(AppClassLoader)加载类
                    Class<?> loadClass = classLoader.loadClass(classFullName);
                    // 检查是否含有Component注解
                    if (loadClass.isAnnotationPresent(Component.class)) {
                        // 创建BeanDefinition
                        BeanDefinition beanDefinition = new BeanDefinition();
                        beanDefinition.setType(loadClass);

                        // 获取beanName
                        Component componentAnnotation = loadClass.getAnnotation(Component.class);
                        String beanName = componentAnnotation.value();
                        // 如果beanName没有设置则使用类名的小驼峰命名作为beanName
                        if ("".equals(beanName)) {
                            beanName = Introspector.decapitalize(loadClass.getSimpleName());
                        }

                        // 查看是否是单例bean
                        if (loadClass.isAnnotationPresent(Scope.class)
                                && "prototype".equals(loadClass.getAnnotation(Scope.class).value())) {
                            // 多例bean
                            beanDefinition.setScope("prototype");
                        } else {
                            // 单例bean
                            beanDefinition.setScope("singleton");
                        }

                        // 存储BeanDefinition到map中
                        beanDefinitionMap.put(beanName, beanDefinition);
                    }
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
  • getBean()判断是否存在对应的BeanDefinition
    public Object getBean(String beanName) {
        // 如果BeanDefinitionMap中没有对应的则说明该bean不在扫描的范围内
        if (!beanDefinitionMap.containsKey(beanName)) {
            return null;
        }

        // 有对应的BeanDefinition
        Object bean = null;
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if ("prototype".equals(beanDefinition.getScope())) {
            // 多例
        } else {
            // 单例
        }
        return bean;
    }

创建Bean

  1. 创建Bean的方法createBean(),简单通过反射使用无参构造器创建一个实例。
private Object createBean(String beanName, BeanDefinition beanDefinition) {
    Class<?> cla = beanDefinition.getType();
    Object bean = null;
    try {
        bean = cla.getDeclaredConstructor().newInstance();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    }
    return bean;
}

2 getBean()中原型(多例)Bean返回新对象

public Object getBean(String beanName) {
   // 如果BeanDefinitionMap中没有对应的则说明该bean不在扫描的范围内
   if (!beanDefinitionMap.containsKey(beanName)) {
       return null;
   }

   // 有对应的BeanDefinition
   Object bean = null;
   BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
   if ("prototype".equals(beanDefinition.getScope())) {
       // 多例
       bean = createBean(beanName, beanDefinition);
   } else {
       // 单例
   }
   return bean;
}
  1. 扫描后创建单例Bean,使用一个单例BeanHashMap进行存储
    • singletonObjects

    • 扫描后创建单例

private void createSingletonBeans() {
    for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : beanDefinitionMap.entrySet()) {
        String beanName = beanDefinitionEntry.getKey();
        BeanDefinition beanDefinition = beanDefinitionEntry.getValue();
        // 检查是否是singleton
        if ("singleton".equals(beanDefinition.getScope())) {
            Class<?> cla = beanDefinition.getType();
            Object bean = createBean(beanName, beanDefinition);
            singletonObjects.put(beanName, bean);
        }
    }
}
	构造方法中调用:
public KunApplicationContext(Class<?> configClass) {
    this.configClass = configClass;

    componentScan();

    createSingletonBeans();
}
  1. getBean()返回单例池中的单例对象

    public Object getBean(String beanName) {
        // 如果BeanDefinitionMap中没有对应的则说明该bean不在扫描的范围内
        if (!beanDefinitionMap.containsKey(beanName)) {
            return null;
        }
    
        // 有对应的BeanDefinition
        Object bean = null;
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if ("prototype".equals(beanDefinition.getScope())) {
            // 多例
            bean = createBean(beanName, beanDefinition);
        } else {
            // 单例
            bean = singletonObjects.get(beanName);
        }
        return bean;
    }
    
  2. 测试容器单例与多例bean

    创新新的服务类:GuoService

    package com.kun.service;
    
    import com.spring.annotation.Component;
    import com.spring.annotation.Scope;
    
    /**
     * @author guokun
     * @date 2022/9/5 17:15
     */
    @Component("guoService")
    @Scope("prototype")
    public class GuoService {
        public void test() {
            System.out.println("guoService test()");
        }
    }
    
    

    修改测试类:Test

    import com.kun.config.KunAppConfig;
    import com.kun.service.GuoService;
    import com.kun.service.KunService;
    import com.spring.KunApplicationContext;
    
    /**
     * @author guokun
     * @date 2022/9/5 17:05
     */
    public class Test {
        public static void main(String[] args) {
            KunApplicationContext kunApplicationContext = new KunApplicationContext(KunAppConfig.class);
            KunService kunService = (KunService) kunApplicationContext.getBean("kunService");
            KunService kunService2 = (KunService) kunApplicationContext.getBean("kunService");
            GuoService guoService = (GuoService) kunApplicationContext.getBean("guoService");
            GuoService guoService2 = (GuoService) kunApplicationContext.getBean("guoService");
            System.out.println(kunService);
            System.out.println(kunService2);
            System.out.println(guoService);
            System.out.println(guoService2);
        }
    }
    
    

    测试结果

    com.kun.service.KunService@32e6e9c3
    com.kun.service.KunService@32e6e9c3
    com.kun.service.GuoService@5056dfcb
    com.kun.service.GuoService@6574b225
    

依赖注入

  1. 创建Autowired注解

    package com.spring.annotation;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * @author guokun
     * @date 2022/9/5 21:15
     * 运行时字段注解
     *  依赖注入(当前只考虑字段属性)
     *  先通过类型再通过字段名去获取单例bean
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    public @interface Autowired {
    }
    
    
  2. 修改GuoService注入KunService

    package com.kun.service;
    
    import com.spring.annotation.Autowired;
    import com.spring.annotation.Component;
    import com.spring.annotation.Scope;
    
    /**
     * @author guokun
     * @date 2022/9/5 17:15
     */
    @Component("guoService")
    @Scope("prototype")
    public class GuoService {
        @Autowired
        private KunService kunService;
        
        public void test() {
            System.out.println("guoService test()");
        }
        public KunService getKunService() {
        	return kunService;
    	}
    }
    
    
  3. 修改createBean()方法,实现依赖注入

    private Object createBean(String beanName, BeanDefinition beanDefinition) {
        Class<?> cla = beanDefinition.getType();
        Object bean = null;
        try {
            bean = cla.getDeclaredConstructor().newInstance();
    
            // 依赖注入
            Field[] declaredFields = cla.getDeclaredFields();
            for (Field field : declaredFields) {
                if (field.isAnnotationPresent(Autowired.class)) {
                    field.setAccessible(true);
                    Class<?> type = field.getType();
                    String typeName = Introspector.decapitalize(type.getSimpleName());
                    Object iocBean = getBean(typeName);
                    if (iocBean == null) {
                        iocBean = getBean(field.getName());
                    }
                    field.set(bean, iocBean);
                }
            }
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return bean;
    }
    
  4. 此时在依赖注入时,需要注入的bean可能还未创建,则需要进行创建,修改getBean()

    public Object getBean(String beanName) {
        // 如果BeanDefinitionMap中没有对应的则说明该bean不在扫描的范围内
        if (!beanDefinitionMap.containsKey(beanName)) {
            return null;
        }
    
        // 有对应的BeanDefinition
        Object bean = null;
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if ("prototype".equals(beanDefinition.getScope())) {
            // 多例
            bean = createBean(beanName, beanDefinition);
        } else {
            // 单例
            bean = singletonObjects.get(beanName);
            
            // 考虑还未创建的单例bean被获取时,提前创建(可能出现循环依赖)
            if (bean == null) {
                bean = createBean(beanName, beanDefinition);
                singletonObjects.put(beanName, bean);
            }
        }
    
        return bean;
    }
    
  5. 测试

    • 创建测试类 IocTest1

      import com.kun.config.KunAppConfig;
      import com.kun.service.GuoService;
      import com.kun.service.KunService;
      import com.spring.KunApplicationContext;
      
      /**
       * @author guokun
       * @date 2022/9/5 21:37
       */
      public class IocTest1 {
          public static void main(String[] args) {
              KunApplicationContext kunApplicationContext = new KunApplicationContext(KunAppConfig.class);
              GuoService guoService = (GuoService) kunApplicationContext.getBean("guoService");
              System.out.println(guoService.getKunService());
          }
      }
      
      
    • 运行结果

      com.kun.service.KunService@1efbd816
      

注意,此时并未处理循环依赖问题

InitializingBean

  1. 创建InitializingBean接口

    package com.spring;
    
    /**
     * @author guokun
     * @date 2022/9/5 21:43
     */
    public interface InitializingBean {
        /**
         * 创建Bean实例后,初始化前调用该方法
         */
        void afterPropertiesSet();
    }
    
    
  2. createBean()的依赖注入完成之后执行InitializingBean接口的afterPropertiesSet()方法

    // 执行InitializingBean的afterPropertiesSet方法
    if (bean instanceof InitializingBean) {
        ((InitializingBean) bean).afterPropertiesSet();
    }
    
  3. KunService中实现InitializingBean接口

    package com.kun.service;
    
    import com.spring.InitializingBean;
    import com.spring.annotation.Component;
    
    /**
     * @author guokun
     * @date 2022/9/5 17:15
     */
    @Component("kunService")
    public class KunService implements InitializingBean {
        public void test() {
            System.out.println("kunService test()");
        }
    
        @Override
        public void afterPropertiesSet() {
            System.out.println(this + ":" + "afterPropertiesSet");
        }
    }
    
    
  4. 测试

    • 测试类 InitializingBeanTest
      import com.kun.config.KunAppConfig;
      import com.kun.service.KunService;
      import com.spring.KunApplicationContext;
      
      /**
       * @author guokun
       * @date 2022/9/5 21:37
       */
      public class InitializingBeanTest {
          public static void main(String[] args) {
              KunApplicationContext kunApplicationContext = new KunApplicationContext(KunAppConfig.class);
              KunService kunService = (KunService) kunApplicationContext.getBean("kunService");
          }
      }
      
      
    • 测试结果
      com.kun.service.KunService@402f32ff:afterPropertiesSet
      

BeanPostProcessor

  1. 创建BeanPostProcessor接口

    package com.spring;
    
    
    /**
     * @author guokun
     * @date 2022/9/5 21:53
     */
    public interface BeanPostProcessor {
    
        /**
         * bean初始化前置处理
         * @param bean
         * @param beanName
         * @return
         */
        default Object postProcessorBeforeInitialization(Object bean, String beanName) {
            return bean;
        }
    
        /**
         * bean初始化后置处理
         * @param bean
         * @param beanName
         * @return
         */
        default Object postProcessorAfterInitialization(Object bean, String beanName) {
            return bean;
        }
    
    }
    
    
  2. ApplicationContext中创建一个List集合存储所有的beanPostProcessorbean对象

    private List<BeanPostProcessor> beanPostProcessorList = new LinkedList<>();
    
  3. 扫描包时将实现了BeanPostProcesso接口的类实例化一个对象放入集合中

    cla.isAssignableFrom(interface.cla)查看某个类是否实现了某个接口

    // 判断是否实现了BeanPostProcessor,如果实现了则放入beanPostProcessorList中
    if (BeanPostProcessor.class.isAssignableFrom(loadClass)) {
        BeanPostProcessor beanPostProcessor = (BeanPostProcessor) loadClass.getDeclaredConstructor().newInstance();
        beanPostProcessorList.add(beanPostProcessor);
    }
    
  4. createBean()的依赖注入后分别执行BeanPostProcessorbeforeafter方法

    // 执行所有BeanPostProcessor的before
    for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
        beanPostProcessor.postProcessorBeforeInitialization(bean, beanName);
    }
    
    // 初始化 To Do
    
    // 执行所有BeanPostProcessor的after
    for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
        beanPostProcessor.postProcessorAfterInitialization(bean, beanName);
    }
    
  5. 创建类KunPostProcessorService实现BeanPostProcessor

    package com.kun.service;
    
    import com.spring.BeanPostProcessor;
    import com.spring.annotation.Component;
    
    /**
     * @author guokun
     * @date 2022/9/5 22:46
     */
    @Component
    public class KunPostProcessorService implements BeanPostProcessor {
        @Override
        public Object postProcessorBeforeInitialization(Object bean, String beanName) {
            System.out.println(this + ":" + "postProcessorBeforeInitialization");
            return bean;
        }
    
        @Override
        public Object postProcessorAfterInitialization(Object bean, String beanName) {
            System.out.println(this + ":" + "postProcessorAfterInitialization");
            return bean;
        }
    }
    
    
  6. 测试

    import com.kun.config.KunAppConfig;
    import com.kun.service.KunService;
    import com.spring.KunApplicationContext;
    
    /**
     * @author guokun
     * @date 2022/9/5 21:37
     */
    public class BeanPostProcessorTest {
        public static void main(String[] args) {
            KunApplicationContext kunApplicationContext = new KunApplicationContext(KunAppConfig.class);
        }
    }
    
    

    测试结果

    com.kun.service.KunPostProcessorService@6d78f375:postProcessorBeforeInitialization
    com.kun.service.KunPostProcessorService@6d78f375:postProcessorAfterInitialization
    com.kun.service.KunService@1810399e:afterPropertiesSet
    com.kun.service.KunPostProcessorService@6d78f375:postProcessorBeforeInitialization
    com.kun.service.KunPostProcessorService@6d78f375:postProcessorAfterInitialization
    

Aware

有时我们创建的Bean可能需要注入一些Spring中的对象,此时就可以通过Aware来实现注入。

原理是Aware会给对应对象设置一个set方法来让程序员在实现类中实现设置,然后Spring会在 IOC执行完成普通对象的注入后 执行Aware的方法来将Spring的对象注入到Bean中。

BeanNameAware

用于获取BeanBeanName

  1. Aware,BeanNameAware接口

    Aware

    package com.spring;
    
    /**
     * @author guokun
     * @date 2022/9/6 22:38
     */
    public interface Aware {
    }
    
    

    BeanNameAware

    package com.spring;
    
    /**
     * @author guokun
     * @date 2022/9/6 22:32
     */
    public interface BeanNameAware extends Aware {
        /**
         * 设置Bean的BeanName属性
         */
        void setBeanName();
    }
    
    
  2. createBean()IOC普通对象注入后执行Aware的方法
    需要判断是否是Aware的实例,然后一一判断是否为其他Aware子类的实例并执行其注入方法

    // Aware注入Spring对象属性
    if (bean instanceof Aware) {
        if (bean instanceof BeanNameAware) {
            ((BeanNameAware) bean).setBeanName(beanName);
        }
    }
    
  3. KunServer实现BeanNameAware接口

    package com.kun.service;
    
    import com.spring.BeanNameAware;
    import com.spring.InitializingBean;
    import com.spring.annotation.Component;
    
    /**
     * @author guokun
     * @date 2022/9/5 17:15
     */
    @Component("kunService")
    public class KunService implements InitializingBean, BeanNameAware {
        private String beanName;
        
        public void test() {
            System.out.println("kunService test()");
        }
    
        @Override
        public void afterPropertiesSet() {
            System.out.println(this + ":" + "afterPropertiesSet");
        }
    
        public String getBeanName() {
            return beanName;
        }
    
        @Override
        public void setBeanName(String name) {
            this.beanName = name;
        }
    }
    
    
  4. 测试

    import com.kun.config.KunAppConfig;
    import com.kun.service.KunService;
    import com.spring.KunApplicationContext;
    
    /**
     * @author guokun
     * @date 2022/9/6 22:46
     */
    public class BeanNameAwareTest {
        public static void main(String[] args) {
            KunApplicationContext context = new KunApplicationContext(KunAppConfig.class);
            KunService kunService = (KunService) context.getBean("kunService");
            System.out.println("beanName:\t" + kunService.getBeanName());
        }
    }
    
    
    com.kun.service.KunPostProcessorService@6d78f375:postProcessorBeforeInitialization
    com.kun.service.KunPostProcessorService@6d78f375:postProcessorAfterInitialization
    com.kun.service.KunService@4439f31e:afterPropertiesSet
    com.kun.service.KunPostProcessorService@6d78f375:postProcessorBeforeInitialization
    com.kun.service.KunPostProcessorService@6d78f375:postProcessorAfterInitialization
    beanName:	kunService
    

网站公告

今日签到

点亮在社区的每一天
去签到