Skip to content

mmsyLH/LHSpring

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 

Repository files navigation

:::info 💡 初始化IOC容器+依赖注入+BeanPostProcessor机制+AOP ::: GitHub地址:https://github.com/1072344372/LHSpring

一图胜千言

image.png

1.实现阶段1

编写Spring容器,实现扫描包,得到bean的class对象 image.png 导包 image.png image.png 创建对应文件,注意导入的是自定义的注解,

package asia.lhweb.spring.annotation;

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

/**
 * 组件扫描
 * 1 @Target(ElementType.TYPE):
 * 指定ComponentScan注解可以修饰type类型
 * 2 @Retention(RetentionPolicy.RUNTIME)
 *  指定ComponentScan存活范围
 * 3 表示ComponentScan可以传入value属性
 * @author 罗汉
 * @date 2023/07/17
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ComponentScan {
    String value() default "";
}

Component、Controller、Repository、Service注解类似这里只展示Component注解

package asia.lhweb.spring.annotation;

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

/**
 * 组件
 *
 * @author 罗汉
 * @date 2023/07/23
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {
    //通过value可以给注入的bean指定id 名字
    String value() default "";
}
package asia.lhweb.spring.component;

import asia.lhweb.spring.annotation.Service;

/**
 * MonsterService是一个service
 *  1 如果指定了那么在注入容器时以指定的为准
 *  2 如果没有指定则使用类名首字母小写的名字
 * @author 罗汉
 * @date 2023/07/23
 */
@Service(value = "monsterService")//把MonsterService注入到我们自己的容器中
public class MonsterService {

}
package asia.lhweb.spring.ioc;

import asia.lhweb.spring.annotation.*;

import org.springframework.util.StringUtils;

import java.io.File;
import java.net.URL;
import java.util.concurrent.ConcurrentHashMap;

/**
 * lhspring应用程序上下文
 *
 * @author 罗汉
 * @date 2023/07/23
 */
public class LHSpringApplicationContext {
    private Class configClass;
    // 基于注解
    private final ConcurrentHashMap<String, Object> ioc = new ConcurrentHashMap<>();

    public LHSpringApplicationContext(Class configClass) {
        this.configClass = configClass;
        System.out.println("配置的路径:this.configClass =" + configClass);
        // 1得到注解
        ComponentScan componentScan = (ComponentScan) this.configClass.getAnnotation(ComponentScan.class);
        // 2通过componentScan得到要扫描的包
        String path = componentScan.value();
        System.out.println("要扫码的包为:path=" + path);

        // 1 得到类加载器->APP 类加载器
        ClassLoader classLoader = LHSpringApplicationContext.class.getClassLoader();
        // 2 获取扫描包的url
        path = path.replace(".", "/");
        URL resource = classLoader.getResource(path);
        System.out.println(resource);
        File file = new File(resource.getFile());
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (File file1 : files) {
                // System.out.println(file1);
                String absolutePath = file1.getAbsolutePath();
                // 只处理class文件
                if (absolutePath.endsWith(".class")) {
                    // 绝对路径:---F:\JavaWorksparce\Spring\out\production\springTest\xyz\lhweb\spring\component\MyComponent.class
                    // xyz.lhweb.spring.component.MyComponent

                    // 1 获取类名
                    String className = absolutePath.substring(absolutePath.lastIndexOf("\\") + 1, absolutePath.indexOf(".class"));
                    // System.out.println(className);

                    // 2 获取类的完整路径
                    String classFullName = path.replace("/", ".") + "." + className;
                    System.out.println(classFullName);

                    // 3 判断该类是不是需要注入到容器中
                    try {
                        // 反射一个类对象
                        // 1 Class.forName 调用该类的静态方法
                        // 2 classLoader.loadClass 不会调用该类的静态方法
                        // 3 isAnnotationPresent判断该类是否有这个注解
                        Class<?> clazz = classLoader.loadClass(classFullName);
                        if (clazz.isAnnotationPresent(Service.class)
                                || (clazz.isAnnotationPresent(Component.class))
                                || (clazz.isAnnotationPresent(Controller.class))
                                || (clazz.isAnnotationPresent(Repository.class))) {

                            if (clazz.isAnnotationPresent(Service.class)){
                                System.out.println("这是一个LHSpring bean="+clazz+"    类名="+className);
                                Service declaredAnnotation = clazz.getDeclaredAnnotation(Service.class);
                                String id = declaredAnnotation.value();
                                if (!StringUtils.isEmpty(id)){
                                    className=id;//替换
                                }
                            }
                            if (clazz.isAnnotationPresent(Component.class)){
                                System.out.println("这是一个LHSpring bean="+clazz+"    类名="+className);
                                Component declaredAnnotation = clazz.getDeclaredAnnotation(Component.class);
                                String id = declaredAnnotation.value();
                                if (!StringUtils.isEmpty(id)){
                                    className=id;//替换
                                }
                            }
                            if (clazz.isAnnotationPresent(Controller.class)){
                                System.out.println("这是一个LHSpring bean="+clazz+"    类名="+className);
                                Controller declaredAnnotation = clazz.getDeclaredAnnotation(Controller.class);
                                String id = declaredAnnotation.value();
                                if (!StringUtils.isEmpty(id)){
                                    className=id;//替换
                                }
                            }
                            if (clazz.isAnnotationPresent(Repository.class)){
                                System.out.println("这是一个LHSpring bean="+clazz+"    类名="+className);
                                Repository declaredAnnotation = clazz.getDeclaredAnnotation(Repository.class);
                                String id = declaredAnnotation.value();
                                if (!StringUtils.isEmpty(id)){
                                    className=id;//替换
                                }
                            }

                        }else {
                            System.out.println("这不是一个Spring bean="+clazz);
                        }

                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }

                }
            }
        }
    }
    //返回容器对象
    public Object getBean(String name) {
        return ioc.get(name);
    }
}
package asia.lhweb.spring.ioc;

