Spring 核心原理 ,代码实现IOC 和AOP

217 阅读4分钟

一、实现Spring IOC功能

* spring 核心
* 容器 IOC AOP 
* 1.存放容器的单例池 concurrenthashMap
* 2.存放beanDefinition 存放生成bean的信息
* 3.spring主流程
*    配置包扫描路径-》ApplicationClassLoad 加载类 -》扫描生成beanDefinition放入 -》
*   BeanDefinitionMap中 并标识为单例bean或者原型bean 作为生成Bean的信息
*    -》根据beanDefinitionMap生成所有 单例bean放入单例池
*    -》getBean() 单例bean从单例池中获取 原型bean 根据BeanDefinition生成
*    ComponentScan注解解析--》扫描路径--》扫描 -》放入beanDefinitionMap中

1.实现包扫描逻辑 生成BeanDefinition放入 beanDefinitionMap

1.定义包扫描路径

@ComponentScan("com.example.myspring.service")
public class AppConfig {
}

2.定义两个容器 singletonObjects 存放单例bean 和beanDefinitionMap 存放生生成bean的信息

//单例池 存放单例bean
private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();
//存beanDefinition
private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();

3.包扫描逻辑

private void scan(Class configClass) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
    ComponentScan componentScan = (ComponentScan) configClass.getDeclaredAnnotation(ComponentScan.class);
    //get scan path
    String scanPath = componentScan.value();//get scan path
    scanPath = scanPath.replace(".", "/");
    //扫描 类加载器
    // Bootstrap  --> jre/lib
    // Ext  --------> jre/ext/lib
    // App ---------> classpath -->
    ClassLoader classLoader = MyApplicationContext.class.getClassLoader();//appClassLoader
    URL resource = classLoader.getResource(scanPath);
    File file = new File(resource.getFile());
    if (file.isDirectory()) {
        File[] files = file.listFiles();
        for (File f : files) {
            String absolutePath = f.getAbsolutePath();
            if (absolutePath.endsWith(".class")) {
                //get  com.example.myspring.service.xxx
                String className = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"))
                        .replace("\", ".");
                //classloader loadClass
                Class<?> clazz = classLoader.loadClass(className);
                if (clazz.isAnnotationPresent(Component.class)) {//判断扫描类是否有 有Component注解 是一个Bean

                    if (BeanPostProcessor.class.isAssignableFrom(clazz)) {
                        BeanPostProcessor instance = (BeanPostProcessor) clazz.getDeclaredConstructor().newInstance();
                        beanPostProcessorList.add(instance);
                    }

                    //解析类 生成BeanDefinition
                    BeanDefinition beanDefinition = new BeanDefinition();
                    beanDefinition.setClazz(clazz);
                    Component component = clazz.getDeclaredAnnotation(Component.class);
                    String beanName = component.value();
                    if (clazz.isAnnotationPresent(Scope.class)) {//判断单例bean 原型bean
                        Scope scope = clazz.getDeclaredAnnotation(Scope.class);
                        beanDefinition.setScope(scope.value());
                    } else {//默认单例bean
                        beanDefinition.setScope(singleton);
                    }
                    beanDefinitionMap.put(beanName, beanDefinition);
                }
            }
        }
    }
}

2.扫描完成 遍历beanDefinitionMap 生成bean对象放入单例池

  1. 遍历beanDefinitionMap 调用createBean() 生成对象放入单例池中
//扫描完成  遍历beanDefinitionMap 单例bean 生成对象放入单例池中
for (String beanName : beanDefinitionMap.keySet()) {
    BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
    Object bean = createBean(beanName, beanDefinition);
    singletonObjects.put(beanName, bean);
}

2.生成bean逻辑实现 (实现依赖注入)

//create bean
public Object createBean(String beanName, BeanDefinition beanDefinition) throws Exception {
    Class clazz = beanDefinition.getClazz();
    Object instance = clazz.newInstance();

    //依赖注入 逻辑实现
    for (Field declaredField : clazz.getDeclaredFields()) {
        if (declaredField.isAnnotationPresent(Autowired.class)) {//判断是否存在Autowired注解
            //从容器中查找bean 注入到依赖bean中
            Object bean = getBean(declaredField.getName());
            declaredField.setAccessible(true);
            declaredField.set(instance, bean);
        }
    }
    //aware回调:调用bean实现BeanNameAware 接口的方法
    if (instance instanceof BeanNameAware) {
        ((BeanNameAware) instance).setBeanName(beanName);
    }
    //初始化前 对bean进行加工
    for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
        instance = beanPostProcessor.postProcessBeforeInitialization(instance, beanName);
    }

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

    //初始化后处理  在这进行代理 aop
    for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
        instance = beanPostProcessor.postProcessAfterInitialization(instance, beanName);
    }
    return instance;
}

3.getBean()功能实现

getBean()方法逻辑 如果是singleton单例bean直接从单例池获取,如果是原型bean

/**
 * getBean 方法 获取一个bean
 *
 * @return
 */
public Object getBean(String beanName) throws Exception {
    Object bean = null;
    if (beanDefinitionMap.containsKey(beanName)) {
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if (beanDefinition.getScope().equals("singleton")) {//单例bean 从单例池获取
            bean = singletonObjects.get(beanName);
        } else {//原型bean
            bean = createBean(beanName, beanDefinition);
            return bean;
        }
    } else {//不存在bean
        throw new NullPointerException();
    }
    return bean;
}

二、实现Spring AOP功能

"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块, 并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共 同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未 来的可操作性和可维护性。 使用"横切"技术,AOP 把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流 程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生 在核心关注点的多处,而各处基本相似,比如权限认证、日志、事物。AOP 的作用在于分离系统

中的各种关注点,将核心关注点和横切关注点分离开来。

AOP 主要应用场景有:

  1. Authentication 权限
  2. Caching 缓存
  3. Context passing 内容传递
  4. Error handling 错误处理
  5. Lazy loading 懒加载
  6. Debugging 调试
  7. logging, tracing, profiling and monitoring 记录跟踪 优化 校准
  8. Performance optimization 性能优化
  9. Persistence 持久化
  10. Resource pooling 资源池
  11. Synchronization 同步
  12. Transactions 事务

1.定义一个接口

public interface BeanPostProcessor {
    //初始化前
    Object postProcessBeforeInitialization(Object bean,String beanName);
    //初始化后
    Object postProcessAfterInitialization(Object bean,String beanName);
}

2.实现接口 在接口逻辑实现代理 找切点执行AOP

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        if (beanName.equals("userService")) {
            System.out.println("userService初始化前处理..");
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        System.out.println(beanName + " 初始化后处理...");
        if (beanName.equals("userService")) {
            System.out.println("生成代理对象");
            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("代理逻辑");//找切点 执行aop
                    //调用代理逻辑
                    return method.invoke(bean, args);
                }
            });
            return proxyInstance;
        }
        return bean;
    }
}