• 【Spring(七)】带你手写一个Spring容器


    有关Spring的所有文章都收录于我的专栏:👉Spring👈
    目录
    前置准备
    第一步、创建我们自定的注解
    第二步、创建我们自己的容器类
    测试
    总结


    相关文章

    【Spring(一)】如何获取对象(Bean)【Spring(一)】如何获取对象(Bean)
    【Spring(二)】java对象属性的配置(Bean的配置)【Spring(二)】java对象属性的配置(Bean的配置)
    【Spring(三)】熟练掌握Spring的使用【Spring(三)】熟练掌握Spring的使用
    【Spring(四)】Spring基于注解的配置方式【Spring(四)】Spring基于注解的配置方式
    【Spring(五)】引入篇:AOP的底层原理之动态代理【Spring(五)】引入篇:AOP的底层原理之动态代理
    【Spring(六)】使用篇:AOP在开发中的使用 【Spring(六)】使用篇:AOP在开发中的使用

    前置准备

    在此之前我们先的了解原生Spring容器中有什么,以及它们的功能都是什么,我们才能有目的实现它。我们先在Spring容器中注入一个Bean。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    第一步、创建我们自定的注解

    @ComponentScan

    这个注解用于标注配置类。我们手写的Spring容器使用的都是基于注解的方式。这个配置类就相当于我们的XML配置文件中配置扫描的包的路径。

    package com.jl.spring.annotation;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * @author long
     * @date 2022/9/4
     * @Target 指定我们的Component注解可以修饰Type程序元素
     */
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ComponentScan {
        String value() default "";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    @Component

    此注解用于标注Bean对象。我们这里只写一个@Component`,其他例如:@Service这些都是相同的原理。

    package com.jl.spring.annotation;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Component {
        // 可以通过此注解指定bean的id值
        String value() default "";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    @Scope

    此注解用于声明Bean为单例还是多例。

    package com.jl.spring.annotation;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * 可以指定bean的作用范围
     * singleton,prototype
     */
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Scope {
        String value() default "";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    @Autowired

    用于自动装配的注解。

    package com.jl.spring.annotation;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target({ElementType.METHOD,ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Autowired {
        // 可以通过此注解指定bean的id值
    //    String value() default "";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    @Aspect

    用于标注切面类的注解。

    package com.jl.spring.annotation;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Aspect {
        String value() default "";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    @Before

    前置通知的注解。

    package com.jl.spring.annotation;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target({ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Before {
        String value();
        String argNames() default "";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    @AfterReturning

    返回通知的注解。

    package com.jl.spring.annotation;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target({ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface AfterReturning {
        String value() default "";
        String pointcut() default "";
        String returning() default "";
        String argNames() default "";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    @After

    后置通知的注解。

    package com.jl.spring.annotation;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target({ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface After {
        String value();
        String argNames() default "";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    第二步、创建我们自己的容器类

    在【一】中我们可以看到原生Spring容器中有几个很重要的属性:

    1. beanDefinitionMap :用于存放Bean的配置信息。
    2. singletonObjects:存放创建好的Bean实例。
    3. beanPostProcessorList:我们这里再添加到一个存放后置处理器的数组。
    private Class configClass;
    // 定义属性BeanDefinitionMap->存放BeanDefinition对象
    private ConcurrentHashMap<String,BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
    // 定义属性SingletonObjects->存放单例对象
    private ConcurrentHashMap<String,Object> singletonObjects= new ConcurrentHashMap<>();
    // 定义属性,存放我们的后置处理器
    private List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    扫描类

    // 该方法完成对指定包的扫描,并将Bean信息封装到BeanDefinition对象,再放入Map中
    public void beanDefinitionByScan(Class configClass){
       this.configClass = configClass;
       //1. 获取要扫描的包
       ComponentScan componentScan =
               (ComponentScan)this.configClass.getDeclaredAnnotation(ComponentScan.class);
       //2. 通过ComponentScan的value =》即要扫描的包
       String path = componentScan.value();
    
       //得到要扫描包下的所有资源(.class)
       //1) 得到类的加载器
       ClassLoader classLoader = JlSpringApplicationContext.class.getClassLoader();
       //2) 通过类的加载器获取到要扫描的包的资源url
       path = path.replace(".","/");
       URL resource = classLoader.getResource(path);
       //3) 将要加载的资源(.class)路径下的文件进行遍历=》io
       File file = new File(resource.getFile());
       if (file.isDirectory()){
           File[] files = file.listFiles();
           for (File f : files) {
               //class文件的绝对路径
               String fileAbsolutePath = f.getAbsolutePath();
               // 这里我们进行过滤,只处理.class文件
               if (fileAbsolutePath.endsWith(".class")) {
                   //1. 获取到类名
                   String className = fileAbsolutePath.substring(fileAbsolutePath.lastIndexOf("\\") + 1, fileAbsolutePath.indexOf(".class"));
                   //2. 获取类的全路径
                   String classFullName = path.replace("/", ".") + "." + className;
                   //3. 判断该.class文件是不是需要注入到容器中;看该类是不是有注解@Component @Service
                   try {
                       //这是我们就得到了该类的Class对象
                       // 这里也可以通过class.forName得到一个Class对象
                       // 区别是:class.forName()会调用类的静态方法,classLoader.loadClass()不会
                       Class<?> clazz = classLoader.loadClass(classFullName);
                       //aClass.isAnnotationPresent(Component.class) 判断该类是否有@Component注解
                       if (clazz.isAnnotationPresent(Component.class)){
                           System.out.println("这是一个SpringBean=" + clazz + " 类名=" + className);
    
                           // 为了方便,我们将后置处理器放入集合中(真实的还是在走createBean和getBean这些逻辑,这里是简化的)
                           // 如果是一个后置处理器就放入集合中
                           // 这里我们不能通过instanceof来判断是否实现了BeanPostProcessor
                           // 原因:这个的clazz是一个类对象,不是一个实例对象
                           if (BeanPostProcessor.class.isAssignableFrom(clazz)){
                               BeanPostProcessor beanPostProcessor = (BeanPostProcessor)clazz.newInstance();
                               beanPostProcessorList.add(beanPostProcessor);
                               continue;
                           }
                           //先得到beanName
                           // 1. 得到component注解
                           Component declaredAnnotation = clazz.getDeclaredAnnotation(Component.class);
                           // 2. 得到value值(1.配置了value 2.没有配置value)
                           String beanName = declaredAnnotation.value();
                           if ("".equals(beanName)){ // 如果没有写value
                               // 将该类的类名首字母小写作为beanName
                               beanName = StringUtils.uncapitalize(className);
                           }
                           // 3. 将bean的信息封装到BeanDefinition对象
                           BeanDefinition beanDefinition = new BeanDefinition();
                           beanDefinition.setClazz(clazz);
                           // 4. 获取scope的值
                           if(clazz.isAnnotationPresent(Scope.class)){// 如果有scope值
                               Scope scopeAnnotation = clazz.getDeclaredAnnotation(Scope.class);
                               beanDefinition.setScope(scopeAnnotation.value());
                           }else { //如果没有scope值
                               beanDefinition.setScope("singleton");
                           }
                           // 5. 将BeanDefinition放入到Map中
                           beanDefinitionMap.put(beanName,beanDefinition);
                       }else {
                           System.out.println("这不是一个SpringBean=" + clazz + " 类名" + className);
                       }
                   } catch (Exception e) {
                       e.printStackTrace();
                   }
    
               }
           }
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    1. 因为我们需要知道需要扫描的包的路径,所以需要借助配置类。我们这里将配置类的Class对象作为参数传递给我们的容器类的构造器(这一步在容器的构造器中体现)。
    2. 有了配置类的Class对象之后,我们就可以通过@ComponentScan拿到要扫描类的路径。
    3. 拿到包的路径之后,就得去扫描包中的类,而且得判断哪些类是加了@Component。只有加了此注解的将来才可以注入到容器中。
    4. 如果有@Component,那么还得判断它是否是后置处理器,如何是后置处理器,实例化之后就将其直接加入到后置处理器集合中。
    5. 如果不是后置处理器,接下来拿到@Component中的value值。如果没有value值为空,就默认按照id=类名首字母小写的方式命名。如果value值不为空,就将获取到的value值作为id。
    6. 接下来判断,类上是否有@Scope。如果有就拿到它的value值,反之就默认为singleton(单例)。最后将此信息存入到BeanDefinition中。BeanDefinition结构:
    package com.jl.spring.ioc;
    /**
     * 用于记录bean的信息(bean为单例还是多例Scope;bean对应的class对象,反射可以生成对应的对象)
     *
     */
    public class BeanDefinition {
        private String scope;
        private Class clazz;
    
        public BeanDefinition(String scope, Class clazz) {
            this.scope = scope;
            this.clazz = clazz;
        }
    
        public BeanDefinition() {
        }
    
        @Override
        public String toString() {
            return "BeanDefinition{" +
                    "scope='" + scope + '\'' +
                    ", clazz=" + clazz +
                    '}';
        }
    
        public String getScope() {
            return scope;
        }
    
        public void setScope(String scope) {
            this.scope = scope;
        }
    
        public Class getClazz() {
            return clazz;
        }
    
        public void setClazz(Class clazz) {
            this.clazz = clazz;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    1. 之后将我们得到的beanName(也就是id值)beanDefinition(记录单例还是多例),存到我们的beanDefinitionMap

    完成Bean实例的创建

    在上一步中我们对所有的类进行了扫描,并且将所有Bean的信息存入到了beanDefinitionMap中。接下来我们就可以创建Bean实例了。

    // 完成  createBean(BeanDefinition beanDefinition)方法
    private Object createBean(String beanName,BeanDefinition beanDefinition){
        // 得到bean的class对象
        Class clazz = beanDefinition.getClazz();
        // 使用反射得到实例
        try {
            Object instance = clazz.getDeclaredConstructor().newInstance();
            // 注入对象
            // 1. 遍历当前要创建的对象的所有字段
            for (Field declaredField : clazz.getDeclaredFields()){
                //2.  判断该字段是否有Autowired修饰
                if (declaredField.isAnnotationPresent(Autowired.class)){
                    // 3.得到字段的名称
                    String name = declaredField.getName();
                    // 4.通过getBean方法来获取要组装对象
                    Object bean = getBean(name);
                    // 5. 进行组装
                    // 因为属性是私有的,所以要暴破
                    declaredField.setAccessible(true);
                    declaredField.set(instance,bean);
                }
    
            }
            System.out.println("创建好了一个实例" + instance);
    
    
            // 我们在Bean的初始化方法前,调用我们后置处理器的before方法
            for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
                // 在后置处理器的before方法,可以对容器生成的bean进行处理
                // 然后返回处理后的bean实例
                Object current = beanPostProcessor.postProcessBeforeInitialization(instance,beanName);
                if (current != null){
                    instance = current;
                }
            }
    
            //判断是否需要执行Bean的初始化方法
            // 1. 判断当前创建的Bean对象是否实现了InitializingBean
            if (instance instanceof InitializingBean){ //如果实现了InitializingBean
                // 将 instance转成接口类型
                try {
                    ((InitializingBean)instance).afterPropertiesSet();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
    
            // 我们在Bean的初始化方法前,调用我们后置处理器的after方法
            for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
                // 在后置处理器的after方法,可以对容器生成的bean进行处理
                // 然后返回处理后的bean实例
                Object current = beanPostProcessor.postProcessAfterInitialization(instance,beanName);
                if (current != null){
                    instance = current; 
                }
            }
            System.out.println("-----------------------------------------");
            return instance;
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        // 如果反射对象失败,则返回空
        return null;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    1. 我们从BeanDefinition中拿到需要创建的Class对象。
    2. 使用Class对象通过反射来创建Bean对象实例。
    3. 因为我们创建对象中还有属性,所以还得考虑自动装配的情况。
    4. 拿到所有Class对象所有的Field对象数组,遍历判断是否有@Autowired。如果有就拿到此属性的名称,以此名称作为id去获取容器中的创建好的Bean实例。最后通过反射完成对属性的赋值。这里还得对属性进行暴破,因为属性是私有的.
    5. 接下来还不能将Bean注入到容器中,因为我们还有后置处理器初始化类
    6. BeanPostProcessor结构:
    package com.jl.spring.processor;
    
    import org.apache.commons.lang.StringUtils;
    
    /**
     * 参考原生Spring容器定义的一个接口
     * 该接口有两个方法
     */
    public interface BeanPostProcessor {
        /**
         * 这连个方法会对所有的bean生效
         * 该方法在bean的初始化方法前调用
         * @param bean
         * @param beanName
         * @return
         */
        default Object postProcessBeforeInitialization(Object bean, String beanName){
            return bean;
        };
    
        /**
         *  该方法在bena的初始化方法之后调用
         * @param bean
         * @param beanName
         * @return
         */
        default Object postProcessAfterInitialization(Object bean, String beanName){
            return bean;
        };
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    1. 遍历我们的beanPostProcessorList(后置处理器集合),调用它们的postProcessBeforeInitialization(),实现对Bean实例的前置处理。
    2. 判断当前的Bean对象是否实现了InitializingBean。如果实现了,执行它的afterPropertiesSet()InitializingBean结构如下:
    package com.jl.spring.processor;
    
    /**
     * 根据原生Spring定义一个接口
     * 这个接口有一个方法
     * afterPropertiesSet在Bean的Setter方法后执行,即就是我们的初始化方法
     * 当一个Bean实现这个接口后,就实现afterPropertiesSet
     */
    public interface InitializingBean {
        void afterPropertiesSet() throws Exception;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    1. 遍历我们的beanPostProcessorList(后置处理器集合),调用它们的postProcessAfterInitialization(),实现对Bean实例的后置处理。
    2. 最后返回我们的创建好的Bean实例。

    获取Bean实例

    // 编写方法返回容器的对象
    public Object getBean(String name){
        // 判断传入的beanName是否在beanDefinition中存在
        if (beanDefinitionMap.containsKey(name)){
            BeanDefinition beanDefinition = beanDefinitionMap.get(name);
            // 得到beanDefinition的scope,分别进行处理
            if("singleton".equalsIgnoreCase(beanDefinition.getScope())){
                // 单例的,直接从单例池中获取
                return  singletonObjects.get(name);
            }else { // 如果不是单例,就通过createBean,反射一个对象
                return createBean(name,beanDefinition);
            }
        }else {
            // 如果不存在
            throw new NullPointerException("没有该bean");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    1. 获取Bean实例,首先就得判断容器中是否有该Bean的信息。
    2. 判断要获取的Bean是否是单例,如果是单例就直接从单例池singletonObjects中获取。如果不是就调用createBean(),造一个Bean实例返回。

    容器的构造方法

    public JlSpringApplicationContext(Class configClass){
        beanDefinitionByScan(configClass);
        // 通过beanDefinition对象,初始化singletonObject单例池
        Enumeration<String> keys = beanDefinitionMap.keys();
        // 遍历所有的beanDefinition对象
        while (keys.hasMoreElements()){
            String beanName = keys.nextElement();
            // 通过beanName得到对应的beanDefinition对象
            BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
            // 判断该bean是singleton还是一个prototype
            if ("singleton".equalsIgnoreCase(beanDefinition.getScope())){
                // 将该bean实例放入到singletonObjects这个集合中
                Object bean = createBean(beanName,beanDefinition);
                singletonObjects.put(beanName,bean);
            }
        }
    //        System.out.println("单例池" + singletonObjects);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    测试

    Bean的测试(默认)

    配置类

    package com.jl.spring.ioc;
    
    import com.jl.spring.annotation.ComponentScan;
    
    /**
     * 这是一个配置类,作用类似我们原生spring的beans.xml 容器配置文件
     */
    @ComponentScan(value = "com.jl.spring.component")
    public class JlSpringConfig {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    测试类:

    package com.jl.spring;
    
    import com.jl.spring.component.MonsterService;
    import com.jl.spring.component.SmartAnimalable;
    import com.jl.spring.ioc.JlSpringApplicationContext;
    import com.jl.spring.ioc.JlSpringConfig;
    
    public class AppMain {
        public static void main(String[] args) {
            JlSpringApplicationContext jlSpringApplicationContext =
                    new JlSpringApplicationContext(JlSpringConfig.class);
            Object car = jlSpringApplicationContext.getBean("car");
            System.out.println(car);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    结果截图:
    在这里插入图片描述

    Bean的测试(通过指定id)

    package com.jl.spring.component;
    
    import com.jl.spring.annotation.Component;
    
    @Component(value = "myCar")
    public class Car {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    测试类:

    package com.jl.spring;
    
    import com.jl.spring.component.MonsterService;
    import com.jl.spring.component.SmartAnimalable;
    import com.jl.spring.ioc.JlSpringApplicationContext;
    import com.jl.spring.ioc.JlSpringConfig;
    
    public class AppMain {
        public static void main(String[] args) {
            JlSpringApplicationContext jlSpringApplicationContext =
                    new JlSpringApplicationContext(JlSpringConfig.class);
            Object car = jlSpringApplicationContext.getBean("myCar");
            System.out.println(car);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    结果截图:
    在这里插入图片描述

    自动装配测试

    package com.jl.spring.component;
    
    import com.jl.spring.annotation.Component;
    import com.jl.spring.processor.InitializingBean;
    
    @Component(value = "monsterDao")
    public class MonsterDao implements InitializingBean {
        public void hi(){
            System.out.println("MonsterDao-hi()被调用。。。");
        }
    
        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.println("MonsterDao初始化方法被调用");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    package com.jl.spring.component;
    
    import com.jl.spring.annotation.Autowired;
    import com.jl.spring.annotation.Component;
    import com.jl.spring.annotation.Scope;
    import com.jl.spring.processor.InitializingBean;
    
    /**
     * MonsterService是一个service
     */
    @Component(value = "monsterService") // 把MonsterService注入到我们自己的Spring容器中
    public class MonsterService implements InitializingBean {
        @Autowired
        private MonsterDao monsterDao;
        public void m1(){
            monsterDao.hi();
        }
    
        /**
         * 该方法就是Bean的方法执行过后,被容器调用
         * 即就是初始化方法
         * @throws Exception
         */
        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.println("MonsterService初始化方法被调用");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    测试类:

    package com.jl.spring;
    
    import com.jl.spring.component.MonsterService;
    import com.jl.spring.component.SmartAnimalable;
    import com.jl.spring.ioc.JlSpringApplicationContext;
    import com.jl.spring.ioc.JlSpringConfig;
    
    public class AppMain {
        public static void main(String[] args) {
            JlSpringApplicationContext jlSpringApplicationContext =
                    new JlSpringApplicationContext(JlSpringConfig.class);
            Object bean = jlSpringApplicationContext.getBean("monsterService");
            System.out.println(bean);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    结果截图:
    在这里插入图片描述

    单例多例测试

    package com.jl.spring.component;
    
    import com.jl.spring.annotation.Autowired;
    import com.jl.spring.annotation.Component;
    import com.jl.spring.annotation.Scope;
    import com.jl.spring.processor.InitializingBean;
    
    /**
     * MonsterService是一个service
     */
    @Component(value = "monsterService") // 把MonsterService注入到我们自己的Spring容器中
    @Scope(value = "prototype")
    public class MonsterService implements InitializingBean {
        @Autowired
        private MonsterDao monsterDao;
        public void m1(){
            monsterDao.hi();
        }
    
        /**
         * 该方法就是Bean的方法执行过后,被容器调用
         * 即就是初始化方法
         * @throws Exception
         */
        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.println("MonsterService初始化方法被调用");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    测试类

    package com.jl.spring;
    
    import com.jl.spring.component.MonsterService;
    import com.jl.spring.component.SmartAnimalable;
    import com.jl.spring.ioc.JlSpringApplicationContext;
    import com.jl.spring.ioc.JlSpringConfig;
    
    public class AppMain {
        public static void main(String[] args) {
            JlSpringApplicationContext jlSpringApplicationContext =
                    new JlSpringApplicationContext(JlSpringConfig.class);
            Object bean = jlSpringApplicationContext.getBean("monsterService");
            Object bean1 = jlSpringApplicationContext.getBean("monsterService");
            System.out.println(bean);
            System.out.println(bean1);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    结果截图:
    在这里插入图片描述

    后置处理器和初始化方法的测试

    package com.jl.spring.component;
    
    import com.jl.spring.annotation.Component;
    import com.jl.spring.processor.InitializingBean;
    
    @Component(value = "myCar")
    public class Car implements InitializingBean {
        public Car() {
            System.out.println("Car无参构造被调用...");
        }
        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.println("初始化方法");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    package com.jl.spring.component;
    
    import com.jl.spring.annotation.Component;
    import com.jl.spring.processor.BeanPostProcessor;
    
    @Component
    public class BeanPostProcessorImpl implements BeanPostProcessor{
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) {
            System.out.println("前置通知");
            return null;
        }
    
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) {
            System.out.println("后置通知");
            return null;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    测试类:

    package com.jl.spring;
    
    import com.jl.spring.component.MonsterService;
    import com.jl.spring.component.SmartAnimalable;
    import com.jl.spring.ioc.JlSpringApplicationContext;
    import com.jl.spring.ioc.JlSpringConfig;
    
    public class AppMain {
        public static void main(String[] args) {
            JlSpringApplicationContext jlSpringApplicationContext =
                    new JlSpringApplicationContext(JlSpringConfig.class);
            Object car = jlSpringApplicationContext.getBean("myCar");
            System.out.println(car);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    结果截图:
    在这里插入图片描述

    AOP的编写

    我们AOP和后置处理器有所联系。AOP就是利用前后置处理器进行切面处理。单例加强。

    我们先看一下,用后置处理器实现的切面。

    package com.jl.spring.component;
    
    public interface SmartAnimalable {
        float getSum(float i ,float j);
        float getSub(float i ,float j);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    package com.jl.spring.component;
    
    import com.jl.spring.annotation.Component;
    
    @Component(value="smartDog")
    public class SmartDog implements SmartAnimalable{
        @Override
        public float getSum(float i, float j) {
            float res = i+j;
            System.out.println("SmartDog-getSum-res=" + res);
            return res;
        }
    
    
        @Override
        public float getSub(float i, float j) {
            float res = i -j;
            System.out.println("SmartDog-getSub-res=" + res);
            return res;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    后置处理器实现类:

    package com.jl.spring.component;
    
    import com.jl.spring.annotation.Component;
    import com.jl.spring.processor.BeanPostProcessor;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    /**
     * 这是我们自己的后置处理器
     * 它是实现了BeanPostProcessor
     * 我们可以重写里边的方法
     * 在Spring容器中仍然将我们的后置处理器当作一个Bean来处理,要注入到容器中
     * 还得考虑多个后置处理器的情况
     */
    @Component
    public class JlBeanPostProcessor implements BeanPostProcessor {
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) {
            System.out.println("后置处理器的JlBeanPostProcessor的before()方法被调用" + bean.getClass() + " beanName=" + beanName);
            return bean;
        }
    
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) {
            System.out.println("后置处理器的JlBeanPostProcessor的after()方法被调用" + bean.getClass() + " beanName=" + beanName);
            // 实现AOP,返回代理对象,即对Bean进行包装
            if("smartDog".equals(beanName)){
                // 使用JDK的动态代理,返回Bean的代理对象
                Object proxyInstance = Proxy.newProxyInstance(JlBeanPostProcessor.class.getClassLoader(), bean.getClass().getInterfaces(),
                        new InvocationHandler() {
                            @Override
                            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                                System.out.println("method"+ method.getName());
                                Object result = null;
                                // 加入要进行前置通知处理的方法是getSum
                                if ("getSum".equals(method.getName())){
                                    SmartAnimalAspect.showBeginLog();
                                    result = method.invoke(bean,args);
                                    // 进行返回通知的处理
                                    SmartAnimalAspect.showSuccessLog();
                                }else {
                                    result = method.invoke(bean,args);
                                }
                                return result;
                            }
                        });
                // 如果bean是需要返回代理对象的,这里就直接返回代理对象
                return proxyInstance;
            }
            // 如果不需要AOP处理,我们就返回原生对象
            return bean;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    看到这里不知道小伙伴们有种似曾相识的感juo。没错!这里就是我们【AOP引入篇】中提到的动态代理。我们因为是简单演示,所以这里只是在postProcessAfterInitialization()中做了处理。

    测试类:

    package com.jl.spring;
    
    import com.jl.spring.component.MonsterService;
    import com.jl.spring.component.SmartAnimalable;
    import com.jl.spring.ioc.JlSpringApplicationContext;
    import com.jl.spring.ioc.JlSpringConfig;
    
    public class AppMain {
        public static void main(String[] args) {
            JlSpringApplicationContext jlSpringApplicationContext =
                    new JlSpringApplicationContext(JlSpringConfig.class);
     // 测试AOP是否生效
            SmartAnimalable smartDog = (SmartAnimalable)jlSpringApplicationContext.getBean("smartDog");
            smartDog.getSum(10,2);
            smartDog.getSub(10,2);
            System.out.println(smartDog.getClass());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    结果截图:
    在这里插入图片描述
    我们只对getSum做了增强,所以结果显示也只是对getSum的增强。
    其实真正的AOP也和这个很类似,但他对很多内容进行了封装。我们下边模拟一个AOP:

    package com.jl.spring.component;
    
    public interface SmartAnimalable {
        float getSum(float i ,float j);
        float getSub(float i ,float j);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    切面类

    package com.jl.spring.component;
    
    import com.jl.spring.annotation.*;
    
    /**
     * 先将SmartAnimalAspect当作一个切面类来使用
     * 后面再改的更加灵活
     */
    @Aspect
    @Component
    public class SmartAnimalAspect {
        @Before(value = "execution float com.jl.spring.component.SmartDog.getSum")
        public static void showBeginLog(){
            System.out.println("前置通知");
        }
        @AfterReturning(value = "execution float com.jl.spring.component.SmartDog.getSum")
        public static void showSuccessLog(){
            System.out.println("返回通知");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    package com.jl.spring.component;
    
    import com.jl.spring.annotation.Component;
    
    @Component(value="smartDog")
    public class SmartDog implements SmartAnimalable{
        @Override
        public float getSum(float i, float j) {
            float res = i+j;
            System.out.println("SmartDog-getSum-res=" + res);
            return res;
        }
    
    
        @Override
        public float getSub(float i, float j) {
            float res = i -j;
            System.out.println("SmartDog-getSub-res=" + res);
            return res;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    测试类:
    虽然是测试类,但这里边还对注解进行了处理,有兴趣的小伙伴可以将其抽取出来,做一些完善。

    package com.jl.spring;
    
    import com.jl.spring.annotation.AfterReturning;
    import com.jl.spring.annotation.Before;
    import com.jl.spring.component.SmartAnimalAspect;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    public class JlTest {
        public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
            Class<SmartAnimalAspect> smartAnimalAspectClass = SmartAnimalAspect.class;
            for (Method declaredMethod : smartAnimalAspectClass.getDeclaredMethods()) {
                if(declaredMethod.isAnnotationPresent(Before.class)){
    
                    String name = declaredMethod.getName();
                    Before annotation = declaredMethod.getAnnotation(Before.class);
                    String value = annotation.value();
    
                    Method declaredMethod1 = smartAnimalAspectClass.getDeclaredMethod(declaredMethod.getName());
                    declaredMethod1.invoke(smartAnimalAspectClass.newInstance(),null);
                }else if(declaredMethod.isAnnotationPresent(AfterReturning.class)){
                    String name = declaredMethod.getName();
                    Before annotation = declaredMethod.getAnnotation(Before.class);
                    String value = annotation.value();
    
                    Method declaredMethod1 = smartAnimalAspectClass.getDeclaredMethod(declaredMethod.getName());
                    declaredMethod1.invoke(smartAnimalAspectClass.newInstance(),null);
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    结果截图:
    在这里插入图片描述

    总结

    以上就是我们手写的一个简易的Spring,主要是帮助大家理解Spring的基本执行流程。

    如果文章中有描述不准确或者错误的地方,还望指正。您可以留言📫或者私信我。🙏
    最后希望大家多多 关注+点赞+收藏^_^,你们的鼓励是我不断前进的动力!!!
    感谢感谢~~~🙏🙏🙏

  • 相关阅读:
    【嵌入式C语言】8.函数
    ML |机器学习模型如何检测和预防过拟合?
    中秋不加班,猿人永不屈服!!! So,How to celebrate the Mid Autumn Festival?
    跨域推荐:嵌入映射、联合训练和解耦表征
    辽宁工程技术大学计算机考研资料汇总
    河南灵活用工平台发展是大趋势吗?
    3 垃圾收集算法
    企业安全不求人,一个小技巧就能搞定
    为什么工作不能让人满意?
    1.计算机组成与体系结构
  • 原文地址:https://blog.csdn.net/qq_35947021/article/details/128035216