import asia.lhweb.spring.annotation.ComponentScan;

/**
 * lhspring配置
 *  类似beans.xml  容器配置文件
 * @author 罗汉
 * @date 2023/07/17
 */
@ComponentScan(value = "asia.lhweb.spring.component")
public class LHSpringConfig {

}

测试方法

import asia.lhweb.spring.ioc.LHSpringApplicationContext;
import asia.lhweb.spring.ioc.LHSpringConfig;

public class Text {
    public static void main(String[] args) {
        LHSpringApplicationContext ioc = new LHSpringApplicationContext(LHSpringConfig.class);
        
    }
}

2.实现阶段2

扫描将bean信息封装到BeanDefinition对象,并放入到Map image.png

新增一个Scope注解

package asia.lhweb.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】
 *
 * @author 罗汉
 * @date 2023/07/23
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Scope {
    //通过value可以指定是singleton还是prototype
    String value() default "";
}

默认为单例,在MonsterService添加这个注解 image.png

新建BeanDefiniton.java 用于封装/记录Bean的信息

package asia.lhweb.spring.ioc;

/**
 * 用于封装/记录Bean的信息[1 scope 2 bean对应的class对象]
 * @author :罗汉
 * @date : 2023/7/23
 */
public class BeanDefiniton {
    private String scope;
    private Class clazz;

    public BeanDefiniton() {
    }

    public BeanDefiniton(String scope, Class clazz) {
        this.scope = scope;
        this.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;
    }

    @Override
    public String toString() {
        return "BeanDefiniton{" +
                "scope='" + scope + '\'' +
                ", clazz=" + clazz +
                '}';
    }
}

修改LHSpringApplicationContext

package asia.lhweb.spring.ioc;

import asia.lhweb.spring.annotation.*;
import org.springframework.util.StringUtils;



import java.io.File;
import java.net.URL;
import java.util.concurrent.ConcurrentHashMap;

/**
 * lhspring应用程序上下文
 *
 * @author 罗汉
 * @date 2023/07/23
 */
public class LHSpringApplicationContext {
    private Class configClass;
    // 基于注解
    private final ConcurrentHashMap<String, BeanDefiniton> beanDefinitonMap = new ConcurrentHashMap<>();//存放BeanDefiniton对象
    private final ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();//存放单例对象

    public LHSpringApplicationContext(Class configClass) {
        beanDefiniton(configClass);
        System.out.println("beanDefinitonMap="+beanDefinitonMap);
    }

