手写Spring(二)

手写Spring(二)

上一节 手写Spring(一)做了一些准备工作,并且写了Spring启动时候是如何扫描、加载类的,最后通过getBean()方法获取bean

依赖注入

bean的单例还是原型只是作用域区别,但是创建bean都是同样的步骤。在补充createBean()这个方法之前我们在service层新加一个OrderService

@Component("orderService")
public class OrderService {
}

在原来的UserService新增一个属性

@Component("userService")
//@Scope("prototype")
public class UserService {
    @Autowired
    private OrderService orderService;
}

按照Spring运行,在测试方法中获取userService这个对象,那么它的orderService属性应该是已经被赋值的。

上节写到createBean()方法中通过构造器创建实例,那么实例的属性现在都是空,下面就要进行依赖注入

private Object createBean(String beanName, BeanDefinition beanDefinition) {
        Class clazz = beanDefinition.getClazz();
        Object instance = null;
        try {
            instance = clazz.getDeclaredConstructor().newInstance();

            // 依赖注入
            // 1.找到属性
            for (Field declaredField : clazz.getDeclaredFields()) {
              	// 2.判断属性有没有@Autowired注解
                if (declaredField.isAnnotationPresent(Autowired.class)) {
                    Autowired annotation = declaredField.getAnnotation(Autowired.class);
                   // 3.通过该属性的名字拿到bean
                    Object bean = getBean(declaredField.getName());
                    // 如果@Autowired属性required=true 并且获取的bean为空
                    if (annotation.require() && bean == null) {
                        throw new NullPointerException();
                    }
                    // 4.设置属性
                    declaredField.setAccessible(true);
                    declaredField.set(instance, bean);
                }
            }

        return instance;
    }

Aware回调

比如UserService有一个属性beanName,创建对象时候我们希望给这个对象赋值一个该bean的名字,Spring中有一个接口叫BeanNameAware就是用来给对象赋名字属性的。

我们现在开始模拟它,首先写一个BeanNameAware接口

public interface BeanNameAware {
    void setBeanName(String name);
}

UserService实现这个BeanNameAware接口

@Component("userService")
//@Scope("prototype")
public class UserService implements BeanNameAware{

    @Autowired
    private OrderService orderService;

    private String beanName;

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

    public void print(){
        System.out.println(orderService);
        System.out.println(beanName);
    }
}

那么在创建bean,依赖注入后,可以判断实例是否实现了BeanNameAware,从而把beanName赋上去

 						// Aware回调
            if (instance instanceof BeanNameAware){
                ((BeanNameAware)instance).setBeanName(beanName);
            }

初始化机制

Aware回调后,创建bean还做了什么,了解Spring的可能知道还有一步叫InitializingBean

public interface InitializingBean {

    void afterPropertiesSet();
}

UserService实现这个InitializingBean接口

@Component("userService")
//@Scope("prototype")
public class UserService implements BeanNameAware , InitializingBean {

    @Autowired
    private OrderService orderService;

    private String beanName;

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

    @Override
    public void afterPropertiesSet() {
        // 可以验证属性是否为空/属性赋值等是否符合要求...
        System.out.println("After properties set");
    }

    public void print(){
        System.out.println(orderService);
        System.out.println(beanName);
    }
}

同样在createBean()的Aware回调方法之后增加初始化的步骤

						// 初始化            if (instance instanceof InitializingBean){                ((InitializingBean)instance).afterPropertiesSet();            }

BeanPostProcessor

之前的实例化bean、依赖注入、回调、初始化其实都是在创建bean的过程中,假设程序员需要在实例化之后去做一些事情,或者之前做一些处理,又或者我们需要在初始化之前、之后做一些处理,那么就希望Spring提供一些方法来让程序员可以自己去扩展bean创建过程中做的事情

BeanPostProcessor

public interface BeanPostProcessor {    Object postProcessBeforeInitialization(Object bean, String beanName);    Object postProcessAfterInitialization(Object bean, String beanName);}

定义一个处理类实现BeanPostProcessor,当然它也是bean需要添加到Spring容器中

@Componentpublic class MyBeanPostProcessor implements BeanPostProcessor {    @Override    public Object postProcessBeforeInitialization(Object bean, String beanName) {        System.out.println("before initialization...");        // 对特定的bean进行一些处理        if (beanName.equals("userService")){            ((UserService)bean).setBeanName("userService1");        }        return bean;    }    @Override    public Object postProcessAfterInitialization(Object bean, String beanName) {        System.out.println("after initialization...");        return bean;    }}

MyApplicationContext中添加处理类列表属性

private List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();

在扫描@Component时添加如下逻辑,在扫描的时候将处理类(xxxProcessor)实例化并添加到列表。

【注意】这里的实例化BeanPostProcessor用的是无参构造器的方式,而Spring中用的是Spring自己的getBean()方法,这样做的好处是xxxProcessor处理类中如果有@Autowired属性时候可以进行注入!并且Spring中xxxProcessor本身的创建过程是不需要有beforeProcessorafterProcessor的!

//clazz对象是否实现了BeanPostProcessor接口if (BeanPostProcessor.class.isAssignableFrom(clazz)) {  try {    BeanPostProcessor instance = (BeanPostProcessor)clazz.getDeclaredConstructor().newInstance();    beanPostProcessorList.add(instance);  } catch (InstantiationException e) {    e.printStackTrace();  } catch (IllegalAccessException e) {    e.printStackTrace();  } catch (InvocationTargetException e) {    e.printStackTrace();  } catch (NoSuchMethodException e) {    e.printStackTrace();  }}

createBean()方法初始化前,初始化后就可以用处理类来进行对bean的处理了

        // BeanPostProcessor --> 初始化前        for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {          instance = beanPostProcessor.postProcessBeforeInitialization(instance, beanName);        }        // 初始化        if (instance instanceof InitializingBean){          ((InitializingBean)instance).afterPropertiesSet();        }        // BeanPostProcessor -->初始化后        for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {          instance = beanPostProcessor.postProcessAfterInitialization(instance, beanName);        }

我这里处理器的逻辑是把beanName更改为userService1,可以看到结果雀食也改了!

但是也有不完善的地方就是,实现了BeanPostProcessor接口的处理类也打印了初始化前、后这样的步骤,也被注入到了BeanDefinition中

手写Spring(二)

*AOP实现原理

Spring的AOP其实就是利用上面的BeanPostProcessor来实现,并且是在初始化后来实现。比如之前我们写到在UserService中有一个print()方法,假如我想要在调用这个方法之前打印一个log,该怎么实现呢?

需要利用刚才的BeanPostProcessor的初始化后来进行,因为创建了bean之后才会调用方法,所以log打印的时机应该在初始化bean之后,调用方法之前。

【注意】初始化后为创建bean的最后一步,而初始化后返回的对象将被放入单例池

MyBeanPostProcessor的初始化后处理逻辑中用jdk的动态代理来生成代理对象,后续代理对象proxyInstance执行某个方法(invoke中的method)时,先执行代理逻辑,之后通过反射的方式基于原始bean(即被代理bean)执行对应的业务方法(本例为print()方法)

@Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        System.out.println("after initialization...");
        if (beanName.equals("userService")) {
            // 返回代理对象
            Object proxyInstance = Proxy.newProxyInstance(MyBeanPostProcessor.class.getClassLoader(),
                    bean.getClass().getInterfaces(),
                    new InvocationHandler() {
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            System.out.println("代理逻辑");// 找切点
                            // bean对象调用对应的方法
                            return method.invoke(bean, args);
                        }
                    });
            return proxyInstance;
        }
        return bean;
    }

本例只是简单编写AOP

对于Spring中,初始化后处理对于某一个bean要不要进行AOP也要判断,执行代理逻辑的时候肯定要判断哪些要执行,也就是找切点

手写Spring(二)

总结

到此为止bean的生命周期大致已经编写完成

整个流程:

  • 判断类需要创建bean
  • 执行创建bean
    • 依赖注入
    • Aware回调
    • 初始化机制
    • BeanPostProcessor 初始化过程的处理
    • 返回bean
  • 将bean加入单例池

主要代码

MyBeanPostProcessor

public class MyApplicationContext {

    private Class configClass;

    /**
     * 单例池
     */
    private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();

    /**
     * <beanName,BeanDefinition>信息
     */
    private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();

    private List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();

    public MyApplicationContext(Class configClass) {
        this.configClass = configClass;

        // 解析配置类,并不是解析限定符、属性,而是解析类上的注解
        // ComponentScan ---> 扫描路径 ---> 扫描
        scan(configClass);

        // 创建bean对象
        for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {
            String beanName = entry.getKey();
            BeanDefinition beanDefinition = entry.getValue();
            if (beanDefinition.getScope().equals("singleton")) {
                Object bean = createBean(beanName, beanDefinition);
                singletonObjects.put(beanName, bean);
            }
        }

    }

    private Object createBean(String beanName, BeanDefinition beanDefinition) {
        Class clazz = beanDefinition.getClazz();
        Object instance = null;
        try {
            instance = clazz.getDeclaredConstructor().newInstance();

            // 依赖注入
            // 1.找到属性
            for (Field declaredField : clazz.getDeclaredFields()) {
                // 2.判断属性有没有@Autowired注解
                if (declaredField.isAnnotationPresent(Autowired.class)) {
                    Autowired annotation = declaredField.getAnnotation(Autowired.class);
                    // 3.通过该属性的名字拿到bean
                    Object bean = getBean(declaredField.getName());
                    // 如果@Autowired属性required=true 并且获取的bean为空
                    if (annotation.require() && bean == null) {
                        throw new NullPointerException();
                    }
                    // 4.设置属性
                    declaredField.setAccessible(true);
                    declaredField.set(instance, bean);
                }
            }

            // Aware回调
            if (instance instanceof BeanNameAware){
                ((BeanNameAware)instance).setBeanName(beanName);
            }

            // BeanPostProcessor --> 初始化前
            for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
                instance = beanPostProcessor.postProcessBeforeInitialization(instance, beanName);
            }

            // 初始化
            if (instance instanceof InitializingBean){
                ((InitializingBean)instance).afterPropertiesSet();
            }

            // BeanPostProcessor -->初始化后
            for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
                instance = beanPostProcessor.postProcessAfterInitialization(instance, beanName);
            }


        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

        return instance;
    }

    private void scan(Class configClass) {
        ComponentScan componentScanAnnotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
        String path = componentScanAnnotation.value(); // 扫描路径 com.wangqun.service

        // 扫描
        // 包下面有些不是我们需要加载的类如XxUtil,所以我们要先拿到包下面的所有类,判断类上面是否有@Component注解
        // 那么如何拿到所有类呢???
        // BootStrap -----> jre/lib
        // Ext -----> jre/ext/lib
        // App -----> classpath 例如:/Users/wangqun03/Projects/HandWritting/Spring/target/classes com.wangqun.Test
        ClassLoader classLoader = MyApplicationContext.class.getClassLoader(); // app
        path = path.replace(".", "/");
        URL resource = classLoader.getResource(path);// 相对路径,相对的是classpath
        File file = new File(resource.getFile());
        if (file.isDirectory()) {// 判断是否是目录
            File[] files = file.listFiles();// 获得目录下的所有文件
            for (File f : files) {
                String absolutePath = f.getAbsolutePath();// 获得文件的绝对路径 这里是编译后的target/classes下的绝对路径
                // 如果是类文件才处理
                if (absolutePath.endsWith(".class")) {
                    String name = toFullQualifiedName(absolutePath);// 需要将绝对路径变成全限定名
                    try {
                        Class<?> clazz = classLoader.loadClass(name);// 通过类全限定名加载类
                        if (clazz.isAnnotationPresent(Component.class)) {
                            // 表示当前这个类是一个Bean
                            // 解析类,判断单例还是原型 ----> BeanDefinition

                            //clazz对象是否实现了BeanPostProcessor接口
                            if (BeanPostProcessor.class.isAssignableFrom(clazz)) {
                                try {
                                    BeanPostProcessor instance = (BeanPostProcessor)clazz.getDeclaredConstructor().newInstance();
                                    beanPostProcessorList.add(instance);
                                } catch (InstantiationException e) {
                                    e.printStackTrace();
                                } catch (IllegalAccessException e) {
                                    e.printStackTrace();
                                } catch (InvocationTargetException e) {
                                    e.printStackTrace();
                                } catch (NoSuchMethodException e) {
                                    e.printStackTrace();
                                }
                            }

                            Component componentAnnotation = clazz.getAnnotation(Component.class);
                            String beanName = componentAnnotation.value();

                            // bean的定义
                            BeanDefinition beanDefinition = new BeanDefinition();
                            beanDefinition.setClazz(clazz);

                            if (clazz.isAnnotationPresent(Scope.class)) {
                                Scope scopeAnnotation = clazz.getDeclaredAnnotation(Scope.class);
                                beanDefinition.setScope(scopeAnnotation.value());
                            } else {
                                beanDefinition.setScope("singleton");
                            }
                            // 将bean的描述放入map
                            beanDefinitionMap.put(beanName, beanDefinition);
                        }
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    /**
     * 绝对路径变为全限定名
     *
     * @param absolutePath 绝对路径
     * @return 全限定名
     */
    private String toFullQualifiedName(String absolutePath) {
        int com = absolutePath.indexOf("com");
        int point = absolutePath.indexOf(".");
        // 去掉.Class
        String substring = absolutePath.substring(0, point);
        // 去掉com之前
        substring = substring.substring(com);
        // 替换
        substring = substring.replace("/", ".");
        return substring;
    }

    public Object getBean(String beanName) {
        if (beanDefinitionMap.containsKey(beanName)) {
            BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
            if (beanDefinition.getScope().equals("singleton")) {
                Object o = singletonObjects.get(beanName);
                return o;
            } else {
                // 创建Bean对象
                return createBean(beanName, beanDefinition);
            }
        } else {
            throw new NullPointerException("Bean " + beanName + " not exists");
        }
    }

}

BeanPostProcessor

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        System.out.println("before initialization...");

        // 对特定的bean进行一些处理
        if (beanName.equals("userService")) {
            ((UserServiceImpl) bean).setBeanName("userService1");
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        System.out.println("after initialization...");
        if (beanName.equals("userService")) {
            // 返回代理对象
            Object proxyInstance = Proxy.newProxyInstance(MyBeanPostProcessor.class.getClassLoader(),
                    bean.getClass().getInterfaces(),
                    new InvocationHandler() {
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            System.out.println("代理逻辑");// 找切点
                            return method.invoke(bean, args);
                        }
                    });
            return proxyInstance;
        }
        return bean;
    }
}
上一篇:java面试题


下一篇:2021-09-29