    /**
     * 完成对指定包的扫描,并且封装到BeanDefinition对象,再放入到Map中
     *
     * @param configClass 配置类
     */
    private void beanDefiniton(Class configClass) {
        this.configClass = configClass;
        // System.out.println("配置的路径:this.configClass =" + configClass);
        // 1得到注解
        ComponentScan componentScan = (ComponentScan) this.configClass.getAnnotation(ComponentScan.class);
        // 2通过componentScan得到要扫描的包
        String path = componentScan.value();
        // System.out.println("要扫码的包为:path=" + path);

        // 1 得到类加载器->APP 类加载器
        ClassLoader classLoader = LHSpringApplicationContext.class.getClassLoader();
        // 2 获取扫描包的url
        path = path.replace(".", "/");
        URL resource = classLoader.getResource(path);
        // System.out.println(resource);
        File file = new File(resource.getFile());
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (File file1 : files) {
                // System.out.println(file1);
                String absolutePath = file1.getAbsolutePath();
                // 只处理class文件
                if (absolutePath.endsWith(".class")) {
                    // 绝对路径:---F:\JavaWorksparce\Spring\out\production\springTest\xyz\lhweb\spring\component\MyComponent.class
                    // xyz.lhweb.spring.component.MyComponent

                    // 1 获取类名
                    String className = absolutePath.substring(absolutePath.lastIndexOf("\\") + 1, absolutePath.indexOf(".class"));
                    // System.out.println(className);

                    // 2 获取类的完整路径
                    String classFullName = path.replace("/", ".") + "." + className;
                    System.out.println(classFullName);

                    // 3 判断该类是不是需要注入到容器中
                    try {
                        // 反射一个类对象
                        // 1 Class.forName 调用该类的静态方法
                        // 2 classLoader.loadClass 不会调用该类的静态方法
                        // 3 isAnnotationPresent判断该类是否有这个注解
                        Class<?> clazz = classLoader.loadClass(classFullName);
                        if (clazz.isAnnotationPresent(Service.class)
                                || (clazz.isAnnotationPresent(Component.class))
                                || (clazz.isAnnotationPresent(Controller.class))
                                || (clazz.isAnnotationPresent(Repository.class))) {

                            if (clazz.isAnnotationPresent(Service.class)){
                                System.out.println("这是一个LHSpring bean="+clazz+"    类名="+className);
                                //将Bean的信息封装到BeanDefiniton中放入map
                                // 1 得到Service注解
                                Service declaredAnnotation = clazz.getDeclaredAnnotation(Service.class);
                                // 2 得到value值
                                String beanName = declaredAnnotation.value();
                                method(className, clazz, beanName);
                            }

                            if (clazz.isAnnotationPresent(Component.class)){
                                System.out.println("这是一个LHSpring bean="+clazz+"    类名="+className);
                                Component declaredAnnotation = clazz.getDeclaredAnnotation(Component.class);
                                String beanName = declaredAnnotation.value();
                                method(className, clazz, beanName);
                            }

                            if (clazz.isAnnotationPresent(Controller.class)){
                                System.out.println("这是一个LHSpring bean="+clazz+"    类名="+className);
                                Controller declaredAnnotation = clazz.getDeclaredAnnotation(Controller.class);
                                String beanName = declaredAnnotation.value();
                                method(className, clazz, beanName);
                            }

                            if (clazz.isAnnotationPresent(Repository.class)){
                                System.out.println("这是一个LHSpring bean="+clazz+"    类名="+className);
                                Repository declaredAnnotation = clazz.getDeclaredAnnotation(Repository.class);
                                String beanName = declaredAnnotation.value();
                                method(className, clazz, beanName);
                            }

                        }else {
                            System.out.println("这不是一个LHSpring bean="+clazz+"  类名="+className);
                        }

                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }

                }
            }
        }
    }

    /**
     * 共同方法提取出来方法
     *
     * @param className 类名
     * @param clazz     clazz
     * @param beanName  bean名字
     */
    private void method(String className, Class<?> clazz, String beanName) {
        if ("".equals(beanName)){//如果为空
            //首字母小写作为beanName
            beanName = StringUtils.uncapitalize(className);//替换
        }
        // 3 放入map
        BeanDefiniton beanDefiniton = new BeanDefiniton();
        beanDefiniton.setClazz(clazz);
        // 4 获取Scope值
        if ( clazz.isAnnotationPresent(Scope.class)){
            //如果配置了Scope
            Scope scopedeclaredAnnotation = clazz.getDeclaredAnnotation(Scope.class);
            beanDefiniton.setScope(scopedeclaredAnnotation.value());
        }else {
            //如果没有配置
            beanDefiniton.setScope("singleton");
        }
        //放入到map中
        beanDefinitonMap.put(beanName,beanDefiniton);
    }


}

测试结果 image.png

3.实现阶段3

初始化bean单例池,并完成getBean方法,createBean方法 image.png 在LHSpringApplicationContext中创建一个得到bean的方法 image.png 修改方法 image.png 到此已经完成image.png image.png 写一个得到bean的方法 image.png

package asia.lhweb.spring.ioc;

import asia.lhweb.spring.annotation.*;
import org.springframework.util.StringUtils;


import java.io.File;
import java.net.URL;
import java.util.Enumeration;
import java.util.concurrent.ConcurrentHashMap;

/**
 * lhspring应用程序上下文
 *
 * @author 罗汉
 * @date 2023/07/23
 */
public class LHSpringApplicationContext {
    private Class configClass;
    // 基于注解
    private final ConcurrentHashMap<String, BeanDefinition> beanDefinitonMap = new ConcurrentHashMap<>();// 存放BeanDefiniton对象
    private final ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();// 存放单例对象

    public LHSpringApplicationContext(Class configClass) {
        //完成扫描
        beanDefinitonByScan(configClass);

        //通过beanDefinitonMap,初始化单例池 singletonObjects
        System.out.println("beanDefinitonMap=" + beanDefinitonMap);
        Enumeration<String> keys = beanDefinitonMap.keys();//kes指的是全部bean的名字
        while (keys.hasMoreElements()){
            //得到beanName
            String beanName = keys.nextElement();
            // System.out.println(beanName);

            //通过BeanName 得到对应的beanDefinition对象
            BeanDefinition beanDefinition = beanDefinitonMap.get(beanName);
            // System.out.println(beanDefinition);
            //判断该bean是singleton还是prototype
            if ("singleton".equalsIgnoreCase(beanDefinition.getScope())){//是单例
                //将该bean实例放入到singletonObjects
                Object bean = createBean(beanDefinition);
                singletonObjects.put(beanName,bean);
            }

        }
        System.out.println(singletonObjects);
    }

    /**
     * 完成对指定包的扫描,并且封装到BeanDefinition对象,再放入到Map中
     *
     * @param configClass 配置类
     */
    public void beanDefinitonByScan(Class configClass) {
        this.configClass = configClass;
        // System.out.println("配置的路径:this.configClass =" + configClass);
        // 1得到注解
        ComponentScan componentScan = (ComponentScan) this.configClass.getAnnotation(ComponentScan.class);
        // 2通过componentScan得到要扫描的包
        String path = componentScan.value();
        // System.out.println("要扫码的包为:path=" + path);

        // 1 得到类加载器->APP 类加载器
        ClassLoader classLoader = LHSpringApplicationContext.class.getClassLoader();
        // 2 获取扫描包的url
        path = path.replace(".", "/");
        URL resource = classLoader.getResource(path);
        // System.out.println(resource);
        File file = new File(resource.getFile());
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (File file1 : files) {
                // System.out.println(file1);
                String absolutePath = file1.getAbsolutePath();
                // 只处理class文件
                if (absolutePath.endsWith(".class")) {
                    // 绝对路径:---F:\JavaWorksparce\Spring\out\production\springTest\xyz\lhweb\spring\component\MyComponent.class
                    // xyz.lhweb.spring.component.MyComponent

                    // 1 获取类名
                    String className = absolutePath.substring(absolutePath.lastIndexOf("\\") + 1, absolutePath.indexOf(".class"));
                    // System.out.println(className);

                    // 2 获取类的完整路径
                    String classFullName = path.replace("/", ".") + "." + className;
                    System.out.println(classFullName);

                    // 3 判断该类是不是需要注入到容器中
                    try {
                        // 反射一个类对象
                        // 1 Class.forName 调用该类的静态方法
                        // 2 classLoader.loadClass 不会调用该类的静态方法
                        // 3 isAnnotationPresent判断该类是否有这个注解
                        Class<?> clazz = classLoader.loadClass(classFullName);
                        if (clazz.isAnnotationPresent(Service.class)
                                || (clazz.isAnnotationPresent(Component.class))
                                || (clazz.isAnnotationPresent(Controller.class))
                                || (clazz.isAnnotationPresent(Repository.class))) {

                            if (clazz.isAnnotationPresent(Service.class)) {
                                System.out.println("这是一个LHSpring bean=" + clazz + "    类名=" + className);
                                // 将Bean的信息封装到BeanDefiniton中放入map
                                // 1 得到Service注解
                                Service declaredAnnotation = clazz.getDeclaredAnnotation(Service.class);
                                // 2 得到value值
                                String beanName = declaredAnnotation.value();
                                method(className, clazz, beanName);
                            }

                            if (clazz.isAnnotationPresent(Component.class)) {
                                System.out.println("这是一个LHSpring bean=" + clazz + "    类名=" + className);
                                Component declaredAnnotation = clazz.getDeclaredAnnotation(Component.class);
                                String beanName = declaredAnnotation.value();
                                method(className, clazz, beanName);
                            }

                            if (clazz.isAnnotationPresent(Controller.class)) {
                                System.out.println("这是一个LHSpring bean=" + clazz + "    类名=" + className);
                                Controller declaredAnnotation = clazz.getDeclaredAnnotation(Controller.class);
                                String beanName = declaredAnnotation.value();
                                method(className, clazz, beanName);
                            }

                            if (clazz.isAnnotationPresent(Repository.class)) {
                                System.out.println("这是一个LHSpring bean=" + clazz + "    类名=" + className);
                                Repository declaredAnnotation = clazz.getDeclaredAnnotation(Repository.class);
                                String beanName = declaredAnnotation.value();
                                method(className, clazz, beanName);
                            }

                        } else {
                            System.out.println("这不是一个LHSpring bean=" + clazz + "  类名=" + className);
                        }

                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }

                }
            }
        }
    }

    /**
     * 共同方法提取出来方法
     *
     * @param className 类名
     * @param clazz     clazz
     * @param beanName  bean名字
     */
    public void method(String className, Class<?> clazz, String beanName) {
        if ("".equals(beanName)) {// 如果为空
            // 首字母小写作为beanName
            beanName = StringUtils.uncapitalize(className);// 替换
        }
        // 3 放入map
        BeanDefinition beanDefinition = new BeanDefinition();
        beanDefinition.setClazz(clazz);
        // 4 获取Scope值
        if (clazz.isAnnotationPresent(Scope.class)) {
            // 如果配置了Scope
            Scope scopedeclaredAnnotation = clazz.getDeclaredAnnotation(Scope.class);
            beanDefinition.setScope(scopedeclaredAnnotation.value());
        } else {
            // 如果没有配置
            beanDefinition.setScope("singleton");
        }
        // 放入到map中
        beanDefinitonMap.put(beanName, beanDefinition);
    }

    /**
     * 创建bean
     *
     * @param beanDefinition bean定义
     */
    private Object createBean(BeanDefinition beanDefinition) {
        // 得到Bean的clazz对象
        Class clazz = beanDefinition.getClazz();

        try {
            // 使用反射得到实例
            Object instance = clazz.getDeclaredConstructor().newInstance();
            return instance;
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 如果反射创建对象失败
        return null;
    }

    /**
     * 得到bean
     *
     * @param beanName bean名字
     * @return {@link Object}
     */
    public Object getBean(String beanName) {
        //判断 传入的beanName是否在beanDefinitonMap中存在
        if (beanDefinitonMap.containsKey(beanName)){//存在
            BeanDefinition beanDefinition = beanDefinitonMap.get(beanName);
            //得到beanDefinition的scope,分别进行处理
            if ("singleton".equalsIgnoreCase(beanDefinition.getScope())){
                //说明是单例的,就直接从单例池获取
                return singletonObjects.get(beanName);
            }else {//不是单例就调用creatBean,反射一个对象
                return createBean(beanDefinition);
            }
        }else {//不存在
            //抛出个空指针异常
            throw  new NullPointerException("没有该bean");

        }

    }
}

结果 image.png 可以自行测试多次获取是否存在的bean名以及是否单例。

4.实现阶段4-完成依赖注入

新添加一个注解类 image.png

package asia.lhweb.spring.annotation;

import java.lang.annotation.*;

/**
 * 自动装配注解
 *
 * @author 罗汉
 * @date 2023/07/23
 */

@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
    //一定要找到一个匹配的找不到就会报错
    // boolean required() default true;
}

image.png 修改createBean方法 image.png

package asia.lhweb.spring.ioc;

import asia.lhweb.spring.annotation.*;
import org.springframework.util.StringUtils;


import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.Enumeration;
import java.util.concurrent.ConcurrentHashMap;

/**
 * lhspring应用程序上下文
 *
 * @author 罗汉
 * @date 2023/07/23
 */
public class LHSpringApplicationContext {
    private Class configClass;
    // 基于注解
    private final ConcurrentHashMap<String, BeanDefinition> beanDefinitonMap = new ConcurrentHashMap<>();// 存放BeanDefiniton对象
    private final ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();// 存放单例对象

    public LHSpringApplicationContext(Class configClass) {
        // 完成扫描
        beanDefinitonByScan(configClass);

        // 通过beanDefinitonMap,初始化单例池 singletonObjects
        System.out.println("beanDefinitonMap=" + beanDefinitonMap);
        Enumeration<String> keys = beanDefinitonMap.keys();// kes指的是全部bean的名字
        while (keys.hasMoreElements()) {
            // 得到beanName
            String beanName = keys.nextElement();
            // System.out.println(beanName);

            // 通过BeanName 得到对应的beanDefinition对象
            BeanDefinition beanDefinition = beanDefinitonMap.get(beanName);
            // System.out.println(beanDefinition);
            // 判断该bean是singleton还是prototype
            if ("singleton".equalsIgnoreCase(beanDefinition.getScope())) {// 是单例
                // 将该bean实例放入到singletonObjects
                Object bean = createBean(beanDefinition);
                singletonObjects.put(beanName, bean);
            }

        }
        System.out.println(singletonObjects);
    }

    /**
     * 完成对指定包的扫描,并且封装到BeanDefinition对象,再放入到Map中
     *
     * @param configClass 配置类
     */
    public void beanDefinitonByScan(Class configClass) {
        this.configClass = configClass;
        // System.out.println("配置的路径:this.configClass =" + configClass);
        // 1得到注解
        ComponentScan componentScan = (ComponentScan) this.configClass.getAnnotation(ComponentScan.class);
        // 2通过componentScan得到要扫描的包
        String path = componentScan.value();
        // System.out.println("要扫码的包为:path=" + path);

        // 1 得到类加载器->APP 类加载器
        ClassLoader classLoader = LHSpringApplicationContext.class.getClassLoader();
        // 2 获取扫描包的url
        path = path.replace(".", "/");
        URL resource = classLoader.getResource(path);
        // System.out.println(resource);
        File file = new File(resource.getFile());
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (File file1 : files) {
                // System.out.println(file1);
                String absolutePath = file1.getAbsolutePath();
                // 只处理class文件
                if (absolutePath.endsWith(".class")) {
                    // 绝对路径:---F:\JavaWorksparce\Spring\out\production\springTest\xyz\lhweb\spring\component\MyComponent.class
                    // xyz.lhweb.spring.component.MyComponent

                    // 1 获取类名
                    String className = absolutePath.substring(absolutePath.lastIndexOf("\\") + 1, absolutePath.indexOf(".class"));
                    // System.out.println(className);

                    // 2 获取类的完整路径
                    String classFullName = path.replace("/", ".") + "." + className;
                    System.out.println(classFullName);

                    // 3 判断该类是不是需要注入到容器中
                    try {
                        // 反射一个类对象
                        // 1 Class.forName 调用该类的静态方法
                        // 2 classLoader.loadClass 不会调用该类的静态方法
                        // 3 isAnnotationPresent判断该类是否有这个注解
                        Class<?> clazz = classLoader.loadClass(classFullName);
                        if (clazz.isAnnotationPresent(Service.class) || (clazz.isAnnotationPresent(Component.class)) || (clazz.isAnnotationPresent(Controller.class)) || (clazz.isAnnotationPresent(Repository.class))) {

                            if (clazz.isAnnotationPresent(Service.class)) {
                                System.out.println("这是一个LHSpring bean=" + clazz + "    类名=" + className);
                                // 将Bean的信息封装到BeanDefiniton中放入map
                                // 1 得到Service注解
                                Service declaredAnnotation = clazz.getDeclaredAnnotation(Service.class);
                                // 2 得到value值
                                String beanName = declaredAnnotation.value();
                                method(className, clazz, beanName);
                            }

                            if (clazz.isAnnotationPresent(Component.class)) {
                                System.out.println("这是一个LHSpring bean=" + clazz + "    类名=" + className);
                                Component declaredAnnotation = clazz.getDeclaredAnnotation(Component.class);
                                String beanName = declaredAnnotation.value();
                                method(className, clazz, beanName);
                            }

                            if (clazz.isAnnotationPresent(Controller.class)) {
                                System.out.println("这是一个LHSpring bean=" + clazz + "    类名=" + className);
                                Controller declaredAnnotation = clazz.getDeclaredAnnotation(Controller.class);
                                String beanName = declaredAnnotation.value();
                                method(className, clazz, beanName);
                            }

                            if (clazz.isAnnotationPresent(Repository.class)) {
                                System.out.println("这是一个LHSpring bean=" + clazz + "    类名=" + className);
                                Repository declaredAnnotation = clazz.getDeclaredAnnotation(Repository.class);
                                String beanName = declaredAnnotation.value();
                                method(className, clazz, beanName);
                            }

                        } else {
                            System.out.println("这不是一个LHSpring bean=" + clazz + "  类名=" + className);
                        }

                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }

                }
            }
        }
    }

    /**
     * 共同方法提取出来方法
     *
     * @param className 类名
     * @param clazz     clazz
     * @param beanName  bean名字
     */
    public void method(String className, Class<?> clazz, String beanName) {
        if ("".equals(beanName)) {// 如果为空
            // 首字母小写作为beanName
            beanName = StringUtils.uncapitalize(className);// 替换
        }
        // 3 放入map
        BeanDefinition beanDefinition = new BeanDefinition();
        beanDefinition.setClazz(clazz);
        // 4 获取Scope值
        if (clazz.isAnnotationPresent(Scope.class)) {
            // 如果配置了Scope
            Scope scopedeclaredAnnotation = clazz.getDeclaredAnnotation(Scope.class);
            beanDefinition.setScope(scopedeclaredAnnotation.value());
        } else {
            // 如果没有配置
            beanDefinition.setScope("singleton");
        }
        // 放入到map中
        beanDefinitonMap.put(beanName, beanDefinition);
    }

    /**
     * 创建bean
     *
     * @param beanDefinition bean定义
     */
    private Object createBean(BeanDefinition beanDefinition) {
        // 得到Bean的clazz对象
        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);// 第一个是需要组装的对象  第二个参数是你要组装的东西
                }
            }
            return instance;
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 如果反射创建对象失败
        return null;
    }

    /**
     * 得到bean
     *
     * @param beanName bean名字
     * @return {@link Object}
     */
    public Object getBean(String beanName) {
        // 判断 传入的beanName是否在beanDefinitonMap中存在
        if (beanDefinitonMap.containsKey(beanName)) {// 存在
            BeanDefinition beanDefinition = beanDefinitonMap.get(beanName);
            // 得到beanDefinition的scope,分别进行处理
            if ("singleton".equalsIgnoreCase(beanDefinition.getScope())) {
                // 说明是单例的,就直接从单例池获取
                return singletonObjects.get(beanName);
            } else {// 不是单例就调用creatBean,反射一个对象
                return createBean(beanDefinition);
            }
        } else {// 不存在
            // 抛出个空指针异常
            throw new NullPointerException("没有该bean");

        }

    }
}

结果展示 image.png

5.实现阶段5-bean后置处理器实现(相对复杂)

根据原生spring定义一个接口 image.png image.png 搞定初始化方法 image.png 模仿spring新建一个接口BeanPostProcessor.java

package asia.lhweb.spring.processor;

import org.springframework.beans.BeansException;
import org.springframework.lang.Nullable;

/**
 * 后置处理程序
 * 1 参考原生spring容器定义的一个接口
 * 2 该接口有2个方法
 * 3 这2个方法会对spring容器的全部bean生效(切面编程的概念)
 * @author 罗汉
 * @date 2023/07/24
 */
public interface BeanPostProcessor {
    /**
     * 在初始化方法前调用
     *
     * @param bean     豆
     * @param beanName bean名字
     * @return {@link Object}
     */
    @Nullable
    default Object postProcessBeforeInitialization(Object bean, String beanName){
        return bean;
    }


    /**
     * 发布过程初始化后调用
     *
     * @param bean     豆
     * @param beanName bean名字
     * @return {@link Object}
     */
    default Object postProcessAfterInitialization(Object bean, String beanName){
        return bean;
    }
}

写一个自己的后置处理器(目前还是普通的bean)

package asia.lhweb.spring.component;

import asia.lhweb.spring.annotation.Component;
import asia.lhweb.spring.processor.BeanPostProcessor;

/**
 * lhbean后置处理程序
 * 可以写里面的方法
 *
 * 在spring容器中仍然把后置处理器当成一个bean对待
 *
 * @author 罗汉
 * @date 2023/07/24
 */
@Component
public class LHBeanPostProcessor implements BeanPostProcessor {
    /**
     * 在初始化方法前调用
     *
     * @param bean     豆
     * @param beanName bean名字
     * @return {@link Object}
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        System.out.println("后置处理器LHBeanPostProcessor 的before调用 bean的类型="+
                bean.getClass()+"bean的名字="+beanName);
        return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
    }

    /**
     * 发布过程初始化后调用
     *
     * @param bean     豆
     * @param beanName bean名字
     * @return {@link Object}
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        System.out.println("后置处理器LHBeanPostProcessor 的after调用   bean的类型="+
                bean.getClass()+"bean的名字="+beanName);
        return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
    }
}

修改beanDefinitonByScan方法 image.png image.png 修改createBean方法 image.png 新建一个car测试

package asia.lhweb.spring.component;

import asia.lhweb.spring.annotation.Component;
import asia.lhweb.spring.processor.InitializingBean;
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;

/**
 * @author :罗汉
 * @date : 2023/7/24
 */
@Component
public class car implements InitializingBean {
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("car的初始化方法");
    }
}
package asia.lhweb.spring.ioc;

import asia.lhweb.spring.annotation.*;
import asia.lhweb.spring.processor.BeanPostProcessor;
import asia.lhweb.spring.processor.InitializingBean;
import org.springframework.util.StringUtils;


import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * lhspring应用程序上下文
 *
 * @author 罗汉
 * @date 2023/07/23
 */
public class LHSpringApplicationContext {
    private Class configClass;
    // 基于注解
    private final ConcurrentHashMap<String, BeanDefinition> beanDefinitonMap = new ConcurrentHashMap<>();// 存放BeanDefiniton对象
    private final ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();// 存放单例对象

    //定义一个属性 用来存放后置处理器
    private  List<BeanPostProcessor> beanPostProcessorList=new ArrayList<BeanPostProcessor>();

    public LHSpringApplicationContext(Class configClass) {
        // 完成扫描
        beanDefinitonByScan(configClass);

        // 通过beanDefinitonMap,初始化单例池 singletonObjects
        System.out.println("beanDefinitonMap=" + beanDefinitonMap);
        Enumeration<String> keys = beanDefinitonMap.keys();// kes指的是全部bean的名字
        while (keys.hasMoreElements()) {
            // 得到beanName
            String beanName = keys.nextElement();
            // System.out.println(beanName);

            // 通过BeanName 得到对应的beanDefinition对象
            BeanDefinition beanDefinition = beanDefinitonMap.get(beanName);
            // System.out.println(beanDefinition);
            // 判断该bean是singleton还是prototype
            if ("singleton".equalsIgnoreCase(beanDefinition.getScope())) {// 是单例
                // 将该bean实例放入到singletonObjects
                Object bean = createBean(beanName,beanDefinition);
                singletonObjects.put(beanName, bean);
            }

        }
        System.out.println(singletonObjects);
    }

    /**
     * 完成对指定包的扫描,并且封装到BeanDefinition对象,再放入到Map中
     *
     * @param configClass 配置类
     */
    public void beanDefinitonByScan(Class configClass) {
        this.configClass = configClass;
        // System.out.println("配置的路径:this.configClass =" + configClass);
        // 1得到注解
        ComponentScan componentScan = (ComponentScan) this.configClass.getAnnotation(ComponentScan.class);
        // 2通过componentScan得到要扫描的包
        String path = componentScan.value();
        // System.out.println("要扫码的包为:path=" + path);

        // 1 得到类加载器->APP 类加载器
        ClassLoader classLoader = LHSpringApplicationContext.class.getClassLoader();
        // 2 获取扫描包的url
        path = path.replace(".", "/");
        URL resource = classLoader.getResource(path);
        // System.out.println(resource);
        File file = new File(resource.getFile());
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (File file1 : files) {
                // System.out.println(file1);
                String absolutePath = file1.getAbsolutePath();
                // 只处理class文件
                if (absolutePath.endsWith(".class")) {
                    // 绝对路径:---F:\JavaWorksparce\Spring\out\production\springTest\xyz\lhweb\spring\component\MyComponent.class
                    // xyz.lhweb.spring.component.MyComponent

                    // 1 获取类名
                    String className = absolutePath.substring(absolutePath.lastIndexOf("\\") + 1, absolutePath.indexOf(".class"));
                    // System.out.println(className);

                    // 2 获取类的完整路径
                    String classFullName = path.replace("/", ".") + "." + className;
                    System.out.println(classFullName);

                    // 3 判断该类是不是需要注入到容器中
                    try {
                        // 反射一个类对象
                        // 1 Class.forName 调用该类的静态方法
                        // 2 classLoader.loadClass 不会调用该类的静态方法
                        // 3 isAnnotationPresent判断该类是否有这个注解
                        Class<?> clazz = classLoader.loadClass(classFullName);
                        if (clazz.isAnnotationPresent(Service.class) || (clazz.isAnnotationPresent(Component.class)) || (clazz.isAnnotationPresent(Controller.class)) || (clazz.isAnnotationPresent(Repository.class))) {

                            if (clazz.isAnnotationPresent(Service.class)) {
                                System.out.println("这是一个LHSpring bean=" + clazz + "    类名=" + className);
                                // 将Bean的信息封装到BeanDefiniton中放入map
                                // 1 得到Service注解
                                Service declaredAnnotation = clazz.getDeclaredAnnotation(Service.class);
                                // 2 得到value值
                                String beanName = declaredAnnotation.value();
                                method(className, clazz, beanName);
                            }

                            if (clazz.isAnnotationPresent(Component.class)) {

                                //为了方便 将后置处理器放到list集合中
                                //1 如果发现是一个后置处理器
                                //2 在原生spring容器中,对后置处理器还是走的getBean,createBean
                                //但是需要再单例池中加对应的逻辑,这里只是为了体验 所以直接放入到list集合中

                                //判断是否实现是后置处理器
                                //这里不能使用 instanceof 来判断 原因:clazz不是一个实例对象,而是一个类对象
                                if (BeanPostProcessor.class.isAssignableFrom(clazz)){
                                    BeanPostProcessor instance = (BeanPostProcessor) clazz.newInstance();
                                    //放入到集合中
                                    beanPostProcessorList.add(instance);
                                    continue;
                                }

                                System.out.println("这是一个LHSpring bean=" + clazz + "    类名=" + className);
                                Component declaredAnnotation = clazz.getDeclaredAnnotation(Component.class);
                                String beanName = declaredAnnotation.value();
                                method(className, clazz, beanName);
                            }

                            if (clazz.isAnnotationPresent(Controller.class)) {
                                System.out.println("这是一个LHSpring bean=" + clazz + "    类名=" + className);
                                Controller declaredAnnotation = clazz.getDeclaredAnnotation(Controller.class);
                                String beanName = declaredAnnotation.value();
                                method(className, clazz, beanName);
                            }

                            if (clazz.isAnnotationPresent(Repository.class)) {
                                System.out.println("这是一个LHSpring bean=" + clazz + "    类名=" + className);
                                Repository declaredAnnotation = clazz.getDeclaredAnnotation(Repository.class);
                                String beanName = declaredAnnotation.value();
                                method(className, clazz, beanName);
                            }

                        } else {
                            System.out.println("这不是一个LHSpring bean=" + clazz + "  类名=" + className);
                        }

                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }

                }
            }
        }
    }

    /**
     * 共同方法提取出来方法
     *
     * @param className 类名
     * @param clazz     clazz
     * @param beanName  bean名字
     */
    public void method(String className, Class<?> clazz, String beanName) {
        if ("".equals(beanName)) {// 如果为空
            // 首字母小写作为beanName
            beanName = StringUtils.uncapitalize(className);// 替换
        }
        // 3 放入map
        BeanDefinition beanDefinition = new BeanDefinition();
        beanDefinition.setClazz(clazz);
        // 4 获取Scope值
        if (clazz.isAnnotationPresent(Scope.class)) {
            // 如果配置了Scope
            Scope scopedeclaredAnnotation = clazz.getDeclaredAnnotation(Scope.class);
            beanDefinition.setScope(scopedeclaredAnnotation.value());
        } else {
            // 如果没有配置
            beanDefinition.setScope("singleton");
        }
        // 放入到map中
        beanDefinitonMap.put(beanName, beanDefinition);
    }

    /**
     * 创建bean
     *
     * @param beanDefinition bean定义
     */
    private Object createBean(String beanName,BeanDefinition beanDefinition) {
        // 得到Bean的clazz对象
        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();

            System.out.println("=========创建好bean====="+instance);

            //在bean的初始化方法前调用后置处理器方法
            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){
                // 2 将instance转成InitializingBean类型
                try {
                    ((InitializingBean)instance).afterPropertiesSet();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }

            //在bean的初始化方法后调用后置处理器方法
            for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
                //在后置处理器的after方法前可以对Bean进行处理 , 然后再返回处理后的bean
                //相当于做了后置处理
                Object current=
                        beanPostProcessor.postProcessAfterInitialization(instance, beanName);
                if (current!=null){
                    instance=current;
                }
            }

            return instance;
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 如果反射创建对象失败
        return null;
    }

    /**
     * 得到bean
     *
     * @param beanName bean名字
     * @return {@link Object}
     */
    public Object getBean(String beanName) {
        // 判断 传入的beanName是否在beanDefinitonMap中存在
        if (beanDefinitonMap.containsKey(beanName)) {// 存在
            BeanDefinition beanDefinition = beanDefinitonMap.get(beanName);
            // 得到beanDefinition的scope,分别进行处理
            if ("singleton".equalsIgnoreCase(beanDefinition.getScope())) {
                // 说明是单例的,就直接从单例池获取
                return singletonObjects.get(beanName);
            } else {// 不是单例就调用creatBean,反射一个对象
                return createBean(beanName,beanDefinition);
            }
        } else {// 不存在
            // 抛出个空指针异常
            throw new NullPointerException("没有该bean");

        }

    }
}

演示效果 image.png

6.实现阶段6-AOP机制实现

先死后活,先实现一个简单的切面类 新建一个接口和实现类

package asia.lhweb.spring.component;

/**
 * @author :罗汉
 * @date : 2023/7/24
 */
public interface SmartAnimalable {
    float getSum(float x,float y);
    float getSub(float x,float y);
}
package asia.lhweb.spring.component;

import asia.lhweb.spring.annotation.Component;

/**
 * @author :罗汉
 * @date : 2023/7/24
 */
@Component(value = "smartDog")
public class SmartDog implements SmartAnimalable{
    @Override
    public float getSum(float x, float y) {
        System.out.println("SmartDog getSum");
        return x+y;
    }

    @Override
    public float getSub(float x, float y) {
        System.out.println("SmartDog getSub");
        return x*y;
    }
}
package asia.lhweb.spring.component;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * 切面类
 *
 *
 * @author 罗汉
 * @date 2023/07/24
 */

public class SmartAnimalAspectj {

    public SmartAnimalAspectj() {
    }

    public static void showBeginLog(){
        System.out.println("前置类");
    }
    public static void showSuccessLog(){
        System.out.println("返回通知");
    }

}

修改方法 image.png 测试 image.png

总结

AOP可以使用注解会更灵活,暂时先做到这里 有机会我再更新

About

手写简易的Spring

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published